diff mbox series

[v2] wpa_supplicant_select_network: check last scan ssids

Message ID 20241105053622.498097-1-arowa@google.com
State New
Headers show
Series [v2] wpa_supplicant_select_network: check last scan ssids | expand

Commit Message

Arowa Suliman Nov. 5, 2024, 5:36 a.m. UTC
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`, the code checks if
the SSID was found in earlier scan results. If not, it triggers a new
scan. If the SSID is found, a new scan is avoided, resulting in faster
connection times.

[1]
https://w1.fi/cgit/hostap/commit/?id=92374d59d4efea5c8b61ed2ceef141c26bcd7f99

Signed-off-by: Arowa Suliman <arowa@chromium.org>
---
 wpa_supplicant/events.c           | 19 +++++++++-
 wpa_supplicant/wpa_supplicant.c   | 60 ++++++++++++++++++++++++++++---
 wpa_supplicant/wpa_supplicant_i.h |  8 +++++
 3 files changed, 81 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 7947b6f08..0557926b4 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2490,6 +2490,7 @@  static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 	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 */
@@ -2555,7 +2556,23 @@  static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 	}
 #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 031268a41..b5420498c 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -5104,6 +5104,30 @@  void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
 	}
 }
 
+/**
+ * Checks whether the ssid was discovered in the last scan.
+ * @wpa_s: wpa_supplicant structure for a network interface.
+ * @ssid: wpa_ssid structure for a configured network.
+ * Returns: true if ssid found, false otherwise.
+ */
+static inline bool check_ssid_last_scan(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid)
+{
+	int i;
+
+	if (wpa_s->last_scan_res != NULL &&
+		   wpa_s->last_scan_res_used != 0) {
+		for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+			if (os_memcmp(wpa_s->last_scan_res[i]->ssid,
+				   ssid->ssid, ssid->ssid_len) == 0) {
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+
 
 /**
  * wpa_supplicant_select_network - Attempt association with a network
@@ -5116,7 +5140,10 @@  void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
 
 	struct wpa_ssid *other_ssid;
 	int disconnected = 0;
+	int i;
 	bool request_new_scan = false;
+	bool ssid_scanned = false;
+
 
 	if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
 		if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
@@ -5162,11 +5189,34 @@  void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
 			(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) {
+				ssid_scanned = false;
+				/* Iterate through the previous scan SSIDs */
+				for (i = 0; i < wpa_s->last_scan_num_ssids; i++) {
+					if (os_memcmp(wpa_s->last_scan_ssids[i].ssid,
+						   ssid->ssid, ssid->ssid_len) == 0) {
+						ssid_scanned = true;
+						break;
+					}
+				}
+			}
+
+			if (!ssid_scanned) {
+				/* Check if ssid is found in previous scan */
+				if (check_ssid_last_scan(wpa_s, ssid)) {
+					wpa_printf(MSG_DEBUG,
+						   "Hidden network was found in last scan results");
+				} else {
+					request_new_scan = true;
+					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 1f41c149e..b9f7e398b 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -668,6 +668,11 @@  struct ml_sta_link_info {
 	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
@@ -806,6 +811,9 @@  struct wpa_supplicant {
 	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