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 memset(unl
, 0, sizeof(*unl
));
18 unl
->sock
= nl_socket_alloc();
25 int unl_genl_init(struct unl
*unl
, const char *family
)
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 int unl_rtnl_init(struct unl
*unl
)
59 if (nl_connect(unl
->sock
, NETLINK_ROUTE
))
70 void unl_free(struct unl
*unl
)
73 free(unl
->family_name
);
76 nl_socket_free(unl
->sock
);
79 nl_cache_free(unl
->cache
);
81 memset(unl
, 0, sizeof(*unl
));
85 ack_handler(struct nl_msg
*msg
, void *arg
)
93 finish_handler(struct nl_msg
*msg
, void *arg
)
101 error_handler(struct sockaddr_nl
*nla
, struct nlmsgerr
*err
, void *arg
)
108 struct nl_msg
*unl_genl_msg(struct unl
*unl
, int cmd
, bool dump
)
120 genlmsg_put(msg
, NL_AUTO_PID
, NL_AUTO_SEQ
,
121 genl_family_get_id(unl
->family
), 0, flags
, cmd
, 0);
127 struct nl_msg
*unl_rtnl_msg(struct unl
*unl
, int cmd
, bool dump
)
139 nlmsg_put(msg
, NL_AUTO_PID
, NL_AUTO_SEQ
, cmd
, 0, flags
);
145 int unl_request(struct unl
*unl
, struct nl_msg
*msg
, unl_cb handler
, void *arg
)
150 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
151 err
= nl_send_auto_complete(unl
->sock
, msg
);
156 nl_cb_err(cb
, NL_CB_CUSTOM
, error_handler
, &err
);
157 nl_cb_set(cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, finish_handler
, &err
);
158 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, ack_handler
, &err
);
160 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, handler
, arg
);
163 nl_recvmsgs(unl
->sock
, cb
);
171 static int request_single_cb(struct nl_msg
*msg
, void *arg
)
173 struct nl_msg
**dest
= arg
;
182 int unl_request_single(struct unl
*unl
, struct nl_msg
*msg
, struct nl_msg
**dest
)
185 return unl_request(unl
, msg
, request_single_cb
, dest
);
188 static int no_seq_check(struct nl_msg
*msg
, void *arg
)
193 void unl_loop(struct unl
*unl
, unl_cb handler
, void *arg
)
197 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
198 unl
->loop_done
= false;
199 nl_cb_set(cb
, NL_CB_SEQ_CHECK
, NL_CB_CUSTOM
, no_seq_check
, NULL
);
200 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, handler
, arg
);
202 while (!unl
->loop_done
)
203 nl_recvmsgs(unl
->sock
, cb
);
208 int unl_genl_multicast_id(struct unl
*unl
, const char *name
)
210 struct nlattr
*tb
[CTRL_ATTR_MCAST_GRP_MAX
+ 1];
211 struct nlattr
*groups
, *group
;
221 ctrlid
= genl_ctrl_resolve(unl
->sock
, "nlctrl");
222 genlmsg_put(msg
, 0, 0, ctrlid
, 0, 0, CTRL_CMD_GETFAMILY
, 0);
223 NLA_PUT_STRING(msg
, CTRL_ATTR_FAMILY_NAME
, unl
->family_name
);
224 unl_request_single(unl
, msg
, &msg
);
228 groups
= unl_find_attr(unl
, msg
, CTRL_ATTR_MCAST_GROUPS
);
230 goto nla_put_failure
;
232 nla_for_each_nested(group
, groups
, rem
) {
235 nla_parse(tb
, CTRL_ATTR_MCAST_GRP_MAX
, nla_data(group
),
236 nla_len(group
), NULL
);
238 if (!tb
[CTRL_ATTR_MCAST_GRP_NAME
] ||
239 !tb
[CTRL_ATTR_MCAST_GRP_ID
])
242 gn
= nla_data(tb
[CTRL_ATTR_MCAST_GRP_NAME
]);
243 if (strcmp(gn
, name
) != 0)
246 ret
= nla_get_u32(tb
[CTRL_ATTR_MCAST_GRP_ID
]);
255 int unl_genl_subscribe(struct unl
*unl
, const char *name
)
259 mcid
= unl_genl_multicast_id(unl
, name
);
263 return nl_socket_add_membership(unl
->sock
, mcid
);
266 int unl_genl_unsubscribe(struct unl
*unl
, const char *name
)
270 mcid
= unl_genl_multicast_id(unl
, name
);
274 return nl_socket_drop_membership(unl
->sock
, mcid
);
277 int unl_nl80211_phy_lookup(const char *name
)
282 snprintf(buf
, sizeof(buf
), "/sys/class/ieee80211/%s/index", name
);
284 fd
= open(buf
, O_RDONLY
);
287 pos
= read(fd
, buf
, sizeof(buf
) - 1);
297 int unl_nl80211_wdev_to_phy(struct unl
*unl
, int wdev
)
303 msg
= unl_genl_msg(unl
, NL80211_CMD_GET_INTERFACE
, false);
307 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, wdev
);
308 if (unl_request_single(unl
, msg
, &msg
) < 0)
311 attr
= unl_find_attr(unl
, msg
, NL80211_ATTR_WIPHY
);
315 ret
= nla_get_u32(attr
);