From b000c702b07b00cb5983cdd7e46ce660fb933ae6 Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Sun, 20 Sep 2015 14:58:23 -0500 Subject: [PATCH] scan: Refactor scanning code In preparation for adding active scans --- src/scan.c | 239 ++++++++++++++++++++++++++++++++++------------------ src/scan.h | 17 +++- src/wiphy.c | 28 ++---- 3 files changed, 178 insertions(+), 106 deletions(-) diff --git a/src/scan.c b/src/scan.c index df163e00..6fa18c7f 100644 --- a/src/scan.c +++ b/src/scan.c @@ -42,26 +42,94 @@ #define SCAN_MAX_INTERVAL 320 #define SCAN_INIT_INTERVAL 10 -struct l_queue *periodic_scans = NULL; +struct l_queue *scan_contexts = NULL; struct l_genl_family *nl80211 = NULL; uint32_t scan_id = 0; -scan_notify_func_t notify = NULL; +struct scan_periodic { + struct l_timeout *timeout; + uint16_t interval; + scan_notify_func_t callback; + void *userdata; +}; + +struct scan_context { + uint32_t ifindex; + enum scan_state state; + struct scan_periodic sp; +}; struct scan_results { uint32_t wiphy; uint32_t ifindex; struct l_queue *bss_list; struct scan_freq_set *freqs; + scan_notify_func_t callback; + void *userdata; }; -struct scan_periodic { - uint32_t ifindex; - struct l_timeout *timeout; - uint16_t interval; - bool triggered:1; -}; +static bool scan_context_match(const void *a, const void *b) +{ + const struct scan_context *sc = a; + uint32_t ifindex = L_PTR_TO_UINT(b); + + return (sc->ifindex == ifindex); +} + +static struct scan_context *scan_context_new(uint32_t ifindex) +{ + struct scan_context *sc; + + sc = l_new(struct scan_context, 1); + + sc->ifindex = ifindex; + sc->state = SCAN_STATE_NOT_RUNNING; + + return sc; +} + +static void scan_context_free(struct scan_context *sc) +{ + l_debug("sc: %p", sc); + + if (sc->sp.timeout) + l_timeout_remove(sc->sp.timeout); + + l_free(sc); +} + +bool scan_ifindex_add(uint32_t ifindex) +{ + struct scan_context *sc; + + sc = l_queue_find(scan_contexts, scan_context_match, + L_UINT_TO_PTR(ifindex)); + + if (sc) + return false; + + sc = scan_context_new(ifindex); + l_queue_push_head(scan_contexts, sc); + + return true; +} + +bool scan_ifindex_remove(uint32_t ifindex) +{ + struct scan_context *sc; + + sc = l_queue_remove_if(scan_contexts, scan_context_match, + L_UINT_TO_PTR(ifindex)); + + if (!sc) + return false; + + l_info("Removing scan context for ifindex: %u", ifindex); + scan_context_free(sc); + + return true; +} void scan_start(struct l_genl_family *nl80211, uint32_t ifindex, scan_func_t callback, void *user_data) @@ -91,29 +159,9 @@ void scan_sched_start(struct l_genl_family *nl80211, uint32_t ifindex, l_error("Starting scheduled scan failed"); } -static struct scan_periodic *scan_periodic_new(uint32_t ifindex) -{ - struct scan_periodic *sp; - - sp = l_new(struct scan_periodic, 1); - - sp->ifindex = ifindex; - sp->interval = SCAN_INIT_INTERVAL; - - return sp; -} - -static void scan_periodic_free(struct scan_periodic *sp) -{ - if (sp->timeout) - l_timeout_remove(sp->timeout); - - l_free(sp); -} - static void scan_periodic_done(struct l_genl_msg *msg, void *user_data) { - struct scan_periodic *sp = user_data; + struct scan_context *sc = user_data; int err; l_debug(""); @@ -122,77 +170,83 @@ static void scan_periodic_done(struct l_genl_msg *msg, void *user_data) if (err < 0) { /* Scan already in progress */ if (err != -EBUSY) - sp->triggered = true; - else l_warn("Periodic scan could not be triggered: %s (%d)", strerror(-err), -err); + return; } - sp->triggered = true; - l_debug("Periodic scan triggered for ifindex: %u", sp->ifindex); + sc->state = SCAN_STATE_PASSIVE; + l_debug("Periodic scan triggered for ifindex: %u", sc->ifindex); } -static bool scan_periodic_match(const void *a, const void *b) +void scan_periodic_start(uint32_t ifindex, scan_notify_func_t func, + void *userdata) { - const struct scan_periodic *sp = a; - uint32_t ifindex = L_PTR_TO_UINT(b); + struct scan_context *sc; - return (sp->ifindex == ifindex); -} - -void scan_periodic_start(uint32_t ifindex) -{ - struct scan_periodic *sp; - - sp = l_queue_find(periodic_scans, scan_periodic_match, + sc = l_queue_find(scan_contexts, scan_context_match, L_UINT_TO_PTR(ifindex)); - if (sp) + if (!sc) { + l_error("scan_periodic_start called without scan_ifindex_add"); + return; + } + + if (sc->sp.interval) return; l_debug("Starting periodic scan for ifindex: %u", ifindex); - sp = scan_periodic_new(ifindex); - l_queue_push_head(periodic_scans, sp); - scan_start(nl80211, ifindex, scan_periodic_done, sp); + sc->sp.interval = SCAN_INIT_INTERVAL; + sc->sp.callback = func; + sc->sp.userdata = userdata; + + scan_start(nl80211, ifindex, scan_periodic_done, sc); } bool scan_periodic_stop(uint32_t ifindex) { - struct scan_periodic *sp; + struct scan_context *sc; - sp = l_queue_remove_if(periodic_scans, scan_periodic_match, + sc = l_queue_find(scan_contexts, scan_context_match, L_UINT_TO_PTR(ifindex)); - if (!sp) + if (!sc) + return false; + + if (!sc->sp.interval) return false; l_debug("Stopping periodic scan for ifindex: %u", ifindex); - scan_periodic_free(sp); + l_timeout_remove(sc->sp.timeout); + sc->sp.interval = 0; + sc->sp.callback = NULL; + sc->sp.userdata = NULL; + return true; } static void scan_periodic_timeout(struct l_timeout *timeout, void *user_data) { - struct scan_periodic *sp = user_data; + struct scan_context *sc = user_data; - l_debug("scan_periodic_timeout: %u", sp->ifindex); + l_debug("scan_periodic_timeout: %u", sc->ifindex); - sp->interval *= 2; - scan_start(nl80211, sp->ifindex, scan_periodic_done, sp); + sc->sp.interval *= 2; + scan_start(nl80211, sc->ifindex, scan_periodic_done, sc); } -static void scan_periodic_rearm(struct scan_periodic *sp) +static void scan_periodic_rearm(struct scan_context *sc) { - l_debug("Arming periodic scan timer: %u", sp->interval); + l_debug("Arming periodic scan timer: %u", sc->sp.interval); - if (sp->timeout) - l_timeout_modify(sp->timeout, sp->interval); + if (sc->sp.timeout) + l_timeout_modify(sc->sp.timeout, sc->sp.interval); else - sp->timeout = l_timeout_create(sp->interval, - scan_periodic_timeout, sp, NULL); + sc->sp.timeout = l_timeout_create(sc->sp.interval, + scan_periodic_timeout, sc, NULL); } enum scan_ssid_security scan_get_ssid_security( @@ -543,9 +597,11 @@ static void get_scan_done(void *user) if (!results->bss_list) goto done; - if (notify) - new_owner = notify(results->wiphy, results->ifindex, - results->bss_list); + l_debug("results->callback: %p", results->callback); + + if (results->callback) + new_owner = results->callback(results->wiphy, results->ifindex, + results->bss_list, results->userdata); if (!new_owner) l_queue_destroy(results->bss_list, @@ -593,6 +649,8 @@ static void scan_notify(struct l_genl_msg *msg, void *user_data) bool have_ifindex; uint32_t uninitialized_var(attr_wiphy); bool have_wiphy; + struct scan_context *sc; + bool active_scan = false; cmd = l_genl_msg_get_command(msg); @@ -621,6 +679,9 @@ static void scan_notify(struct l_genl_msg *msg, void *user_data) have_ifindex = true; attr_ifindex = *((uint32_t *) data); break; + case NL80211_ATTR_SCAN_SSIDS: + active_scan = true; + break; } } @@ -634,7 +695,9 @@ static void scan_notify(struct l_genl_msg *msg, void *user_data) return; } - if (!notify) + sc = l_queue_find(scan_contexts, scan_context_match, + L_UINT_TO_PTR(attr_ifindex)); + if (!sc) return; switch (cmd) { @@ -643,7 +706,6 @@ static void scan_notify(struct l_genl_msg *msg, void *user_data) { struct l_genl_msg *scan_msg; struct scan_results *results; - struct scan_periodic *sp; results = l_new(struct scan_results, 1); results->wiphy = attr_wiphy; @@ -651,25 +713,36 @@ static void scan_notify(struct l_genl_msg *msg, void *user_data) scan_parse_new_scan_results(msg, results); + /* + * Can't use active_scan here, since NEW_SCAN_RESULTS always + * contains this attribute + */ + if (sc->state == SCAN_STATE_PASSIVE) { + results->callback = sc->sp.callback; + results->userdata = sc->sp.userdata; + } + scan_msg = l_genl_msg_new_sized(NL80211_CMD_GET_SCAN, 8); l_genl_msg_append_attr(scan_msg, NL80211_ATTR_IFINDEX, 4, &attr_ifindex); l_genl_family_dump(nl80211, scan_msg, get_scan_callback, results, get_scan_done); - sp = l_queue_find(periodic_scans, scan_periodic_match, - L_UINT_TO_PTR(attr_ifindex)); - if (sp) { - if (!sp->triggered) { - l_debug("Resetting periodic timeout"); - sp->interval = SCAN_INIT_INTERVAL; - } + if (sc->state == SCAN_STATE_PASSIVE && sc->sp.interval != 0) + scan_periodic_rearm(sc); - scan_periodic_rearm(sp); - } + sc->state = SCAN_STATE_NOT_RUNNING; - return; + break; } + + case NL80211_CMD_TRIGGER_SCAN: + if (active_scan) + sc->state = SCAN_STATE_ACTIVE; + else + sc->state = SCAN_STATE_PASSIVE; + + break; } } @@ -782,7 +855,7 @@ bool scan_freq_set_contains(struct scan_freq_set *freqs, uint32_t freq) return false; } -bool scan_init(struct l_genl_family *in, scan_notify_func_t func) +bool scan_init(struct l_genl_family *in) { nl80211 = in; scan_id = l_genl_family_register(nl80211, "scan", scan_notify, @@ -793,8 +866,7 @@ bool scan_init(struct l_genl_family *in, scan_notify_func_t func) return false; } - notify = func; - periodic_scans = l_queue_new(); + scan_contexts = l_queue_new(); return true; } @@ -806,10 +878,9 @@ bool scan_exit() if (!nl80211) return false; - notify = NULL; - l_queue_destroy(periodic_scans, - (l_queue_destroy_func_t) scan_periodic_free); - periodic_scans = NULL; + l_queue_destroy(scan_contexts, + (l_queue_destroy_func_t) scan_context_free); + scan_contexts = NULL; r = l_genl_family_unregister(nl80211, scan_id); scan_id = 0; diff --git a/src/scan.h b/src/scan.h index 53c53370..27adf28b 100644 --- a/src/scan.h +++ b/src/scan.h @@ -32,9 +32,16 @@ enum scan_band { SCAN_BAND_5_GHZ, }; +enum scan_state { + SCAN_STATE_NOT_RUNNING, + SCAN_STATE_PASSIVE, + SCAN_STATE_ACTIVE, +}; + typedef void (*scan_func_t)(struct l_genl_msg *msg, void *user_data); typedef bool (*scan_notify_func_t)(uint32_t wiphy, uint32_t ifindex, - struct l_queue *bss_list); + struct l_queue *bss_list, + void *userdata); struct scan_freq_set; struct ie_rsn_info; @@ -56,7 +63,8 @@ struct scan_bss { void scan_start(struct l_genl_family *nl80211, uint32_t ifindex, scan_func_t callback, void *user_data); -void scan_periodic_start(uint32_t ifindex); +void scan_periodic_start(uint32_t ifindex, scan_notify_func_t func, + void *userdata); bool scan_periodic_stop(uint32_t ifindex); void scan_sched_start(struct l_genl_family *nl80211, uint32_t ifindex, @@ -79,5 +87,8 @@ void scan_freq_set_free(struct scan_freq_set *freqs); bool scan_freq_set_add(struct scan_freq_set *freqs, uint32_t freq); bool scan_freq_set_contains(struct scan_freq_set *freqs, uint32_t freq); -bool scan_init(struct l_genl_family *in, scan_notify_func_t func); +bool scan_ifindex_add(uint32_t ifindex); +bool scan_ifindex_remove(uint32_t ifindex); + +bool scan_init(struct l_genl_family *in); bool scan_exit(); diff --git a/src/wiphy.c b/src/wiphy.c index a4170003..cbb676dd 100644 --- a/src/wiphy.c +++ b/src/wiphy.c @@ -115,6 +115,9 @@ struct autoconnect_entry { static struct l_queue *wiphy_list = NULL; +static bool new_scan_results(uint32_t wiphy_id, uint32_t ifindex, + struct l_queue *bss_list, void *userdata); + static void do_debug(const char *str, void *user_data) { const char *prefix = user_data; @@ -239,7 +242,7 @@ static void netdev_enter_state(struct netdev *netdev, enum netdev_state state) switch (state) { case NETDEV_STATE_AUTOCONNECT: - scan_periodic_start(netdev->index); + scan_periodic_start(netdev->index, new_scan_results, netdev); break; case NETDEV_STATE_DISCONNECTED: scan_periodic_stop(netdev->index); @@ -918,6 +921,7 @@ static void netdev_free(void *data) l_queue_destroy(netdev->autoconnect_list, l_free); l_io_destroy(netdev->eapol_io); + scan_ifindex_remove(netdev->index); netdev_set_linkmode_and_operstate(netdev->index, 0, IF_OPER_DOWN, NULL, NULL); @@ -1742,26 +1746,11 @@ static void process_bss(struct netdev *netdev, struct scan_bss *bss) } static bool new_scan_results(uint32_t wiphy_id, uint32_t ifindex, - struct l_queue *bss_list) + struct l_queue *bss_list, void *userdata) { - struct wiphy *wiphy; - struct netdev *netdev; + struct netdev *netdev = userdata; const struct l_queue_entry *bss_entry; - wiphy = l_queue_find(wiphy_list, wiphy_match, - L_UINT_TO_PTR(wiphy_id)); - if (!wiphy) { - l_warn("Scan notification for unknown wiphy"); - return false; - } - - netdev = l_queue_find(wiphy->netdev_list, netdev_match, - L_UINT_TO_PTR(ifindex)); - if (!netdev) { - l_warn("Scan notification for unknown ifindex"); - return false; - } - netdev->old_bss_list = netdev->bss_list; netdev->bss_list = bss_list; l_hashmap_foreach(netdev->networks, network_reset_bss_list, NULL); @@ -1925,6 +1914,7 @@ static void interface_dump_callback(struct l_genl_msg *msg, void *user_data) netdev_set_linkmode_and_operstate(netdev->index, 1, IF_OPER_DORMANT, NULL, NULL); + scan_ifindex_add(netdev->index); netdev_enter_state(netdev, NETDEV_STATE_AUTOCONNECT); } @@ -2288,7 +2278,7 @@ static void nl80211_appeared(void *user_data) wiphy_regulatory_notify, NULL, NULL)) l_error("Registering for regulatory notification failed"); - if (!scan_init(nl80211, new_scan_results)) + if (!scan_init(nl80211)) l_error("Unable to init scan functionality"); wiphy_list = l_queue_new();