]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Scan 6 GHz channels after change to 6 GHz-allowed regdom
authorMatthew Wang <matthewmwang@chromium.org>
Fri, 2 Jun 2023 22:15:11 +0000 (15:15 -0700)
committerJouni Malinen <j@w1.fi>
Tue, 31 Oct 2023 10:01:26 +0000 (12:01 +0200)
Drivers will often report regdom changes in the middle of a scan if they
detect during that scan that the regulatory domain has changed. If this
happens and we enter a regdom that supports 6 GHz channels when the
previous one didn't (this often happens in 6 GHz-capable regdoms for
devices after suspend/resume), immediately trigger a 6 GHz-only scan if
we were not able to connect to an AP on a legacy band.

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

Signed-off-by: Matthew Wang <matthewmwang@chromium.org>
wpa_supplicant/bgscan_learn.c
wpa_supplicant/bgscan_simple.c
wpa_supplicant/dbus/dbus_new_handlers.c
wpa_supplicant/events.c
wpa_supplicant/rrm.c
wpa_supplicant/scan.c
wpa_supplicant/scan.h
wpa_supplicant/sme.c
wpa_supplicant/wpa_supplicant_i.h

index 3db425963eb025d0b45e2a1b04018942a7509248..9830c4aa16e1c3ed1ac6a3f782a90eab36e4d04a 100644 (file)
@@ -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);
index 1b12726d203373caf8763cc4f77b654bd1f514a0..f398b8507760a5044493eb5f321c647f61dc4b5c 100644 (file)
@@ -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);
index 6651267110b6f5612c3441d696975845bf3c1b4d..cd1a59a11844fe11d299565846442dc933b300f6 100644 (file)
@@ -1727,7 +1727,7 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
                                wpa_s->last_scan_req = MANUAL_SCAN_REQ;
                                if (wpa_supplicant_trigger_scan(wpa_s,
                                                                &params,
-                                                               false)) {
+                                                               false, false)) {
                                        reply = wpas_dbus_error_scan_error(
                                                message,
                                                "Scan request rejected");
@@ -1753,7 +1753,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");
                }
index dec98f867854c18171a6a0637a940fdf36cfe9cf..fbafe4bc387c80ca5337123a3dec9eea778dbdc9 100644 (file)
@@ -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,
@@ -2310,6 +2312,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 */
@@ -2319,6 +2322,11 @@ 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,
@@ -2472,7 +2480,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);
@@ -2485,8 +2494,44 @@ scan_work_done:
 }
 
 
+static int wpas_trigger_6ghz_scan(struct wpa_supplicant *wpa_s,
+                                 union wpa_event_data *data)
+{
+       struct wpa_driver_scan_params params;
+       unsigned 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);
+       return 0;
+}
+
+
+/**
+ * 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;
@@ -2558,6 +2603,10 @@ 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 &&
+                           wpas_trigger_6ghz_scan(wpa_s, data) < 0)
+                               return 1;
+
                        /*
                         * No SSID found. If SCAN results are as a result of
                         * own scan request and not due to a scan request on
@@ -2705,7 +2754,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 */
 }
 
@@ -2715,7 +2764,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 */
 }
 
@@ -4796,12 +4845,17 @@ void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s,
 
        dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
                         radio_list) {
+               bool was_6ghz_enabled;
+
                wpa_printf(MSG_DEBUG, "%s: Updating hw mode",
                           ifs->ifname);
                free_hw_features(ifs);
                ifs->hw.modes = wpa_drv_get_hw_feature_data(
                        ifs, &ifs->hw.num_modes, &ifs->hw.flags, &dfs_domain);
 
+               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);
@@ -4810,6 +4864,12 @@ 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 6 GHz band */
+                       wpa_dbg(ifs, MSG_INFO,
+                               "Channel list changed - trigger 6 GHz-only scan");
+                       ifs->crossed_6ghz_dom = true;
                }
        }
 
index bf6575a0bf3919d20e9e9a490342a9e1b7c84647..8e51717ab12546cfd473e5034a5a642452ff92bc 100644 (file)
@@ -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;
 }
index b05f3d0a06dc31b37a18f51f9d3ddce8b32cc010..ef5e3e6967f5b866730ceccf4426de5db7b4e5e9 100644 (file)
@@ -285,11 +285,12 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
  * 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.
+ * @next: Whether or not to perform this scan as the next radio work
  * Returns: 0 on success, -1 on failure
  */
 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;
@@ -317,9 +318,11 @@ 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");
                return -1;
@@ -1537,7 +1540,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) {
index 4a21b42210c4d61cae4f7d9ea5cec72b94c8115e..b5ed7842f6a459ee54292f659c68f38006fb3cf6 100644 (file)
@@ -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);
index 9f12a7b3c47c66c42f6796aadac0a9e0d373e214..578e1828c4b9bfd34760ccd7f64f6126c9bf50ed 100644 (file)
@@ -3093,7 +3093,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;
index 89f078ca0a8612b9497d25bb4e96fbc12c024c22..8787ba61f5238ae03e4d526acb65d63358ff249a 100644 (file)
@@ -1566,6 +1566,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;