summaryrefslogtreecommitdiffstats
path: root/src/assocwatch.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/assocwatch.c')
-rw-r--r--src/assocwatch.c88
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);
+}