2 #include <netlink/netlink.h>
3 #include <netlink/genl/genl.h>
4 #include <netlink/genl/ctrl.h>
5 #include <netlink/genl/family.h>
10 #include <linux/nl80211.h>
14 static int unl_init(struct unl
*unl
)
16 unl
->sock
= nl_socket_alloc();
23 int unl_genl_init(struct unl
*unl
, const char *family
)
25 memset(unl
, 0, sizeof(*unl
));
30 unl
->hdrlen
= NLMSG_ALIGN(sizeof(struct genlmsghdr
));
31 unl
->family_name
= strdup(family
);
32 if (!unl
->family_name
)
35 if (genl_connect(unl
->sock
))
38 if (genl_ctrl_alloc_cache(unl
->sock
, &unl
->cache
))
41 unl
->family
= genl_ctrl_search_by_name(unl
->cache
, family
);
53 void unl_free(struct unl
*unl
)
56 free(unl
->family_name
);
59 nl_socket_free(unl
->sock
);
62 nl_cache_free(unl
->cache
);
64 memset(unl
, 0, sizeof(*unl
));
68 ack_handler(struct nl_msg
*msg
, void *arg
)
76 finish_handler(struct nl_msg
*msg
, void *arg
)
84 error_handler(struct sockaddr_nl
*nla
, struct nlmsgerr
*err
, void *arg
)
91 struct nl_msg
*unl_genl_msg(struct unl
*unl
, int cmd
, bool dump
)
103 genlmsg_put(msg
, NL_AUTO_PID
, NL_AUTO_SEQ
,
104 genl_family_get_id(unl
->family
), 0, flags
, cmd
, 0);
110 int unl_genl_request(struct unl
*unl
, struct nl_msg
*msg
, unl_cb handler
, void *arg
)
112 struct nlmsghdr
*nlh
;
116 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
117 nlh
= nlmsg_hdr(msg
);
119 err
= nl_send_auto_complete(unl
->sock
, msg
);
124 nl_cb_err(cb
, NL_CB_CUSTOM
, error_handler
, &err
);
125 nl_cb_set(cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, finish_handler
, &err
);
126 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, ack_handler
, &err
);
128 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, handler
, arg
);
131 nl_recvmsgs(unl
->sock
, cb
);
139 static int request_single_cb(struct nl_msg
*msg
, void *arg
)
141 struct nl_msg
**dest
= arg
;
150 int unl_genl_request_single(struct unl
*unl
, struct nl_msg
*msg
, struct nl_msg
**dest
)
153 return unl_genl_request(unl
, msg
, request_single_cb
, dest
);
156 static int no_seq_check(struct nl_msg
*msg
, void *arg
)
161 void unl_genl_loop(struct unl
*unl
, unl_cb handler
, void *arg
)
165 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
166 unl
->loop_done
= false;
167 nl_cb_set(cb
, NL_CB_SEQ_CHECK
, NL_CB_CUSTOM
, no_seq_check
, NULL
);
168 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, handler
, arg
);
170 while (!unl
->loop_done
)
171 nl_recvmsgs(unl
->sock
, cb
);
176 int unl_genl_multicast_id(struct unl
*unl
, const char *name
)
178 struct nlattr
*tb
[CTRL_ATTR_MCAST_GRP_MAX
+ 1];
179 struct nlattr
*groups
, *group
;
189 ctrlid
= genl_ctrl_resolve(unl
->sock
, "nlctrl");
190 genlmsg_put(msg
, 0, 0, ctrlid
, 0, 0, CTRL_CMD_GETFAMILY
, 0);
191 NLA_PUT_STRING(msg
, CTRL_ATTR_FAMILY_NAME
, unl
->family_name
);
192 unl_genl_request_single(unl
, msg
, &msg
);
196 groups
= unl_find_attr(unl
, msg
, CTRL_ATTR_MCAST_GROUPS
);
198 goto nla_put_failure
;
200 nla_for_each_nested(group
, groups
, rem
) {
203 nla_parse(tb
, CTRL_ATTR_MCAST_GRP_MAX
, nla_data(group
),
204 nla_len(group
), NULL
);
206 if (!tb
[CTRL_ATTR_MCAST_GRP_NAME
] ||
207 !tb
[CTRL_ATTR_MCAST_GRP_ID
])
210 gn
= nla_data(tb
[CTRL_ATTR_MCAST_GRP_NAME
]);
211 if (strcmp(gn
, name
) != 0)
214 ret
= nla_get_u32(tb
[CTRL_ATTR_MCAST_GRP_ID
]);
223 int unl_genl_subscribe(struct unl
*unl
, const char *name
)
227 mcid
= unl_genl_multicast_id(unl
, name
);
231 return nl_socket_add_membership(unl
->sock
, mcid
);
234 int unl_genl_unsubscribe(struct unl
*unl
, const char *name
)
238 mcid
= unl_genl_multicast_id(unl
, name
);
242 return nl_socket_drop_membership(unl
->sock
, mcid
);
245 int unl_nl80211_phy_lookup(const char *name
)
250 snprintf(buf
, sizeof(buf
), "/sys/class/ieee80211/%s/index", name
);
252 fd
= open(buf
, O_RDONLY
);
255 pos
= read(fd
, buf
, sizeof(buf
) - 1);
265 int unl_nl80211_wdev_to_phy(struct unl
*unl
, int wdev
)
271 msg
= unl_genl_msg(unl
, NL80211_CMD_GET_INTERFACE
, false);
275 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, wdev
);
276 if (unl_genl_request_single(unl
, msg
, &msg
) < 0)
279 attr
= unl_find_attr(unl
, msg
, NL80211_ATTR_WIPHY
);
283 ret
= nla_get_u32(attr
);