blob: 7dc27f78c735668393f452cc5dbce970668f4d67 [file] [log] [blame]
Johannes Berg2c61ba62008-10-24 20:24:44 +02001/*
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>
Johannes Bergc5514492011-12-07 09:08:40 +01008#include <netlink/genl/ctrl.h>
Johannes Berg2c61ba62008-10-24 20:24:44 +02009#include <netlink/msg.h>
10#include <netlink/attr.h>
Johannes Berged98fa12010-10-26 13:50:10 +020011#include <linux/genetlink.h>
Johannes Berg2c61ba62008-10-24 20:24:44 +020012
Johannes Berg656aa242008-12-08 18:30:22 +010013#include "iw.h"
14
Johannes Berg2c61ba62008-10-24 20:24:44 +020015static 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
Johannes Berg2c61ba62008-10-24 20:24:44 +020023static int ack_handler(struct nl_msg *msg, void *arg)
24{
25 int *ret = arg;
26 *ret = 0;
27 return NL_STOP;
28}
29
30struct handler_args {
31 const char *group;
32 int id;
33};
34
35static 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
Johannes Bergc5514492011-12-07 09:08:40 +010046 if (!tb[CTRL_ATTR_MCAST_GROUPS])
Johannes Berg2c61ba62008-10-24 20:24:44 +020047 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 }
Johannes Bergc5514492011-12-07 09:08:40 +010064
Johannes Berg2c61ba62008-10-24 20:24:44 +020065 return NL_SKIP;
66}
67
Pat Erley57077d62009-01-29 14:35:18 +010068int nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group)
Johannes Berg2c61ba62008-10-24 20:24:44 +020069{
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
Pat Erley57077d62009-01-29 14:35:18 +010088 ctrlid = genl_ctrl_resolve(sock, "nlctrl");
Johannes Berg2c61ba62008-10-24 20:24:44 +020089
Johannes Bergc5514492011-12-07 09:08:40 +010090 genlmsg_put(msg, 0, 0, ctrlid, 0,
Johannes Berg2c61ba62008-10-24 20:24:44 +020091 0, CTRL_CMD_GETFAMILY, 0);
92
93 ret = -ENOBUFS;
94 NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
95
Pat Erley57077d62009-01-29 14:35:18 +010096 ret = nl_send_auto_complete(sock, msg);
Johannes Berg2c61ba62008-10-24 20:24:44 +020097 if (ret < 0)
98 goto out;
99
100 ret = 1;
101
102 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
Johannes Berg2c61ba62008-10-24 20:24:44 +0200103 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)
Pat Erley57077d62009-01-29 14:35:18 +0100107 nl_recvmsgs(sock, cb);
Johannes Berg2c61ba62008-10-24 20:24:44 +0200108
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}