Created
January 1, 2017 18:29
-
-
Save longsleep/03e034a8cd27e112ed64968df8b37501 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
sudo apt-get install libnl-genl-3-dev | |
gcc debug-nl80211.c $(pkg-config --cflags --libs libnl-genl-3.0) -o debug-nl80211 | |
*/ | |
#include <errno.h> | |
#include <netlink/netlink.h> | |
#include <netlink/genl/ctrl.h> | |
#include <netlink/genl/genl.h> | |
#include <linux/nl80211.h> | |
#include <net/if.h> | |
struct handler_args { // For family_handler() and nl_get_multicast_id(). | |
const char *group; | |
int id; | |
}; | |
static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) { | |
// Callback for errors. | |
printf("error_handler() called.\n"); | |
int *ret = arg; | |
*ret = err->error; | |
return NL_STOP; | |
} | |
static int finish_handler(struct nl_msg *msg, void *arg) { | |
// Callback for NL_CB_FINISH. | |
printf("finish_handler() called.\n"); | |
int *ret = arg; | |
*ret = 0; | |
return NL_SKIP; | |
} | |
static int ack_handler(struct nl_msg *msg, void *arg) { | |
// Callback for NL_CB_ACK. | |
printf("ack_handler() called.\n"); | |
int *ret = arg; | |
*ret = 0; | |
return NL_STOP; | |
} | |
static int family_handler(struct nl_msg *msg, void *arg) { | |
// Callback for NL_CB_VALID within nl_get_multicast_id(). From http://sourcecodebrowser.com/iw/0.9.14/genl_8c.html. | |
printf("family_handler() called.\n"); | |
struct handler_args *grp = arg; | |
struct nlattr *tb[CTRL_ATTR_MAX + 1]; | |
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); | |
struct nlattr *mcgrp; | |
int rem_mcgrp; | |
nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); | |
if (!tb[CTRL_ATTR_MCAST_GROUPS]) return NL_SKIP; | |
nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) { // This is a loop. | |
struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1]; | |
nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp), nla_len(mcgrp), NULL); | |
if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] || !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]) continue; | |
if (strncmp(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]), grp->group, | |
nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]))) { | |
continue; | |
} | |
grp->id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]); | |
break; | |
} | |
return NL_SKIP; | |
} | |
int nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group) { | |
// From http://sourcecodebrowser.com/iw/0.9.14/genl_8c.html. | |
struct nl_msg *msg; | |
struct nl_cb *cb; | |
int ret, ctrlid; | |
struct handler_args grp = { .group = group, .id = -ENOENT, }; | |
msg = nlmsg_alloc(); | |
if (!msg) return -ENOMEM; | |
cb = nl_cb_alloc(NL_CB_DEFAULT); | |
if (!cb) { | |
ret = -ENOMEM; | |
goto out_fail_cb; | |
} | |
ctrlid = genl_ctrl_resolve(sock, "nlctrl"); | |
genlmsg_put(msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0); | |
ret = -ENOBUFS; | |
NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family); | |
ret = nl_send_auto_complete(sock, msg); | |
if (ret < 0) goto out; | |
ret = 1; | |
nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret); | |
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret); | |
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &ret); | |
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, family_handler, &grp); | |
while (ret > 0) nl_recvmsgs(sock, cb); | |
if (ret == 0) ret = grp.id; | |
nla_put_failure: | |
out: | |
nl_cb_put(cb); | |
out_fail_cb: | |
nlmsg_free(msg); | |
return ret; | |
} | |
int do_scan_trigger(struct nl_sock *socket, int if_index, int driver_id) { | |
printf("do_scan_trigger start\n"); | |
int mcid = nl_get_multicast_id(socket, "nl80211", "scan"); | |
printf("nl_get_multicast_id: %d\n", mcid); | |
return 0; | |
} | |
int main() { | |
int if_index = if_nametoindex("wlan0"); // Use this wireless interface for scanning. | |
// Open socket to kernel. | |
struct nl_sock *socket = nl_socket_alloc(); // Allocate new netlink socket in memory. | |
genl_connect(socket); // Create file descriptor and bind socket. | |
int driver_id = genl_ctrl_resolve(socket, "nl80211"); // Find the nl80211 driver ID. | |
// Issue NL80211_CMD_TRIGGER_SCAN to the kernel and wait for it to finish. | |
int err = do_scan_trigger(socket, if_index, driver_id); | |
if (err != 0) { | |
printf("do_scan_trigger() failed with %d.\n", err); | |
return err; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment