]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Reset external_scan_running on interface deletion
authorDavid Su <dysu@google.com>
Tue, 26 Jan 2021 22:26:13 +0000 (14:26 -0800)
committerJouni Malinen <j@w1.fi>
Tue, 2 Feb 2021 21:48:14 +0000 (23:48 +0200)
Currently, the external_scan_running flag is not reset when an interface
is removed. Thus, if a connection attempt is made on another iface, it
will fail due to wpa_supplicant incorrectly assuming the radio is still
busy due to the ongoing scan.

To fix this, convert external_scan_running to a pointer to the interface
that started the scan. If this interface is removed, also reset the
pointer to NULL so that other operations may continue on this radio.

Test:
  1. Start scan on wlan0
  2. Remove wlan0
  3. Can connect to a network on wlan1

Signed-off-by: David Su <dysu@google.com>
wpa_supplicant/events.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index 48757dbd1450b747c637640001b23f94cbdeb2af..199829bcf2a4d2671d67c90a4f41357932917c1e 100644 (file)
@@ -4792,7 +4792,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                        }
                } else {
                        wpa_dbg(wpa_s, MSG_DEBUG, "External program started a scan");
-                       wpa_s->radio->external_scan_running = 1;
+                       wpa_s->radio->external_scan_req_interface = wpa_s;
                        wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED);
                }
                break;
@@ -4800,7 +4800,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
                        wpa_s->scan_res_handler = NULL;
                        wpa_s->own_scan_running = 0;
-                       wpa_s->radio->external_scan_running = 0;
+                       wpa_s->radio->external_scan_req_interface = NULL;
                        wpa_s->last_scan_req = NORMAL_SCAN_REQ;
                        break;
                }
@@ -4820,7 +4820,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                if (!(data && data->scan_info.external_scan))
                        wpa_s->own_scan_running = 0;
                if (data && data->scan_info.nl_scan_event)
-                       wpa_s->radio->external_scan_running = 0;
+                       wpa_s->radio->external_scan_req_interface = NULL;
                radio_work_check_next(wpa_s);
                break;
 #endif /* CONFIG_NO_SCAN_PROCESSING */
index a1eaaf1284866f182b00e811731e3171ec257be2..62a3ea691a9b8750fd9bffe9b79e0d0079ee2ae2 100644 (file)
@@ -247,7 +247,7 @@ static void wpas_p2p_scan_res_handled(struct wpa_supplicant *wpa_s)
        unsigned int delay = wpas_p2p_search_delay(wpa_s);
 
        /* In case of concurrent P2P and external scans, delay P2P search. */
-       if (wpa_s->radio->external_scan_running) {
+       if (external_scan_running(wpa_s->radio)) {
                delay = wpa_s->conf->p2p_search_delay;
                wpa_printf(MSG_DEBUG,
                           "P2P: Delay next P2P search by %d ms to let externally triggered scan complete",
index a7e74344c2fd835f18183ef09743dfab2bb05f99..281fe11bee42348d9d84bfbe9cda1367c0f464e9 100644 (file)
@@ -5868,7 +5868,7 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
                dl_list_for_each(tmp, &radio->work, struct wpa_radio_work,
                                 list) {
                        if (os_strcmp(tmp->type, "scan") == 0 &&
-                           radio->external_scan_running &&
+                           external_scan_running(radio) &&
                            (((struct wpa_driver_scan_params *)
                              tmp->ctx)->only_new_results ||
                             tmp->wpa_s->clear_driver_scan_cache))
@@ -5924,7 +5924,7 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
                         * rejected by kernel.
                         */
                        if (os_strcmp(tmp->type, "scan") == 0 &&
-                           radio->external_scan_running &&
+                           external_scan_running(radio) &&
                            (((struct wpa_driver_scan_params *)
                              tmp->ctx)->only_new_results ||
                             tmp->wpa_s->clear_driver_scan_cache))
@@ -5963,7 +5963,7 @@ static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
                if (work->started)
                        return; /* already started and still in progress */
 
-               if (wpa_s && wpa_s->radio->external_scan_running) {
+               if (wpa_s && external_scan_running(wpa_s->radio)) {
                        wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
                        return;
                }
@@ -6059,6 +6059,10 @@ static void radio_remove_interface(struct wpa_supplicant *wpa_s)
                   wpa_s->ifname, radio->name);
        dl_list_del(&wpa_s->radio_list);
        radio_remove_works(wpa_s, NULL, 0);
+       /* If the interface that triggered the external scan was removed, the
+        * external scan is no longer running. */
+       if (wpa_s == radio->external_scan_req_interface)
+               radio->external_scan_req_interface = NULL;
        wpa_s->radio = NULL;
        if (!dl_list_empty(&radio->ifaces))
                return; /* Interfaces remain for this radio */
index 0ce7447fe72854c58648a6ebae5b8a1086ca50a8..f70f3c853700a42f454d8833142409baa4c8f14c 100644 (file)
@@ -332,12 +332,23 @@ struct wpa_global {
 struct wpa_radio {
        char name[16]; /* from driver_ops get_radio_name() or empty if not
                        * available */
-       unsigned int external_scan_running:1;
+       /** NULL if no external scan running. */
+       struct wpa_supplicant *external_scan_req_interface;
        unsigned int num_active_works;
        struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */
        struct dl_list work; /* struct wpa_radio_work::list entries */
 };
 
+/**
+ * Checks whether an external scan is running on a given radio.
+ * @radio: Pointer to radio struct
+ * Returns: true if an external scan is running, false otherwise.
+ */
+static inline bool external_scan_running(struct wpa_radio *radio)
+{
+       return radio && radio->external_scan_req_interface;
+}
+
 #define MAX_ACTIVE_WORKS 2