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