1 #include <netlink/netlink.h>
2 #include <netlink/genl/genl.h>
3 #include <netlink/genl/ctrl.h>
4 #include <netlink/genl/family.h>
9 #include <linux/nl80211.h>
13 static int unl_init(struct unl
*unl
)
15 unl
->sock
= nl_socket_alloc();
22 int unl_genl_init(struct unl
*unl
, const char *family
)
24 memset(unl
, 0, sizeof(*unl
));
29 unl
->hdrlen
= NLMSG_ALIGN(sizeof(struct genlmsghdr
));
30 unl
->family_name
= strdup(family
);
31 if (!unl
->family_name
)
34 if (genl_connect(unl
->sock
))
37 if (genl_ctrl_alloc_cache(unl
->sock
, &unl
->cache
))
40 unl
->family
= genl_ctrl_search_by_name(unl
->cache
, family
);
52 void unl_free(struct unl
*unl
)
55 free(unl
->family_name
);
58 nl_socket_free(unl
->sock
);
61 nl_cache_free(unl
->cache
);
63 memset(unl
, 0, sizeof(*unl
));
67 ack_handler(struct nl_msg
*msg
, void *arg
)
75 finish_handler(struct nl_msg
*msg
, void *arg
)
83 error_handler(struct sockaddr_nl
*nla
, struct nlmsgerr
*err
, void *arg
)
90 struct nl_msg
*unl_genl_msg(struct unl
*unl
, int cmd
, bool dump
)
102 genlmsg_put(msg
, NL_AUTO_PID
, NL_AUTO_SEQ
,
103 genl_family_get_id(unl
->family
), 0, flags
, cmd
, 0);
109 int unl_genl_request(struct unl
*unl
, struct nl_msg
*msg
, unl_cb handler
, void *arg
)
111 struct nlmsghdr
*nlh
;
115 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
116 nlh
= nlmsg_hdr(msg
);
118 err
= nl_send_auto_complete(unl
->sock
, msg
);
123 nl_cb_err(cb
, NL_CB_CUSTOM
, error_handler
, &err
);
124 nl_cb_set(cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, finish_handler
, &err
);
125 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, ack_handler
, &err
);
127 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, handler
, arg
);
130 nl_recvmsgs(unl
->sock
, cb
);
138 static int request_single_cb(struct nl_msg
*msg
, void *arg
)
140 struct nl_msg
**dest
= arg
;
149 int unl_genl_request_single(struct unl
*unl
, struct nl_msg
*msg
, struct nl_msg
**dest
)
152 return unl_genl_request(unl
, msg
, request_single_cb
, dest
);
155 static int no_seq_check(struct nl_msg
*msg
, void *arg
)
160 void unl_genl_loop(struct unl
*unl
, unl_cb handler
, void *arg
)
164 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
165 unl
->loop_done
= false;
166 nl_cb_set(cb
, NL_CB_SEQ_CHECK
, NL_CB_CUSTOM
, no_seq_check
, NULL
);
167 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, handler
, arg
);
169 while (!unl
->loop_done
)
170 nl_recvmsgs(unl
->sock
, cb
);
175 static int unl_genl_multicast_id(struct unl
*unl
, const char *name
)
177 struct nlattr
*tb
[CTRL_ATTR_MCAST_GRP_MAX
+ 1];
178 struct nlattr
*groups
, *group
;
188 ctrlid
= genl_ctrl_resolve(unl
->sock
, "nlctrl");
189 genlmsg_put(msg
, 0, 0, ctrlid
, 0, 0, CTRL_CMD_GETFAMILY
, 0);
190 NLA_PUT_STRING(msg
, CTRL_ATTR_FAMILY_NAME
, unl
->family_name
);
191 unl_genl_request_single(unl
, msg
, &msg
);
193 goto nla_put_failure
;
195 groups
= unl_find_attr(unl
, msg
, CTRL_ATTR_MCAST_GROUPS
);
199 nla_for_each_nested(group
, groups
, rem
) {
202 nla_parse(tb
, CTRL_ATTR_MCAST_GRP_MAX
, nla_data(group
),
203 nla_len(group
), NULL
);
205 if (!tb
[CTRL_ATTR_MCAST_GRP_NAME
] ||
206 !tb
[CTRL_ATTR_MCAST_GRP_ID
])
209 gn
= nla_data(tb
[CTRL_ATTR_MCAST_GRP_NAME
]);
210 if (strcmp(gn
, name
) != 0)
213 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
);