diff mbox series

[4/4] Scan 6ghz channels after change to 6ghz-allowed regdom

Message ID 20230602221511.1237936-4-matthewmwang@chromium.org
State Accepted
Headers show
Series [1/4] Use default IEs in wpa_supplicant_trigger_scan | expand

Commit Message

Matthew Wang June 2, 2023, 10:15 p.m. UTC
Drivers will often report regdom changes in the middle of a scan if it
detects during that scan that the regulatory domain has changed. If this
happens and we enter a regdom that supports 6ghz channels when the
previous one didn't (this often happens in 6ghz-capable regdoms for
devices after suspend/resume), immediately trigger a 6ghz-only scan
if we were not able to connect to an AP on a legacy band.

This should significantly improve connection time to 6ghz AP after
regdom has been reset.

Signed-off-by: Matthew Wang <matthewmwang@chromium.org>
---
 wpa_supplicant/bgscan_learn.c           |  2 +-
 wpa_supplicant/bgscan_simple.c          |  2 +-
 wpa_supplicant/dbus/dbus_new_handlers.c |  7 +--
 wpa_supplicant/events.c                 | 65 +++++++++++++++++++++++--
 wpa_supplicant/rrm.c                    |  2 +-
 wpa_supplicant/scan.c                   |  9 ++--
 wpa_supplicant/scan.h                   |  2 +-
 wpa_supplicant/sme.c                    |  2 +-
 wpa_supplicant/wpa_supplicant_i.h       |  4 ++
 9 files changed, 79 insertions(+), 16 deletions(-)
diff mbox series

Patch

diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index 3db425963eb..9830c4aa16e 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -305,7 +305,7 @@  static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx)
 	}
 
 	wpa_printf(MSG_DEBUG, "bgscan learn: Request a background scan");
-	if (wpa_supplicant_trigger_scan(wpa_s, &params, true)) {
+	if (wpa_supplicant_trigger_scan(wpa_s, &params, true, false)) {
 		wpa_printf(MSG_DEBUG, "bgscan learn: Failed to trigger scan");
 		eloop_register_timeout(data->scan_interval, 0,
 				       bgscan_learn_timeout, data, NULL);
diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c
index 1b12726d203..f398b850776 100644
--- a/wpa_supplicant/bgscan_simple.c
+++ b/wpa_supplicant/bgscan_simple.c
@@ -49,7 +49,7 @@  static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx)
 	 */
 
 	wpa_printf(MSG_DEBUG, "bgscan simple: Request a background scan");
-	if (wpa_supplicant_trigger_scan(wpa_s, &params, true)) {
+	if (wpa_supplicant_trigger_scan(wpa_s, &params, true, false)) {
 		wpa_printf(MSG_DEBUG, "bgscan simple: Failed to trigger scan");
 		eloop_register_timeout(data->scan_interval, 0,
 				       bgscan_simple_timeout, data, NULL);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index d7fdea0ed90..0692f0dfab3 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1704,8 +1704,8 @@  DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
 
 			if (params.freqs && params.freqs[0]) {
 				wpa_s->last_scan_req = MANUAL_SCAN_REQ;
-				if (wpa_supplicant_trigger_scan(wpa_s,
-								&params, false)) {
+				if (wpa_supplicant_trigger_scan(wpa_s, &params,
+								false, false)) {
 					reply = wpas_dbus_error_scan_error(
 						message,
 						"Scan request rejected");
@@ -1731,7 +1731,8 @@  DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
 		}
 
 		wpa_s->last_scan_req = MANUAL_SCAN_REQ;
-		if (wpa_supplicant_trigger_scan(wpa_s, &params, !custom_ies)) {
+		if (wpa_supplicant_trigger_scan(wpa_s, &params, !custom_ies,
+						false)) {
 			reply = wpas_dbus_error_scan_error(
 				message, "Scan request rejected");
 		}
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index e7aaa1a1284..74ecd0d7b71 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -57,7 +57,9 @@ 
 
 #ifndef CONFIG_NO_SCAN_PROCESSING
 static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
-					      int new_scan, int own_request);
+					      int new_scan, int own_request,
+					      bool trigger_6ghz_scan,
+					      union wpa_event_data *data);
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 #ifdef CONFIG_OWE
 static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
@@ -2196,6 +2198,7 @@  static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 	struct wpa_scan_results *scan_res = NULL;
 	int ret = 0;
 	int ap = 0;
+	bool trigger_6ghz_scan;
 #ifndef CONFIG_NO_RANDOM_POOL
 	size_t i, num;
 #endif /* CONFIG_NO_RANDOM_POOL */
@@ -2205,6 +2208,10 @@  static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 		ap = 1;
 #endif /* CONFIG_AP */
 
+	trigger_6ghz_scan = wpa_s->crossed_6ghz_dom && wpa_s->last_scan_all_chan;
+	wpa_s->crossed_6ghz_dom = false;
+	wpa_s->last_scan_all_chan = false;
+
 	wpa_supplicant_notify_scanning(wpa_s, 0);
 
 	scan_res = wpa_supplicant_get_scan_results(wpa_s,
@@ -2355,7 +2362,8 @@  static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 	if (wpa_s->supp_pbc_active && !wpas_wps_partner_link_scan_done(wpa_s))
 		return ret;
 
-	return wpas_select_network_from_last_scan(wpa_s, 1, own_request);
+	return wpas_select_network_from_last_scan(wpa_s, 1, own_request,
+						  trigger_6ghz_scan, data);
 
 scan_work_done:
 	wpa_scan_results_free(scan_res);
@@ -2368,8 +2376,20 @@  scan_work_done:
 }
 
 
+/**
+ * Select a network from the last scan.
+ * @wpa_s: pointer to wpa_supplicant data
+ * @new_scan: whether this function was called right after a scan has finished
+ * @own_request: whether the scan was requested by this interface
+ * @trigger_6ghz_scan: whether to trigger a 6ghz-only scan when applicable
+ * @data: scan data from scan that finished if applicable
+ *
+ * See _wpa_supplicant_event_scan_results for return values.
+ */
 static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
-					      int new_scan, int own_request)
+					      int new_scan, int own_request,
+					      bool trigger_6ghz_scan,
+					      union wpa_event_data *data)
 {
 	struct wpa_bss *selected;
 	struct wpa_ssid *ssid = NULL;
@@ -2441,6 +2461,33 @@  static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
 			if (new_scan)
 				wpa_supplicant_rsn_preauth_scan_results(wpa_s);
 		} else if (own_request) {
+			if (wpa_s->support_6ghz && trigger_6ghz_scan && data) {
+				struct wpa_driver_scan_params params;
+				int j;
+
+				wpa_dbg(wpa_s, MSG_INFO, "Triggering 6GHz-only scan");
+				os_memset(&params, 0, sizeof(params));
+				params.non_coloc_6ghz =
+					wpa_s->last_scan_non_coloc_6ghz;
+				for (j = 0;
+				     j < data->scan_info.num_ssids; j++) {
+					params.ssids[j] =
+						data->scan_info.ssids[j];
+				}
+				params.num_ssids = data->scan_info.num_ssids;
+				wpa_add_scan_freqs_list(
+					wpa_s, HOSTAPD_MODE_IEEE80211A, &params,
+					true, !wpa_s->last_scan_non_coloc_6ghz,
+					false);
+				if (!wpa_supplicant_trigger_scan(wpa_s, &params,
+								 true, true)) {
+					os_free(params.freqs);
+					return 1;
+				}
+				wpa_dbg(wpa_s, MSG_INFO, "Failed to trigger 6GHz-only scan");
+				os_free(params.freqs);
+			}
+
 			/*
 			 * No SSID found. If SCAN results are as a result of
 			 * own scan request and not due to a scan request on
@@ -2588,7 +2635,7 @@  int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s)
 		return -1;
 	}
 
-	return wpas_select_network_from_last_scan(wpa_s, 0, 1);
+	return wpas_select_network_from_last_scan(wpa_s, 0, 1, false, NULL);
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 }
 
@@ -2598,7 +2645,7 @@  int wpa_wps_supplicant_fast_associate(struct wpa_supplicant *wpa_s)
 #ifdef CONFIG_NO_SCAN_PROCESSING
 	return -1;
 #else /* CONFIG_NO_SCAN_PROCESSING */
-	return wpas_select_network_from_last_scan(wpa_s, 1, 1);
+	return wpas_select_network_from_last_scan(wpa_s, 1, 1, false, NULL);
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 }
 
@@ -4683,6 +4730,9 @@  void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s,
 		ifs->hw.modes = wpa_drv_get_hw_feature_data(
 			ifs, &ifs->hw.num_modes, &ifs->hw.flags, &dfs_domain);
 
+		bool was_6ghz_enabled = ifs->is_6ghz_enabled;
+		ifs->is_6ghz_enabled = wpas_is_6ghz_supported(ifs, true);
+
 		/* Restart PNO/sched_scan with updated channel list */
 		if (ifs->pno) {
 			wpas_stop_pno(ifs);
@@ -4691,6 +4741,11 @@  void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s,
 			wpa_dbg(ifs, MSG_DEBUG,
 				"Channel list changed - restart sched_scan");
 			wpas_scan_restart_sched_scan(ifs);
+		} else if (ifs->scanning && !was_6ghz_enabled && ifs->is_6ghz_enabled) {
+			/* Look for APs in the 6GHz band */
+			wpa_dbg(ifs, MSG_INFO,
+				"Channel list changed - trigger 6GHz-only scan");
+			ifs->crossed_6ghz_dom = true;
 		}
 	}
 
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index bf6575a0bf3..8e51717ab12 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -1033,7 +1033,7 @@  static void wpas_rrm_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 	}
 	os_get_reltime(&wpa_s->beacon_rep_scan);
 	if (wpa_s->scanning || wpas_p2p_in_progress(wpa_s) ||
-	    wpa_supplicant_trigger_scan(wpa_s, params, true))
+	    wpa_supplicant_trigger_scan(wpa_s, params, true, false))
 		wpas_rrm_refuse_request(wpa_s);
 	params->duration = prev_duration;
 }
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 8287d88af18..5ffe7040b52 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -279,6 +279,7 @@  static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
  * @wpa_s: Pointer to wpa_supplicant data
  * @params: Scan parameters
  * @default_ies: Whether or not to use the default IEs in the probe request.
+ * @next: Whether or not to perform this scan as the next radio work.
  * Note that this will free any existing IEs set in @params, so this shouldn't
  * be set if the IEs have already been set with wpa_supplicant_extra_ies.
  * Otherwise, wpabuf_free will lead to a double-free.
@@ -286,7 +287,7 @@  static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
  */
 int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
 				struct wpa_driver_scan_params *params,
-				bool default_ies)
+				bool default_ies, bool next)
 {
 	struct wpa_driver_scan_params *ctx;
 	struct wpabuf *ies = NULL;
@@ -314,8 +315,10 @@  int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
 		params->extra_ies = NULL;
 		params->extra_ies_len = 0;
 	}
+	wpa_s->last_scan_all_chan = !params->freqs;
+	wpa_s->last_scan_non_coloc_6ghz = params->non_coloc_6ghz;
 	if (!ctx ||
-	    radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
+	    radio_add_work(wpa_s, 0, "scan", next, wpas_trigger_scan_cb, ctx) < 0)
 	{
 		wpa_scan_free_params(ctx);
 		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1");
@@ -1474,7 +1477,7 @@  scan:
 		wpas_p2p_scan_freqs(wpa_s, &params, true);
 #endif /* CONFIG_P2P */
 
-	ret = wpa_supplicant_trigger_scan(wpa_s, scan_params, false);
+	ret = wpa_supplicant_trigger_scan(wpa_s, scan_params, false, false);
 
 	if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs &&
 	    !wpa_s->manual_scan_freqs) {
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 17c7b06a6bd..c4aefab559e 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -46,7 +46,7 @@  void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
 struct wpa_driver_scan_params;
 int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
 				struct wpa_driver_scan_params *params,
-				bool default_ies);
+				bool default_ies, bool next);
 struct wpa_scan_results *
 wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
 				struct scan_info *info, int new_scan);
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 8e72643f1dc..51e6e8f7a19 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -3083,7 +3083,7 @@  static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 	params.low_priority = 1;
 	wpa_printf(MSG_DEBUG, "SME OBSS: Request an OBSS scan");
 
-	if (wpa_supplicant_trigger_scan(wpa_s, &params, true))
+	if (wpa_supplicant_trigger_scan(wpa_s, &params, true, false))
 		wpa_printf(MSG_DEBUG, "SME OBSS: Failed to trigger scan");
 	else
 		wpa_s->sme.sched_obss_scan = 1;
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index efd83c79eb5..011e0aa72a4 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1527,6 +1527,10 @@  struct wpa_supplicant {
 	unsigned int enable_dscp_policy_capa:1;
 	unsigned int connection_dscp:1;
 	unsigned int wait_for_dscp_req:1;
+	bool is_6ghz_enabled;
+	bool crossed_6ghz_dom;
+	bool last_scan_all_chan;
+	bool last_scan_non_coloc_6ghz;
 	bool support_6ghz;
 
 	struct wpa_signal_info last_signal_info;