scan: Refactor scanning code

In preparation for adding active scans
This commit is contained in:
Denis Kenzior 2015-09-20 14:58:23 -05:00
parent d377b4c31f
commit b000c702b0
3 changed files with 178 additions and 106 deletions

View File

@ -42,26 +42,94 @@
#define SCAN_MAX_INTERVAL 320 #define SCAN_MAX_INTERVAL 320
#define SCAN_INIT_INTERVAL 10 #define SCAN_INIT_INTERVAL 10
struct l_queue *periodic_scans = NULL; struct l_queue *scan_contexts = NULL;
struct l_genl_family *nl80211 = NULL; struct l_genl_family *nl80211 = NULL;
uint32_t scan_id = 0; 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 { struct scan_results {
uint32_t wiphy; uint32_t wiphy;
uint32_t ifindex; uint32_t ifindex;
struct l_queue *bss_list; struct l_queue *bss_list;
struct scan_freq_set *freqs; struct scan_freq_set *freqs;
scan_notify_func_t callback;
void *userdata;
}; };
struct scan_periodic { static bool scan_context_match(const void *a, const void *b)
uint32_t ifindex; {
struct l_timeout *timeout; const struct scan_context *sc = a;
uint16_t interval; uint32_t ifindex = L_PTR_TO_UINT(b);
bool triggered:1;
}; 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, void scan_start(struct l_genl_family *nl80211, uint32_t ifindex,
scan_func_t callback, void *user_data) 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"); 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) 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; int err;
l_debug(""); l_debug("");
@ -122,77 +170,83 @@ static void scan_periodic_done(struct l_genl_msg *msg, void *user_data)
if (err < 0) { if (err < 0) {
/* Scan already in progress */ /* Scan already in progress */
if (err != -EBUSY) if (err != -EBUSY)
sp->triggered = true;
else
l_warn("Periodic scan could not be triggered: %s (%d)", l_warn("Periodic scan could not be triggered: %s (%d)",
strerror(-err), -err); strerror(-err), -err);
return; return;
} }
sp->triggered = true; sc->state = SCAN_STATE_PASSIVE;
l_debug("Periodic scan triggered for ifindex: %u", sp->ifindex); 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; struct scan_context *sc;
uint32_t ifindex = L_PTR_TO_UINT(b);
return (sp->ifindex == ifindex); sc = l_queue_find(scan_contexts, scan_context_match,
}
void scan_periodic_start(uint32_t ifindex)
{
struct scan_periodic *sp;
sp = l_queue_find(periodic_scans, scan_periodic_match,
L_UINT_TO_PTR(ifindex)); 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; return;
l_debug("Starting periodic scan for ifindex: %u", ifindex); l_debug("Starting periodic scan for ifindex: %u", ifindex);
sp = scan_periodic_new(ifindex); sc->sp.interval = SCAN_INIT_INTERVAL;
l_queue_push_head(periodic_scans, sp); sc->sp.callback = func;
scan_start(nl80211, ifindex, scan_periodic_done, sp); sc->sp.userdata = userdata;
scan_start(nl80211, ifindex, scan_periodic_done, sc);
} }
bool scan_periodic_stop(uint32_t ifindex) 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)); L_UINT_TO_PTR(ifindex));
if (!sp) if (!sc)
return false;
if (!sc->sp.interval)
return false; return false;
l_debug("Stopping periodic scan for ifindex: %u", ifindex); 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; return true;
} }
static void scan_periodic_timeout(struct l_timeout *timeout, void *user_data) 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; sc->sp.interval *= 2;
scan_start(nl80211, sp->ifindex, scan_periodic_done, sp); 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) if (sc->sp.timeout)
l_timeout_modify(sp->timeout, sp->interval); l_timeout_modify(sc->sp.timeout, sc->sp.interval);
else else
sp->timeout = l_timeout_create(sp->interval, sc->sp.timeout = l_timeout_create(sc->sp.interval,
scan_periodic_timeout, sp, NULL); scan_periodic_timeout, sc, NULL);
} }
enum scan_ssid_security scan_get_ssid_security( enum scan_ssid_security scan_get_ssid_security(
@ -543,9 +597,11 @@ static void get_scan_done(void *user)
if (!results->bss_list) if (!results->bss_list)
goto done; goto done;
if (notify) l_debug("results->callback: %p", results->callback);
new_owner = notify(results->wiphy, results->ifindex,
results->bss_list); if (results->callback)
new_owner = results->callback(results->wiphy, results->ifindex,
results->bss_list, results->userdata);
if (!new_owner) if (!new_owner)
l_queue_destroy(results->bss_list, 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; bool have_ifindex;
uint32_t uninitialized_var(attr_wiphy); uint32_t uninitialized_var(attr_wiphy);
bool have_wiphy; bool have_wiphy;
struct scan_context *sc;
bool active_scan = false;
cmd = l_genl_msg_get_command(msg); 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; have_ifindex = true;
attr_ifindex = *((uint32_t *) data); attr_ifindex = *((uint32_t *) data);
break; 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; return;
} }
if (!notify) sc = l_queue_find(scan_contexts, scan_context_match,
L_UINT_TO_PTR(attr_ifindex));
if (!sc)
return; return;
switch (cmd) { 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 l_genl_msg *scan_msg;
struct scan_results *results; struct scan_results *results;
struct scan_periodic *sp;
results = l_new(struct scan_results, 1); results = l_new(struct scan_results, 1);
results->wiphy = attr_wiphy; 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); 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); scan_msg = l_genl_msg_new_sized(NL80211_CMD_GET_SCAN, 8);
l_genl_msg_append_attr(scan_msg, NL80211_ATTR_IFINDEX, 4, l_genl_msg_append_attr(scan_msg, NL80211_ATTR_IFINDEX, 4,
&attr_ifindex); &attr_ifindex);
l_genl_family_dump(nl80211, scan_msg, get_scan_callback, l_genl_family_dump(nl80211, scan_msg, get_scan_callback,
results, get_scan_done); results, get_scan_done);
sp = l_queue_find(periodic_scans, scan_periodic_match, if (sc->state == SCAN_STATE_PASSIVE && sc->sp.interval != 0)
L_UINT_TO_PTR(attr_ifindex)); scan_periodic_rearm(sc);
if (sp) {
if (!sp->triggered) {
l_debug("Resetting periodic timeout");
sp->interval = SCAN_INIT_INTERVAL;
}
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; 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; nl80211 = in;
scan_id = l_genl_family_register(nl80211, "scan", scan_notify, 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; return false;
} }
notify = func; scan_contexts = l_queue_new();
periodic_scans = l_queue_new();
return true; return true;
} }
@ -806,10 +878,9 @@ bool scan_exit()
if (!nl80211) if (!nl80211)
return false; return false;
notify = NULL; l_queue_destroy(scan_contexts,
l_queue_destroy(periodic_scans, (l_queue_destroy_func_t) scan_context_free);
(l_queue_destroy_func_t) scan_periodic_free); scan_contexts = NULL;
periodic_scans = NULL;
r = l_genl_family_unregister(nl80211, scan_id); r = l_genl_family_unregister(nl80211, scan_id);
scan_id = 0; scan_id = 0;

View File

@ -32,9 +32,16 @@ enum scan_band {
SCAN_BAND_5_GHZ, 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 void (*scan_func_t)(struct l_genl_msg *msg, void *user_data);
typedef bool (*scan_notify_func_t)(uint32_t wiphy, uint32_t ifindex, 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 scan_freq_set;
struct ie_rsn_info; struct ie_rsn_info;
@ -56,7 +63,8 @@ struct scan_bss {
void scan_start(struct l_genl_family *nl80211, uint32_t ifindex, void scan_start(struct l_genl_family *nl80211, uint32_t ifindex,
scan_func_t callback, void *user_data); 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); bool scan_periodic_stop(uint32_t ifindex);
void scan_sched_start(struct l_genl_family *nl80211, 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_add(struct scan_freq_set *freqs, uint32_t freq);
bool scan_freq_set_contains(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(); bool scan_exit();

View File

@ -115,6 +115,9 @@ struct autoconnect_entry {
static struct l_queue *wiphy_list = NULL; 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) static void do_debug(const char *str, void *user_data)
{ {
const char *prefix = 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) { switch (state) {
case NETDEV_STATE_AUTOCONNECT: case NETDEV_STATE_AUTOCONNECT:
scan_periodic_start(netdev->index); scan_periodic_start(netdev->index, new_scan_results, netdev);
break; break;
case NETDEV_STATE_DISCONNECTED: case NETDEV_STATE_DISCONNECTED:
scan_periodic_stop(netdev->index); scan_periodic_stop(netdev->index);
@ -918,6 +921,7 @@ static void netdev_free(void *data)
l_queue_destroy(netdev->autoconnect_list, l_free); l_queue_destroy(netdev->autoconnect_list, l_free);
l_io_destroy(netdev->eapol_io); l_io_destroy(netdev->eapol_io);
scan_ifindex_remove(netdev->index);
netdev_set_linkmode_and_operstate(netdev->index, 0, IF_OPER_DOWN, netdev_set_linkmode_and_operstate(netdev->index, 0, IF_OPER_DOWN,
NULL, NULL); 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, 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 = userdata;
struct netdev *netdev;
const struct l_queue_entry *bss_entry; 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->old_bss_list = netdev->bss_list;
netdev->bss_list = bss_list; netdev->bss_list = bss_list;
l_hashmap_foreach(netdev->networks, network_reset_bss_list, NULL); 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, netdev_set_linkmode_and_operstate(netdev->index, 1,
IF_OPER_DORMANT, NULL, NULL); IF_OPER_DORMANT, NULL, NULL);
scan_ifindex_add(netdev->index);
netdev_enter_state(netdev, NETDEV_STATE_AUTOCONNECT); netdev_enter_state(netdev, NETDEV_STATE_AUTOCONNECT);
} }
@ -2288,7 +2278,7 @@ static void nl80211_appeared(void *user_data)
wiphy_regulatory_notify, NULL, NULL)) wiphy_regulatory_notify, NULL, NULL))
l_error("Registering for regulatory notification failed"); 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"); l_error("Unable to init scan functionality");
wiphy_list = l_queue_new(); wiphy_list = l_queue_new();