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);