mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-12-21 03:32:42 +01:00
scan: Refactor scanning code
In preparation for adding active scans
This commit is contained in:
parent
d377b4c31f
commit
b000c702b0
239
src/scan.c
239
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);
|
||||
|
||||
sc->state = SCAN_STATE_NOT_RUNNING;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
scan_periodic_rearm(sp);
|
||||
}
|
||||
case NL80211_CMD_TRIGGER_SCAN:
|
||||
if (active_scan)
|
||||
sc->state = SCAN_STATE_ACTIVE;
|
||||
else
|
||||
sc->state = SCAN_STATE_PASSIVE;
|
||||
|
||||
return;
|
||||
}
|
||||
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;
|
||||
|
17
src/scan.h
17
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();
|
||||
|
28
src/wiphy.c
28
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();
|
||||
|
Loading…
Reference in New Issue
Block a user