feature request: scan_timeout instead of hardwired 10 second timeout in driver_nl80211_scan.c

Message ID CAEo+FfKX8T9f0ppbMOLMfTk20rK2AASXL8fz=QHRUNgM3Vtuaw@mail.gmail.com
State New
Headers show
Series
  • feature request: scan_timeout instead of hardwired 10 second timeout in driver_nl80211_scan.c
Related show

Commit Message

David Poole Dec. 14, 2017, 4:02 p.m.
Hello.

I ran into a problem when doing scans using a Alfa AWUS051NHv.2 on
recent Fedora and Ubuntu. I had a couple networks up in the UNII-3
bands that I couldn't find in a wpa_supplicant scan when running on
Fedora. Running same version (built from git) on Ubuntu, I could find
the networks.

Fedora 26.
Linux zaphod.local 4.13.16-202.fc26.x86_64 #1 SMP Thu Nov 30 15:39:32
UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

Ubuntu 16.04
Linux dahlcorporation 4.4.0-103-generic #126-Ubuntu SMP Mon Dec 4
16:23:28 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

Turned out the problem was the hardwired timeout = 10 in
src/drivers/driver_nl80211_scan.c

On Fedora, the kernel nl80211 would obey the "Abort scan" request
(sent a NL80211_CMD_SCAN_ABORTED).  On Ubuntu, the abort would fail
"Abort scan failed: ret=-95 (Operation not supported)". In failing to
abort, the scan appeared to finish and I could find my devices.

Running "time iw dev $device scan" showed a scan with this hardware
would take ~15 seconds. I bumped the timeout to 30, recompiled, and my
scans worked fine (I could find my devices in UNII-3 bands).

I have a patch (below) to set scan_timeout as a global config.  (Not
sure if I should attach or paste into the email.)

I'll test some more with my Intel 8260 and a few other devices.

         "preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
@@ -581,7 +581,7 @@ static char ** wpa_cli_complete_get(const char
*str, int pos)
         "wps_nfc_dev_pw_id", "ext_password_backend",
         "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
         "dtim_period", "beacon_int", "ignore_old_scan_res",
-        "scan_cur_freq", "sched_scan_interval",
+        "scan_cur_freq", "scan_timeout", "sched_scan_interval",
         "sched_scan_start_delay",
         "tdls_external_control", "osu_dir", "wowlan_triggers",
         "p2p_search_delay", "mac_addr", "rand_addr_lifetime",

Patch

diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index a6307e3b1..41ebd9a83 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -567,6 +567,9 @@  struct wpa_driver_scan_params {
      */
     s8 relative_adjust_rssi;

+    /* number of seconds to wait for a scan completed event before giving up */
+    unsigned int scan_timeout;
+
     /*
      * NOTE: Whenever adding new parameters here, please make sure
      * wpa_scan_clone_params() and wpa_scan_free_params() get updated with
diff --git a/src/drivers/driver_nl80211_scan.c
b/src/drivers/driver_nl80211_scan.c
index 984485b00..2bdb88343 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -388,6 +388,11 @@  int wpa_driver_nl80211_scan(struct i802_bss *bss,
          */
         timeout = 30;
     }
+    /* if we're passed a timeout in params, use that. */
+    if (params->scan_timeout) {
+        timeout = params->scan_timeout;
+    }
+
     wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
            "seconds", ret, timeout);
     eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index a0d480ed9..073a86777 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -4606,6 +4606,7 @@  static const struct global_parse_data global_fields[] = {
     { INT_RANGE(ignore_old_scan_res, 0, 1), 0 },
     { FUNC(freq_list), 0 },
     { INT(scan_cur_freq), 0 },
+    { INT(scan_timeout), 0 },
     { INT(sched_scan_interval), 0 },
     { INT(sched_scan_start_delay), 0 },
     { INT(tdls_external_control), 0},
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 07b67e6b4..43dea8162 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -859,6 +859,14 @@  struct wpa_config {
     int scan_cur_freq;

     /**
+     * scan_timeout - value in seconds to wait for a scan survey to finish.
+     *
+     * Not all drivers generate "scan completed" wireless event, so try to
+     * read results after a timeout.
+     */
+    unsigned int scan_timeout;
+
+    /**
      * changed_parameters - Bitmap of changed parameters since last update
      */
     unsigned int changed_parameters;
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 6b7abe2bb..26edf5ae7 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1372,6 +1372,9 @@  static void wpa_config_write_global(FILE *f,
struct wpa_config *config)
     if (config->scan_cur_freq != DEFAULT_SCAN_CUR_FREQ)
         fprintf(f, "scan_cur_freq=%d\n", config->scan_cur_freq);

+    if (config->scan_timeout)
+        fprintf(f, "scan_timeout=%d\n", config->scan_timeout);
+
     if (config->sched_scan_interval)
         fprintf(f, "sched_scan_interval=%u\n",
             config->sched_scan_interval);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 104b25898..e7200f034 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -1059,6 +1059,14 @@  ssid_list_set:
         int_array_concat(&params.freqs, wpa_s->conf->freq_list);
     }

+    /* if user specified a scan timeout, add that */
+    if (wpa_s->conf->scan_timeout) {
+        wpa_dbg(wpa_s, MSG_DEBUG,
+            "timeout the scan after %d seconds if driver doesn't send event",
+            wpa_s->conf->scan_timeout);
+        params.scan_timeout = wpa_s->conf->scan_timeout;
+    }
+
     /* Use current associated channel? */
     if (wpa_s->conf->scan_cur_freq && !params.freqs) {
         unsigned int num = wpa_s->num_multichan_concurrent;
@@ -1485,6 +1493,14 @@  int wpa_supplicant_req_sched_scan(struct
wpa_supplicant *wpa_s)
             "Optimize scan based on conf->freq_list");
         int_array_concat(&params.freqs, wpa_s->conf->freq_list);
     }
+    /* if user specified a scan timeout, add that */
+    if (wpa_s->conf->scan_timeout) {
+        wpa_dbg(wpa_s, MSG_DEBUG,
+            "timeout the scan after %d seconds if driver doesn't send event",
+            wpa_s->conf->scan_timeout);
+        params.scan_timeout = wpa_s->conf->scan_timeout;
+    }
+

     scan_params = &params;

@@ -2444,6 +2460,7 @@  wpa_scan_clone_params(const struct
wpa_driver_scan_params *src)
     params->relative_rssi = src->relative_rssi;
     params->relative_adjust_band = src->relative_adjust_band;
     params->relative_adjust_rssi = src->relative_adjust_rssi;
+    params->scan_timeout = src->scan_timeout;
     return params;

 failed:
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 6b345af11..52f1d8e30 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -486,7 +486,7 @@  static char ** wpa_cli_complete_set(const char
*str, int pos)
         "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
         "sae_groups", "dtim_period", "beacon_int",
         "ap_vendor_elements", "ignore_old_scan_res", "freq_list",
-        "scan_cur_freq", "sched_scan_interval",
+        "scan_cur_freq", "scan_timeout", "sched_scan_interval",
         "tdls_external_control", "osu_dir", "wowlan_triggers",
         "p2p_search_delay", "mac_addr", "rand_addr_lifetime",