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.
This commit is contained in:
James Prestwood 2021-03-15 10:29:28 -07:00 committed by Denis Kenzior
parent 0c0d9e5696
commit e8c87c8b42
2 changed files with 77 additions and 0 deletions

View File

@ -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;

View File

@ -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);