From 42fe517d4ee9620fdeada59fc6a4dd870e2f9f25 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Mon, 16 Jul 2018 15:29:15 -0700 Subject: [PATCH] netdev: added station watch For Ad-Hoc networks, the kernel takes care of auth/assoc and issues a NEW_STATION event when that is complete. This provides a way to notify when NEW_STATION events occur as well as forward the MAC of the station to Ad-Hoc. The two new API's added: - netdev_station_watch_add() - netdev_station_watch_remove() --- src/netdev.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/netdev.h | 8 ++++++++ 2 files changed, 62 insertions(+) diff --git a/src/netdev.c b/src/netdev.c index 311f13a1..e71b9628 100644 --- a/src/netdev.c +++ b/src/netdev.c @@ -103,6 +103,8 @@ struct netdev { struct watchlist frame_watches; + struct watchlist station_watches; + struct l_io *pae_io; /* for drivers without EAPoL over NL80211 */ bool connected : 1; @@ -589,6 +591,7 @@ static void netdev_free(void *data) device_remove(netdev->device); watchlist_destroy(&netdev->event_watches); watchlist_destroy(&netdev->frame_watches); + watchlist_destroy(&netdev->station_watches); l_io_destroy(netdev->pae_io); @@ -2988,6 +2991,39 @@ static void netdev_unprot_disconnect_event(struct l_genl_msg *msg, netdev_sa_query_timeout, netdev, NULL); } +static void netdev_station_event(struct l_genl_msg *msg, + struct netdev *netdev, bool added) +{ + struct l_genl_attr attr; + uint16_t type; + uint16_t len; + const void *data; + const uint8_t *mac = NULL; + + if (netdev_get_iftype(netdev) != NETDEV_IFTYPE_ADHOC) + return; + + if (!l_genl_attr_init(&attr, msg)) + return; + + while (l_genl_attr_next(&attr, &type, &len, &data)) { + switch (type) { + case NL80211_ATTR_MAC: + mac = data; + break; + } + } + + if (!mac) { + l_error("%s station event did not include MAC attribute", + added ? "new" : "del"); + return; + } + + WATCHLIST_NOTIFY(&netdev->station_watches, + netdev_station_watch_func_t, netdev, mac, added); +} + static void netdev_mlme_notify(struct l_genl_msg *msg, void *user_data) { struct netdev *netdev = NULL; @@ -3047,6 +3083,12 @@ static void netdev_mlme_notify(struct l_genl_msg *msg, void *user_data) case NL80211_CMD_UNPROT_DISASSOCIATE: netdev_unprot_disconnect_event(msg, netdev); break; + case NL80211_CMD_NEW_STATION: + netdev_station_event(msg, netdev, true); + break; + case NL80211_CMD_DEL_STATION: + netdev_station_event(msg, netdev, false); + break; } } @@ -4044,6 +4086,7 @@ static void netdev_create_from_genl(struct l_genl_msg *msg) watchlist_init(&netdev->event_watches, NULL); watchlist_init(&netdev->frame_watches, &netdev_frame_watch_ops); + watchlist_init(&netdev->station_watches, NULL); l_queue_push_tail(netdev_list, netdev); @@ -4173,6 +4216,17 @@ bool netdev_watch_remove(struct netdev *netdev, uint32_t id) return watchlist_remove(&netdev->event_watches, id); } +uint32_t netdev_station_watch_add(struct netdev *netdev, + netdev_station_watch_func_t func, void *user_data) +{ + return watchlist_add(&netdev->station_watches, func, user_data, NULL); +} + +bool netdev_station_watch_remove(struct netdev *netdev, uint32_t id) +{ + return watchlist_remove(&netdev->station_watches, id); +} + bool netdev_init(struct l_genl_family *in, const char *whitelist, const char *blacklist) { diff --git a/src/netdev.h b/src/netdev.h index d16c469b..3017307b 100644 --- a/src/netdev.h +++ b/src/netdev.h @@ -91,6 +91,9 @@ typedef void (*netdev_frame_watch_func_t)(struct netdev *netdev, const struct mmpdu_header *frame, const void *body, size_t body_len, void *user_data); +typedef void (*netdev_station_watch_func_t)(struct netdev *netdev, + const uint8_t *mac, bool added, + void *user_data); struct wiphy *netdev_get_wiphy(struct netdev *netdev); const uint8_t *netdev_get_address(struct netdev *netdev); @@ -157,6 +160,11 @@ uint32_t netdev_watch_add(struct netdev *netdev, netdev_watch_func_t func, void *user_data); bool netdev_watch_remove(struct netdev *netdev, uint32_t id); +uint32_t netdev_station_watch_add(struct netdev *netdev, + netdev_station_watch_func_t func, void *user_data); + +bool netdev_station_watch_remove(struct netdev *netdev, uint32_t id); + bool netdev_init(struct l_genl_family *in, const char *whitelist, const char *blacklist); bool netdev_exit(void);