Home | History | Annotate | Download | only in iw
      1 /*
      2  * This ought to be provided by libnl
      3  */
      4 
      5 #include <asm/errno.h>
      6 #include <netlink/genl/genl.h>
      7 #include <netlink/genl/family.h>
      8 #include <netlink/genl/ctrl.h>
      9 #include <netlink/msg.h>
     10 #include <netlink/attr.h>
     11 #include <linux/genetlink.h>
     12 
     13 #include "iw.h"
     14 
     15 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
     16 			 void *arg)
     17 {
     18 	int *ret = arg;
     19 	*ret = err->error;
     20 	return NL_STOP;
     21 }
     22 
     23 static int ack_handler(struct nl_msg *msg, void *arg)
     24 {
     25 	int *ret = arg;
     26 	*ret = 0;
     27 	return NL_STOP;
     28 }
     29 
     30 struct handler_args {
     31 	const char *group;
     32 	int id;
     33 };
     34 
     35 static int family_handler(struct nl_msg *msg, void *arg)
     36 {
     37 	struct handler_args *grp = arg;
     38 	struct nlattr *tb[CTRL_ATTR_MAX + 1];
     39 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
     40 	struct nlattr *mcgrp;
     41 	int rem_mcgrp;
     42 
     43 	nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
     44 		  genlmsg_attrlen(gnlh, 0), NULL);
     45 
     46 	if (!tb[CTRL_ATTR_MCAST_GROUPS])
     47 		return NL_SKIP;
     48 
     49 	nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) {
     50 		struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];
     51 
     52 		nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX,
     53 			  nla_data(mcgrp), nla_len(mcgrp), NULL);
     54 
     55 		if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] ||
     56 		    !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID])
     57 			continue;
     58 		if (strncmp(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]),
     59 			    grp->group, nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])))
     60 			continue;
     61 		grp->id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
     62 		break;
     63 	}
     64 
     65 	return NL_SKIP;
     66 }
     67 
     68 int nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group)
     69 {
     70 	struct nl_msg *msg;
     71 	struct nl_cb *cb;
     72 	int ret, ctrlid;
     73 	struct handler_args grp = {
     74 		.group = group,
     75 		.id = -ENOENT,
     76 	};
     77 
     78 	msg = nlmsg_alloc();
     79 	if (!msg)
     80 		return -ENOMEM;
     81 
     82 	cb = nl_cb_alloc(NL_CB_DEFAULT);
     83 	if (!cb) {
     84 		ret = -ENOMEM;
     85 		goto out_fail_cb;
     86 	}
     87 
     88 	ctrlid = genl_ctrl_resolve(sock, "nlctrl");
     89 
     90 	genlmsg_put(msg, 0, 0, ctrlid, 0,
     91 		    0, CTRL_CMD_GETFAMILY, 0);
     92 
     93 	ret = -ENOBUFS;
     94 	NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
     95 
     96 	ret = nl_send_auto_complete(sock, msg);
     97 	if (ret < 0)
     98 		goto out;
     99 
    100 	ret = 1;
    101 
    102 	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
    103 	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret);
    104 	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, family_handler, &grp);
    105 
    106 	while (ret > 0)
    107 		nl_recvmsgs(sock, cb);
    108 
    109 	if (ret == 0)
    110 		ret = grp.id;
    111  nla_put_failure:
    112  out:
    113 	nl_cb_put(cb);
    114  out_fail_cb:
    115 	nlmsg_free(msg);
    116 	return ret;
    117 }
    118