3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2025-02-16 23:40:43 +01:00

scan: Refactor scan request and periodic scan logic

This should not change the behaviour except for fixing a rare crash
due to scan_cancel not working correctly when cancelling the first scan
request in the queue while a periodic scan was running, and potentially
other corner cases.  To be able to better distinguish between a periodic
scan in progress and a scan request in progress add a sc->current_sr
field that points either at a scan request or is NULL when a periodic
scan is in ongoing.  Move the triggered flag from scan_request and
scan_preiodic directly to scan_context so it's there together with
start_cmd_id.  Hopefully make scan_cancel simpler/clearer.

Note sc->state and sc->triggered have similar semantics so one of them
may be easily removed.  Also the wiphy_id parameter to the scan callback
is rather useless, note I temporarily pass 0 as the value on error but
perhaps it should be dropped.
This commit is contained in:
Andrew Zaborowski 2018-12-04 03:44:34 +01:00 committed by Denis Kenzior
parent f07119b33a
commit e4858d6da3

View File

@ -63,7 +63,6 @@ struct scan_periodic {
void *userdata; void *userdata;
bool rearm:1; bool rearm:1;
bool retry:1; bool retry:1;
bool triggered:1;
bool needs_active_scan:1; bool needs_active_scan:1;
bool passive:1; /* Active or Passive scan? */ bool passive:1; /* Active or Passive scan? */
struct l_queue *cmds; struct l_queue *cmds;
@ -76,7 +75,6 @@ struct scan_request {
void *userdata; void *userdata;
scan_destroy_func_t destroy; scan_destroy_func_t destroy;
bool passive:1; /* Active or Passive scan? */ bool passive:1; /* Active or Passive scan? */
bool triggered:1;
struct l_queue *cmds; struct l_queue *cmds;
}; };
@ -84,8 +82,10 @@ struct scan_context {
uint32_t ifindex; uint32_t ifindex;
enum scan_state state; enum scan_state state;
struct scan_periodic sp; struct scan_periodic sp;
struct scan_request *current_sr;
struct l_queue *requests; struct l_queue *requests;
unsigned int start_cmd_id; unsigned int start_cmd_id;
bool triggered:1;
struct wiphy *wiphy; struct wiphy *wiphy;
}; };
@ -127,10 +127,19 @@ static void scan_request_free(void *data)
l_free(sr); l_free(sr);
} }
static void scan_request_trigger_failed(struct scan_request *sr, int err) static void scan_request_failed(struct scan_context *sc,
struct scan_request *sr, int err)
{ {
sc->current_sr = NULL;
sc->triggered = false;
sc->start_cmd_id = 0;
sc->state = SCAN_STATE_NOT_RUNNING;
l_queue_remove(sc->requests, sr);
if (sr->trigger) if (sr->trigger)
sr->trigger(err, sr->userdata); sr->trigger(err, sr->userdata);
else if (sr->callback)
sr->callback(0, sc->ifindex, err, NULL, sr->userdata);
scan_request_free(sr); scan_request_free(sr);
} }
@ -227,7 +236,7 @@ static unsigned int scan_send_start(struct l_genl_msg **msg,
static void scan_triggered(struct l_genl_msg *msg, void *userdata) static void scan_triggered(struct l_genl_msg *msg, void *userdata)
{ {
struct scan_context *sc = userdata; struct scan_context *sc = userdata;
struct scan_request *sr = l_queue_peek_head(sc->requests); struct scan_request *sr = sc->current_sr;
int err; int err;
l_debug(""); l_debug("");
@ -240,8 +249,7 @@ static void scan_triggered(struct l_genl_msg *msg, void *userdata)
if (err == -EBUSY) if (err == -EBUSY)
return; return;
l_queue_pop_head(sc->requests); scan_request_failed(sc, sr, err);
scan_request_trigger_failed(sr, err);
l_error("Received error during CMD_TRIGGER_SCAN: %s (%d)", l_error("Received error during CMD_TRIGGER_SCAN: %s (%d)",
strerror(-err), -err); strerror(-err), -err);
@ -254,7 +262,7 @@ static void scan_triggered(struct l_genl_msg *msg, void *userdata)
sc->state = sr->passive ? SCAN_STATE_PASSIVE : SCAN_STATE_ACTIVE; sc->state = sr->passive ? SCAN_STATE_PASSIVE : SCAN_STATE_ACTIVE;
l_debug("%s scan triggered for ifindex: %u", l_debug("%s scan triggered for ifindex: %u",
sr->passive ? "Passive" : "Active", sc->ifindex); sr->passive ? "Passive" : "Active", sc->ifindex);
sr->triggered = true; sc->triggered = true;
if (sr->trigger) { if (sr->trigger) {
sr->trigger(0, sr->userdata); sr->trigger(0, sr->userdata);
@ -437,7 +445,8 @@ static int scan_request_send_next(struct scan_context *sc,
sc->start_cmd_id = scan_send_start(&cmd, scan_triggered, sc); sc->start_cmd_id = scan_send_start(&cmd, scan_triggered, sc);
if (sc->start_cmd_id) { if (sc->start_cmd_id) {
sr->triggered = false; sc->triggered = false;
sc->current_sr = sr;
return 0; return 0;
} }
@ -480,6 +489,7 @@ static uint32_t scan_common(uint32_t ifindex, bool passive,
if (!scan_request_send_next(sc, sr)) if (!scan_request_send_next(sc, sr))
goto done; goto done;
sr->destroy = NULL; /* Don't call destroy when returning error */
scan_request_free(sr); scan_request_free(sr);
return 0; return 0;
done: done:
@ -532,24 +542,9 @@ bool scan_cancel(uint32_t ifindex, uint32_t id)
if (!sc) if (!sc)
return false; return false;
sr = l_queue_peek_head(sc->requests); /* If already triggered, just zero out the callback */
if (!sr) if (sc->current_sr && sc->current_sr->id == id && sc->triggered) {
return false; sr = sc->current_sr;
if (sr->id == id) {
/* If we already sent the trigger command, cancel the scan */
if (!sr->triggered && sc->start_cmd_id) {
l_genl_family_cancel(nl80211, sc->start_cmd_id);
sc->start_cmd_id = 0;
l_queue_pop_head(sc->requests);
start_next_scan_request(sc);
goto free;
}
/* If already triggered, just zero out the callback */
sr->callback = NULL; sr->callback = NULL;
if (sr->destroy) { if (sr->destroy) {
@ -565,12 +560,15 @@ bool scan_cancel(uint32_t ifindex, uint32_t id)
if (!sr) if (!sr)
return false; return false;
free: /* If we already sent the trigger command, cancel the scan */
if (sr->destroy) if (sr == sc->current_sr) {
sr->destroy(sr->userdata); l_genl_family_cancel(nl80211, sc->start_cmd_id);
sc->start_cmd_id = 0;
sc->current_sr = NULL;
start_next_scan_request(sc);
}
scan_request_free(sr); scan_request_free(sr);
return true; return true;
} }
@ -619,7 +617,7 @@ static void scan_periodic_triggered(struct l_genl_msg *msg, void *user_data)
l_debug("Periodic %s scan triggered for ifindex: %u", sc->sp.passive ? l_debug("Periodic %s scan triggered for ifindex: %u", sc->sp.passive ?
"passive" : "active", sc->ifindex); "passive" : "active", sc->ifindex);
sc->sp.triggered = true; sc->triggered = true;
if (sc->sp.trigger) if (sc->sp.trigger)
sc->sp.trigger(0, sc->sp.userdata); sc->sp.trigger(0, sc->sp.userdata);
@ -770,8 +768,7 @@ static bool start_next_scan_request(struct scan_context *sc)
if (!scan_request_send_next(sc, sr)) if (!scan_request_send_next(sc, sr))
return true; return true;
l_queue_pop_head(sc->requests); scan_request_failed(sc, sr, -EIO);
scan_request_trigger_failed(sr, -EIO);
} }
if (sc->sp.retry) { if (sc->sp.retry) {
@ -1147,35 +1144,29 @@ static void discover_hidden_network_bsses(struct scan_context *sc,
static void scan_finished(struct scan_context *sc, uint32_t wiphy, static void scan_finished(struct scan_context *sc, uint32_t wiphy,
int err, struct l_queue *bss_list) int err, struct l_queue *bss_list)
{ {
struct scan_request *sr; struct scan_request *sr = sc->current_sr;
scan_notify_func_t callback = NULL; scan_notify_func_t callback = NULL;
void *userdata; void *userdata;
scan_destroy_func_t destroy = NULL;
bool new_owner = false; bool new_owner = false;
sr = l_queue_peek_head(sc->requests); if (sr) {
if (sr && sr->triggered) {
callback = sr->callback; callback = sr->callback;
userdata = sr->userdata; userdata = sr->userdata;
destroy = sr->destroy;
scan_request_free(sr); sc->current_sr = NULL;
l_queue_pop_head(sc->requests); l_queue_pop_head(sc->requests);
} else if (sc->sp.interval) { } else if (sc->sp.interval) {
/* /*
* If we'd called sc.sp->trigger, we must call back now * If we'd called sc.sp->trigger, we must call back now
* independent of whether the scan was succesful or was * independent of whether the scan was succesful or was
* aborted. If the scan was successful though we call back * aborted. If the scan was successful though we call back
* with the scan results even if didn't triggered this scan. * with the scan results even if we didn't trigger this scan.
*/ */
if (sc->sp.triggered || bss_list) { if (sc->triggered || bss_list) {
callback = sc->sp.callback; callback = sc->sp.callback;
userdata = sc->sp.userdata; userdata = sc->sp.userdata;
destroy = NULL;
} }
sc->sp.triggered = false;
if (bss_list) if (bss_list)
discover_hidden_network_bsses(sc, bss_list); discover_hidden_network_bsses(sc, bss_list);
} }
@ -1184,9 +1175,10 @@ static void scan_finished(struct scan_context *sc, uint32_t wiphy,
new_owner = callback(wiphy, sc->ifindex, err, new_owner = callback(wiphy, sc->ifindex, err,
bss_list, userdata); bss_list, userdata);
if (destroy) if (sr)
destroy(userdata); scan_request_free(sr);
sc->triggered = false;
sc->state = SCAN_STATE_NOT_RUNNING; sc->state = SCAN_STATE_NOT_RUNNING;
if (!start_next_scan_request(sc) && sc->sp.rearm) if (!start_next_scan_request(sc) && sc->sp.rearm)
@ -1245,10 +1237,13 @@ static void scan_parse_new_scan_results(struct l_genl_msg *msg,
static bool scan_send_next_cmd(struct scan_context *sc) static bool scan_send_next_cmd(struct scan_context *sc)
{ {
struct scan_request *sr = l_queue_peek_head(sc->requests); struct scan_request *sr = sc->current_sr;
int err; int err;
if (sr && sr->triggered) { if (!sc->triggered)
return false;
if (sr) {
err = scan_request_send_next(sc, sr); err = scan_request_send_next(sc, sr);
if (!err) if (!err)
return true; return true;
@ -1257,20 +1252,19 @@ static bool scan_send_next_cmd(struct scan_context *sc)
if (err < 0 && err == -ENOMSG) if (err < 0 && err == -ENOMSG)
return false; return false;
sr = l_queue_pop_head(sc->requests); scan_request_failed(sc, sr, -EIO);
scan_request_trigger_failed(sr, -EIO);
/* /*
* The request is destroyed, return 'true' to stop further * The request is destroyed, return 'true' to stop further
* processing. * processing.
*/ */
return true; return true;
} else if (sc->sp.triggered) { } else {
struct l_genl_msg *cmd = l_queue_pop_head(sc->sp.cmds); struct l_genl_msg *cmd = l_queue_pop_head(sc->sp.cmds);
if (!cmd) if (!cmd)
return false; return false;
sc->sp.triggered = false; sc->triggered = false;
sc->start_cmd_id = scan_send_start(&cmd, sc->start_cmd_id = scan_send_start(&cmd,
scan_periodic_triggered, sc); scan_periodic_triggered, sc);