FROMLIST: wpa_supplicant_select_network: check last scan ssids
This recent patch [1] introduced a redundant scan when selecting a
hidden network that was previously scanned and found. This occurs
because the code only checks for the condition
`(wpa_s->no_suitable_network || wpa_s->last_scan_external)`, which
doesn't cover the case where the last scan successfully found the hidden
SSID.
This patch saves the scanned SSIDs from the last scan and updates the
condition to check if the hidden SSID was included. If the hidden SSID
is not found in `last_scan_ssids`, it triggers a new scan
(`request_new_scan = true`).
[1]
https://w1.fi/cgit/hostap/commit/?id=92374d59d4efea5c8b61ed2ceef141c26bcd7f99
(am from https://patchwork.ozlabs.org/project/hostap/patch/20241007163329.3060529-1-arowa@google.com/)
BUG=b:363899693
TEST=Ran hwsim and wifi_matfunc on Rex/Karis/BE200 + NUC-AP
Checked the net.log for wifi.SimpleConnect.hidden5ht20 and there are no
redundant scans.
Ran checkpatch.pl [PASS]
UPSTREAM-TASK=b:372508941
Change-Id: I7d9b1d99294c2b5fbc4c12516540fb998b006020
Signed-off-by: Arowa Suliman <arowa@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/hostap/+/5896176
Reviewed-by: Sean Paul <sean@poorly.run>
Reviewed-by: Matthew Wang <matthewmwang@chromium.org>
Tested-by: Arowa Suliman <arowa@chromium.org>
Commit-Queue: Arowa Suliman <arowa@chromium.org>
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 38e7bc7..18bbe48 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2724,6 +2724,7 @@
int ap = 0;
bool trigger_6ghz_scan;
bool short_ssid_match_found = false;
+ size_t idx;
#ifndef CONFIG_NO_RANDOM_POOL
size_t i, num;
#endif /* CONFIG_NO_RANDOM_POOL */
@@ -2789,7 +2790,23 @@
}
#endif /* CONFIG_NO_RANDOM_POOL */
- wpa_s->last_scan_external = data && data->scan_info.external_scan;
+ if (data) {
+ wpa_s->last_scan_external = data->scan_info.external_scan;
+ wpa_s->last_scan_num_ssids = data->scan_info.num_ssids;
+ for (idx = 0; idx < wpa_s->last_scan_num_ssids; idx++) {
+ /* Copy the SSID and its length */
+ if (data->scan_info.ssids[idx].ssid_len > SSID_MAX_LEN)
+ continue;
+
+ os_memcpy(wpa_s->last_scan_ssids[idx].ssid,
+ data->scan_info.ssids[idx].ssid,
+ data->scan_info.ssids[idx].ssid_len);
+ wpa_s->last_scan_ssids[idx].ssid[data->scan_info.ssids[idx].ssid_len] =
+ '\0';
+ wpa_s->last_scan_ssids[idx].ssid_len =
+ data->scan_info.ssids[idx].ssid_len;
+ }
+ }
if (update_only) {
ret = 1;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index d40f405..137b70c 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -5048,7 +5048,12 @@
struct wpa_ssid *other_ssid;
int disconnected = 0;
+ int i;
bool request_new_scan = false;
+ bool ssid_scanned = false;
+ const char *current_ssid_name;
+ const char *prev_ssid_name;
+
if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
@@ -5094,11 +5099,36 @@
(ssid->mode == WPAS_MODE_MESH ||
ssid->mode == WPAS_MODE_AP) ? ssid : NULL;
- if (ssid->scan_ssid &&
- (wpa_s->no_suitable_network || wpa_s->last_scan_external)) {
- wpa_printf(MSG_DEBUG,
- "Request a new scan for hidden network");
- request_new_scan = true;
+ if (ssid->scan_ssid) {
+ /* Check if the previous scan included the selected network */
+ if (wpa_s->last_scan_num_ssids > 1) {
+ current_ssid_name = wpa_ssid_txt(ssid->ssid, ssid->ssid_len);
+ ssid_scanned = false;
+ /* Iterate through the previous scan SSIDs */
+ for (i = 0; i < wpa_s->last_scan_num_ssids; i++) {
+ prev_ssid_name = wpa_ssid_txt(
+ wpa_s->last_scan_ssids[i].ssid,
+ wpa_s->last_scan_ssids[i].ssid_len);
+ if (os_strcmp(current_ssid_name, prev_ssid_name) == 0) {
+ ssid_scanned = true;
+ break;
+ }
+ }
+ if (!ssid_scanned) {
+ /* SSID not found in previous scan, request a new scan */
+ request_new_scan = true;
+ }
+ } else {
+ /* No previous scan or wildcard scan, request a new scan */
+ request_new_scan = true;
+ }
+
+ if (request_new_scan) {
+ wpa_printf(MSG_DEBUG, "Request a new scan for hidden network");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "Hidden network was scanned for in last scan");
+ }
} else if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
!ssid->owe_only) {
wpa_printf(MSG_DEBUG,
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 792f949..4ffa169 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -668,6 +668,11 @@
u16 status;
};
+struct last_scan_ssid {
+ u8 ssid[SSID_MAX_LEN + 1];
+ size_t ssid_len;
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
@@ -807,6 +812,9 @@
size_t last_scan_res_size;
struct os_reltime last_scan;
bool last_scan_external;
+ struct last_scan_ssid last_scan_ssids[WPAS_MAX_SCAN_SSIDS];
+ size_t last_scan_num_ssids;
+
const struct wpa_driver_ops *driver;
int interface_removed; /* whether the network interface has been