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 
error_handler(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)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 
ack_handler(struct nl_msg * msg,void * arg)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 
family_handler(struct nl_msg * msg,void * arg)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 
nl_get_multicast_id(struct nl_sock * sock,const char * family,const char * group)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