diff options
Diffstat (limited to 'src/assocwatch.c')
-rw-r--r-- | src/assocwatch.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/src/assocwatch.c b/src/assocwatch.c new file mode 100644 index 0000000..c3bf5f2 --- /dev/null +++ b/src/assocwatch.c @@ -0,0 +1,88 @@ +#include <sys/types.h> +#include <sys/socket.h> +#include <linux/types.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <linux/if.h> +#include <assert.h> +#include <libdaemon/dlog.h> +#include "wireless.h" + +#include "util.h" +#include "assocwatch.h" +#include "nlapi.h" + +static int handle_wireless_event(int idx, uint8_t *data, int l, int (*cb) (int idx, struct hw_addr *a)) { + struct iw_event *e; + int hs; + struct hw_addr ap; + + e = (struct iw_event*) data; + hs = sizeof(struct iw_event)-sizeof(union iwreq_data); + while (l >= sizeof(struct iw_event)) { + + if (e->len < hs) { + daemon_log(LOG_ERR, "ASSOCWATCH: Recieved corrupt wireless event\n"); + return -1; + } + + switch (e->cmd) { + + case SIOCGIWAP: + if (e->len < hs + sizeof(struct sockaddr)) { + daemon_log(LOG_ERR, "ASSOCWATCH: Recieved corrupt AP wireless event\n"); + return -1; + } + + memcpy(ap.addr, e->u.ap_addr.sa_data, ETH_ALEN); + + if (cb(idx, is_assoc_ap(&ap) ? &ap : NULL) < 0) + return -1; + + return 0; + } + + l -= e->len; + e = (struct iw_event*) (((uint8_t*) e) + e->len); + } + + return 0; +} + +static int callback(struct nlmsghdr *n, void *u) { + int (*cb) (int idx, struct hw_addr *a) = u; + + if (n->nlmsg_type == RTM_NEWLINK) { + struct ifinfomsg* ifi; + struct rtattr *a; + int la; + + if (n->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) { + daemon_log(LOG_ERR, "ASSOCWATCH: Corrupt NETLINK message\n"); + return -1; + } + + ifi = NLMSG_DATA(n); + a = (void*) ifi + NLMSG_ALIGN(sizeof(struct ifinfomsg)); + la = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg)); + + while (RTA_OK(a, la)) { + if(a->rta_type == IFLA_WIRELESS) + handle_wireless_event(ifi->ifi_index, RTA_DATA(a), RTA_PAYLOAD(a), cb); + + a = RTA_NEXT(a, la); + } + } + + return 0; +} + + +int assocwatch_init(int (*cb) (int idx, struct hw_addr *a)) { + return nlapi_register(callback, cb); +} |