From e8c87c8b42a88e3d9bd23ed8458665f8f2fff5e3 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Mon, 15 Mar 2021 10:29:28 -0700 Subject: [PATCH] scan: add scan_get_firmware_scan Adds support for getting firmware scan results from the kernel. This is intended to be used after the firmware roamed automatically and the scan result is require for handshake initialization. The scan 'request' is competely separate from the normal scan queue, though scan_results, scan_request, and the scan_context are all used for consistency and code reuse. --- src/scan.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/scan.h | 3 +++ 2 files changed, 77 insertions(+) diff --git a/src/scan.c b/src/scan.c index ce8bbf4a..a37e1714 100644 --- a/src/scan.c +++ b/src/scan.c @@ -100,6 +100,11 @@ struct scan_context { unsigned int start_cmd_id; /* Non-zero if GET_SCAN is still running */ unsigned int get_scan_cmd_id; + /* + * Special request used for getting scan results after the firmware + * roamed automatically. + */ + unsigned int get_fw_scan_cmd_id; /* * Whether the top request in the queue has triggered the current * scan. May be set and cleared multiple times during a single @@ -208,6 +213,9 @@ static void scan_context_free(struct scan_context *sc) if (sc->get_scan_cmd_id && nl80211) l_genl_family_cancel(nl80211, sc->get_scan_cmd_id); + if (sc->get_fw_scan_cmd_id && nl80211) + l_genl_family_cancel(nl80211, sc->get_fw_scan_cmd_id); + l_free(sc); } @@ -1809,6 +1817,72 @@ static void scan_notify(struct l_genl_msg *msg, void *user_data) } } +static void get_fw_scan_done(void *userdata) +{ + struct scan_results *results = userdata; + struct scan_request *sr = results->sr; + struct scan_context *sc = results->sc; + int err = l_queue_length(results->bss_list) == 0 ? -ENOENT : 0; + bool new_owner = false; + + sc->get_fw_scan_cmd_id = 0; + + if (sr->callback) + new_owner = sr->callback(err, results->bss_list, NULL, + sr->userdata); + + if (!new_owner) + l_queue_destroy(results->bss_list, + (l_queue_destroy_func_t) scan_bss_free); + + if (sr->destroy) + sr->destroy(sr->userdata); + + l_free(sr); + l_free(results); +} + +bool scan_get_firmware_scan(uint64_t wdev_id, scan_notify_func_t notify, + void *userdata, scan_destroy_func_t destroy) +{ + struct l_genl_msg *scan_msg; + struct scan_results *results; + struct scan_request *sr; + struct scan_context *sc = l_queue_find(scan_contexts, + scan_context_match, &wdev_id); + + if (!sc) + return false; + + sr = l_new(struct scan_request, 1); + sr->callback = notify; + sr->destroy = destroy; + sr->userdata = userdata; + + results = l_new(struct scan_results, 1); + results->sc = sc; + results->time_stamp = l_time_now(); + results->bss_list = l_queue_new(); + results->sr = sr; + + scan_msg = l_genl_msg_new_sized(NL80211_CMD_GET_SCAN, 8); + l_genl_msg_append_attr(scan_msg, NL80211_ATTR_WDEV, 8, &sc->wdev_id); + + sc->get_fw_scan_cmd_id = l_genl_family_dump(nl80211, scan_msg, + get_scan_callback, + results, + get_fw_scan_done); + if (!sc->get_fw_scan_cmd_id) { + l_queue_destroy(results->bss_list, + (l_queue_destroy_func_t) scan_bss_free); + l_free(results); + l_free(sr); + return false; + } + + return true; +} + uint8_t scan_freq_to_channel(uint32_t freq, enum scan_band *out_band) { uint32_t channel = 0; diff --git a/src/scan.h b/src/scan.h index 355b4b5a..498e8b2a 100644 --- a/src/scan.h +++ b/src/scan.h @@ -151,6 +151,9 @@ bool scan_periodic_stop(uint64_t wdev_id); uint64_t scan_get_triggered_time(uint64_t wdev_id, uint32_t id); +bool scan_get_firmware_scan(uint64_t wdev_id, scan_notify_func_t notify, + void *userdata, scan_destroy_func_t destroy); + void scan_bss_free(struct scan_bss *bss); int scan_bss_rank_compare(const void *a, const void *b, void *user);