nexmon – Rev 1

Subversion Repositories:
Rev:
/*
 * This ought to be provided by libnl
 */

#include <asm/errno.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <netlink/msg.h>
#include <netlink/attr.h>
#include <linux/genetlink.h>

#include "iw.h"

static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
                         void *arg)
{
        int *ret = arg;
        *ret = err->error;
        return NL_STOP;
}

static int ack_handler(struct nl_msg *msg, void *arg)
{
        int *ret = arg;
        *ret = 0;
        return NL_STOP;
}

struct handler_args {
        const char *group;
        int id;
};

static int family_handler(struct nl_msg *msg, void *arg)
{
        struct handler_args *grp = arg;
        struct nlattr *tb[CTRL_ATTR_MAX + 1];
        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
        struct nlattr *mcgrp;
        int rem_mcgrp;

        nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);

        if (!tb[CTRL_ATTR_MCAST_GROUPS])
                return NL_SKIP;

        nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) {
                struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];

                nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX,
                          nla_data(mcgrp), nla_len(mcgrp), NULL);

                if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] ||
                    !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID])
                        continue;
                if (strncmp(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]),
                            grp->group, nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])))
                        continue;
                grp->id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
                break;
        }

        return NL_SKIP;
}

int nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group)
{
        struct nl_msg *msg;
        struct nl_cb *cb;
        int ret, ctrlid;
        struct handler_args grp = {
                .group = group,
                .id = -ENOENT,
        };

        msg = nlmsg_alloc();
        if (!msg)
                return -ENOMEM;

        cb = nl_cb_alloc(NL_CB_DEFAULT);
        if (!cb) {
                ret = -ENOMEM;
                goto out_fail_cb;
        }

        ctrlid = genl_ctrl_resolve(sock, "nlctrl");

        genlmsg_put(msg, 0, 0, ctrlid, 0,
                    0, CTRL_CMD_GETFAMILY, 0);

        ret = -ENOBUFS;
        NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);

        ret = nl_send_auto_complete(sock, msg);
        if (ret < 0)
                goto out;

        ret = 1;

        nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
        nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret);
        nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, family_handler, &grp);

        while (ret > 0)
                nl_recvmsgs(sock, cb);

        if (ret == 0)
                ret = grp.id;
 nla_put_failure:
 out:
        nl_cb_put(cb);
 out_fail_cb:
        nlmsg_free(msg);
        return ret;
}