mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-11-18 10:19:24 +01:00
scan: add hidden networks into the scan requests
To support an auto-connect for the hidden networks and having a limited number of SSIDs that can be appended into a probe request, introduced a concept of a command batch. Now, scan request may consist of a series of commands. The commands in the batch are triggered sequentially. Once we are notified about the results from a previous command, a consequent command in the batch is triggered. The collective results are reported once the batch is complete. On a command failure, the batch processing is canceled and scan request is removed
This commit is contained in:
parent
87108984bc
commit
c33deb7a0a
196
src/scan.c
196
src/scan.c
@ -38,6 +38,8 @@
|
||||
#include "src/wiphy.h"
|
||||
#include "src/netdev.h"
|
||||
#include "src/ie.h"
|
||||
#include "src/common.h"
|
||||
#include "src/network.h"
|
||||
#include "src/scan.h"
|
||||
|
||||
#define SCAN_MAX_INTERVAL 320
|
||||
@ -68,7 +70,7 @@ struct scan_request {
|
||||
scan_destroy_func_t destroy;
|
||||
bool passive:1; /* Active or Passive scan? */
|
||||
bool triggered:1;
|
||||
struct l_genl_msg *start_cmd;
|
||||
struct l_queue *cmds;
|
||||
};
|
||||
|
||||
struct scan_context {
|
||||
@ -106,12 +108,20 @@ static bool scan_request_match(const void *a, const void *b)
|
||||
return sr->id == id;
|
||||
}
|
||||
|
||||
static void scan_cmd_free(void *data)
|
||||
{
|
||||
struct l_genl_msg *cmd = data;
|
||||
|
||||
l_genl_msg_unref(cmd);
|
||||
}
|
||||
|
||||
static void scan_request_free(void *data)
|
||||
{
|
||||
struct scan_request *sr = data;
|
||||
|
||||
l_genl_msg_unref(sr->start_cmd);
|
||||
free(sr);
|
||||
l_queue_destroy(sr->cmds, scan_cmd_free);
|
||||
|
||||
l_free(sr);
|
||||
}
|
||||
|
||||
static struct scan_context *scan_context_new(uint32_t ifindex)
|
||||
@ -274,7 +284,8 @@ static void scan_freq_count(uint32_t freq, void *user_data)
|
||||
*count += 1;
|
||||
}
|
||||
|
||||
static struct l_genl_msg *scan_build_cmd(struct scan_context *sc, bool passive,
|
||||
static struct l_genl_msg *scan_build_cmd(struct scan_context *sc,
|
||||
bool ignore_flush_flag,
|
||||
const struct scan_parameters *params)
|
||||
{
|
||||
struct l_genl_msg *msg;
|
||||
@ -288,21 +299,9 @@ static struct l_genl_msg *scan_build_cmd(struct scan_context *sc, bool passive,
|
||||
msg = l_genl_msg_new_sized(NL80211_CMD_TRIGGER_SCAN,
|
||||
64 + params->extra_ie_size +
|
||||
4 * n_channels);
|
||||
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &sc->ifindex);
|
||||
|
||||
if (!passive) {
|
||||
l_genl_msg_enter_nested(msg, NL80211_ATTR_SCAN_SSIDS);
|
||||
|
||||
if (params->ssid)
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_SSID,
|
||||
strlen(params->ssid),
|
||||
params->ssid);
|
||||
else
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_SSID, 0, NULL);
|
||||
|
||||
l_genl_msg_leave_nested(msg);
|
||||
}
|
||||
|
||||
if (params->extra_ie && params->extra_ie_size)
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_IE,
|
||||
params->extra_ie_size,
|
||||
@ -311,7 +310,7 @@ static struct l_genl_msg *scan_build_cmd(struct scan_context *sc, bool passive,
|
||||
if (params->freqs)
|
||||
scan_build_attr_scan_frequencies(msg, params->freqs);
|
||||
|
||||
if (params->flush)
|
||||
if (params->flush && !ignore_flush_flag)
|
||||
flags |= NL80211_SCAN_FLAG_FLUSH;
|
||||
|
||||
if (flags)
|
||||
@ -320,6 +319,98 @@ static struct l_genl_msg *scan_build_cmd(struct scan_context *sc, bool passive,
|
||||
return msg;
|
||||
}
|
||||
|
||||
static void scan_cmds_add(struct l_queue *cmds, struct scan_context *sc,
|
||||
bool passive,
|
||||
const struct scan_parameters *params)
|
||||
{
|
||||
const struct l_queue *networks;
|
||||
struct l_genl_msg *cmd;
|
||||
uint8_t max_ssids_per_scan;
|
||||
uint8_t num_ssids_can_append;
|
||||
const struct l_queue_entry *entry;
|
||||
|
||||
cmd = scan_build_cmd(sc, false, params);
|
||||
|
||||
if (passive) {
|
||||
/* passive scan */
|
||||
l_queue_push_tail(cmds, cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
l_genl_msg_enter_nested(cmd, NL80211_ATTR_SCAN_SSIDS);
|
||||
|
||||
if (params->ssid) {
|
||||
/* direct probe request scan */
|
||||
l_genl_msg_append_attr(cmd, NL80211_ATTR_SSID,
|
||||
strlen(params->ssid), params->ssid);
|
||||
l_genl_msg_leave_nested(cmd);
|
||||
|
||||
l_queue_push_tail(cmds, cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
num_ssids_can_append = max_ssids_per_scan =
|
||||
wiphy_get_max_num_ssids_per_scan(sc->wiphy);
|
||||
networks = network_info_get_known();
|
||||
|
||||
for (entry = l_queue_get_entries((void *) networks); entry;
|
||||
entry = entry->next) {
|
||||
const struct network_info *network = entry->data;
|
||||
|
||||
if (!network->is_hidden)
|
||||
continue;
|
||||
|
||||
l_genl_msg_append_attr(cmd, NL80211_ATTR_SSID,
|
||||
strlen(network->ssid), network->ssid);
|
||||
num_ssids_can_append--;
|
||||
|
||||
if (!num_ssids_can_append) {
|
||||
l_genl_msg_leave_nested(cmd);
|
||||
l_queue_push_tail(cmds, cmd);
|
||||
|
||||
num_ssids_can_append = max_ssids_per_scan;
|
||||
|
||||
/*
|
||||
* Create a consecutive scan trigger in the batch of
|
||||
* scans. The 'flush' flag is ignored, this allows to
|
||||
* get the results of all scans in the batch after the
|
||||
* last scan is finished.
|
||||
*/
|
||||
cmd = scan_build_cmd(sc, true, params);
|
||||
l_genl_msg_enter_nested(cmd, NL80211_ATTR_SCAN_SSIDS);
|
||||
}
|
||||
}
|
||||
|
||||
l_genl_msg_append_attr(cmd, NL80211_ATTR_SSID, 0, NULL);
|
||||
l_genl_msg_leave_nested(cmd);
|
||||
l_queue_push_tail(cmds, cmd);
|
||||
}
|
||||
|
||||
static bool scan_request_send_first_cmd(struct scan_context *sc,
|
||||
struct scan_request *sr)
|
||||
{
|
||||
struct l_genl_msg *cmd = l_queue_pop_head(sr->cmds);
|
||||
if (!cmd)
|
||||
goto error;
|
||||
|
||||
sc->start_cmd_id = scan_send_start(&cmd, scan_triggered, sc);
|
||||
|
||||
if (sc->start_cmd_id)
|
||||
return true;
|
||||
|
||||
scan_cmd_free(cmd);
|
||||
error:
|
||||
if (sr->trigger)
|
||||
sr->trigger(-EIO, sr->userdata);
|
||||
|
||||
if (sr->destroy)
|
||||
sr->destroy(sr->userdata);
|
||||
|
||||
scan_request_free(sr);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint32_t scan_common(uint32_t ifindex, bool passive,
|
||||
const struct scan_parameters *params,
|
||||
scan_trigger_func_t trigger,
|
||||
@ -342,10 +433,9 @@ static uint32_t scan_common(uint32_t ifindex, bool passive,
|
||||
sr->destroy = destroy;
|
||||
sr->passive = passive;
|
||||
sr->id = ++next_scan_request_id;
|
||||
sr->cmds = l_queue_new();
|
||||
|
||||
sr->start_cmd = scan_build_cmd(sc, passive, params);
|
||||
if (!sr->start_cmd)
|
||||
goto error;
|
||||
scan_cmds_add(sr->cmds, sc, passive, params);
|
||||
|
||||
if (l_queue_length(sc->requests) > 0)
|
||||
goto done;
|
||||
@ -353,13 +443,9 @@ static uint32_t scan_common(uint32_t ifindex, bool passive,
|
||||
if (sc->state != SCAN_STATE_NOT_RUNNING || sc->start_cmd_id)
|
||||
goto done;
|
||||
|
||||
sc->start_cmd_id = scan_send_start(&sr->start_cmd, scan_triggered, sc);
|
||||
if (sc->start_cmd_id > 0)
|
||||
if (scan_request_send_first_cmd(sc, sr))
|
||||
goto done;
|
||||
|
||||
error:
|
||||
scan_request_free(sr);
|
||||
|
||||
return 0;
|
||||
done:
|
||||
l_queue_push_tail(sc->requests, sr);
|
||||
@ -415,8 +501,8 @@ bool scan_cancel(uint32_t ifindex, uint32_t id)
|
||||
if (!sr)
|
||||
return false;
|
||||
|
||||
/* If we already sent the trigger command, cancel the scan */
|
||||
if (sr->id == id && !sr->start_cmd) {
|
||||
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;
|
||||
@ -614,20 +700,10 @@ static bool start_next_scan_request(struct scan_context *sc)
|
||||
while (!l_queue_isempty(sc->requests)) {
|
||||
sr = l_queue_peek_head(sc->requests);
|
||||
|
||||
sc->start_cmd_id = scan_send_start(&sr->start_cmd,
|
||||
scan_triggered, sc);
|
||||
|
||||
if (sc->start_cmd_id)
|
||||
if (scan_request_send_first_cmd(sc, sr))
|
||||
return true;
|
||||
|
||||
if (sr->trigger)
|
||||
sr->trigger(-EIO, sr->userdata);
|
||||
|
||||
if (sr->destroy)
|
||||
sr->destroy(sr->userdata);
|
||||
|
||||
sr = l_queue_pop_head(sc->requests);
|
||||
scan_request_free(sr);
|
||||
l_queue_pop_head(sc->requests);
|
||||
}
|
||||
|
||||
if (sc->sp.retry) {
|
||||
@ -1078,6 +1154,43 @@ static void scan_parse_new_scan_results(struct l_genl_msg *msg,
|
||||
}
|
||||
}
|
||||
|
||||
static bool scan_send_next_cmd(struct scan_context *sc)
|
||||
{
|
||||
struct scan_request *sr = l_queue_peek_head(sc->requests);
|
||||
struct l_genl_msg *cmd;
|
||||
|
||||
if (sr && sr->triggered) {
|
||||
cmd = l_queue_pop_head(sr->cmds);
|
||||
if (!cmd)
|
||||
return false;
|
||||
|
||||
sr->triggered = false;
|
||||
|
||||
sc->start_cmd_id = scan_send_start(&cmd, scan_triggered, sc);
|
||||
if (sc->start_cmd_id)
|
||||
return true;
|
||||
|
||||
scan_cmd_free(cmd);
|
||||
|
||||
if (sr->trigger)
|
||||
sr->trigger(-EIO, sr->userdata);
|
||||
|
||||
if (sr->destroy)
|
||||
sr->destroy(sr->userdata);
|
||||
|
||||
sr = l_queue_pop_head(sc->requests);
|
||||
scan_request_free(sr);
|
||||
|
||||
/*
|
||||
* The request is destroyed, return 'true' to stop further
|
||||
* processing.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void scan_notify(struct l_genl_msg *msg, void *user_data)
|
||||
{
|
||||
struct l_genl_attr attr;
|
||||
@ -1146,6 +1259,9 @@ static void scan_notify(struct l_genl_msg *msg, void *user_data)
|
||||
struct l_genl_msg *scan_msg;
|
||||
struct scan_results *results;
|
||||
|
||||
if (scan_send_next_cmd(sc))
|
||||
return;
|
||||
|
||||
results = l_new(struct scan_results, 1);
|
||||
results->wiphy = attr_wiphy;
|
||||
results->ifindex = attr_ifindex;
|
||||
|
Loading…
Reference in New Issue
Block a user