]>
Commit | Line | Data |
---|---|---|
2c61ba61 JB |
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> | |
ed98fa17 | 11 | #include <linux/genetlink.h> |
2c61ba61 | 12 | |
656aa246 JB |
13 | #include "iw.h" |
14 | ||
2c61ba61 JB |
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 | ||
2c61ba61 JB |
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 | ||
57077d64 | 68 | int nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group) |
2c61ba61 JB |
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 | ||
57077d64 | 88 | ctrlid = genl_ctrl_resolve(sock, "nlctrl"); |
2c61ba61 JB |
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 | ||
57077d64 | 96 | ret = nl_send_auto_complete(sock, msg); |
2c61ba61 JB |
97 | if (ret < 0) |
98 | goto out; | |
99 | ||
100 | ret = 1; | |
101 | ||
102 | nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret); | |
2c61ba61 JB |
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) | |
57077d64 | 107 | nl_recvmsgs(sock, cb); |
2c61ba61 JB |
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 | } |