diff mbox

[2/7] wpa_supplicant: Support minimum interval between scan attempts.

Message ID 1341593561-14090-2-git-send-email-greearb@candelatech.com
State Superseded
Headers show

Commit Message

Ben Greear July 6, 2012, 4:52 p.m. UTC
From: Ben Greear <greearb@candelatech.com>

When running lots of vifs, they can all end up wanting to
scan right after the other.  This leaves too little time for
useful work to happen.  Allow users to configure a minimum
timer interval (in seconds) between scans.  Default is zero,
which is current behaviour.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 wpa_supplicant/config.c           |    2 ++
 wpa_supplicant/config.h           |    4 ++++
 wpa_supplicant/events.c           |   14 ++++++++++++++
 wpa_supplicant/scan.c             |   20 +++++++++++++++++++-
 wpa_supplicant/scan.h             |    1 +
 wpa_supplicant/wpa_supplicant_i.h |    1 +
 6 files changed, 41 insertions(+), 1 deletions(-)

Comments

Jouni Malinen July 7, 2012, 3:13 p.m. UTC | #1
On Fri, Jul 06, 2012 at 09:52:36AM -0700, greearb@candelatech.com wrote:
> When running lots of vifs, they can all end up wanting to
> scan right after the other.  This leaves too little time for
> useful work to happen.  Allow users to configure a minimum
> timer interval (in seconds) between scans.  Default is zero,
> which is current behaviour.

Is this still needed after the autoscan functionality was added?
Wouldn't something like autoscan=periodic:30 be usable with more or less
the same end result?
Ben Greear July 7, 2012, 3:42 p.m. UTC | #2
On 07/07/2012 08:13 AM, Jouni Malinen wrote:
> On Fri, Jul 06, 2012 at 09:52:36AM -0700, greearb@candelatech.com wrote:
>> When running lots of vifs, they can all end up wanting to
>> scan right after the other.  This leaves too little time for
>> useful work to happen.  Allow users to configure a minimum
>> timer interval (in seconds) between scans.  Default is zero,
>> which is current behaviour.
>
> Is this still needed after the autoscan functionality was added?
> Wouldn't something like autoscan=periodic:30 be usable with more or less
> the same end result?

The problem I saw is that each interface wants to scan...so if you
have 100 virtual stations configured for an AP that doesn't exist,
they are all constantly scanning trying to associate.

Even if the AP exists, if one is trying to associate and the
other 99 trying to scan, association can often time out.

The scan fanout helps, and the scan-on-channel logic in the
kernel helps..but I still found this option useful for
wpa_supplicant as well.

I haven't looked at the autoscan logic, but I think it wouldn't
help the scan-on-startup logic that stations use...

Thanks,
Ben
diff mbox

Patch

diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index a68b31e..792dc42 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2502,6 +2502,7 @@  struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
 	config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
 	config->max_num_sta = DEFAULT_MAX_NUM_STA;
 	config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
+	config->min_scan_gap = DEFAULT_MIN_SCAN_GAP;
 
 	if (ctrl_interface)
 		config->ctrl_interface = os_strdup(ctrl_interface);
@@ -2873,6 +2874,7 @@  static const struct global_parse_data global_fields[] = {
 	{ INT(dot11RSNAConfigPMKLifetime), 0 },
 	{ INT(dot11RSNAConfigPMKReauthThreshold), 0 },
 	{ INT(dot11RSNAConfigSATimeout), 0 },
+	{ INT(min_scan_gap), 0 },
 #ifndef CONFIG_NO_CONFIG_WRITE
 	{ INT(update_config), 0 },
 #endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 46c4da2..1384add 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -23,6 +23,7 @@ 
 #define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
 #define DEFAULT_MAX_NUM_STA 128
 #define DEFAULT_ACCESS_NETWORK_TYPE 15
+#define DEFAULT_MIN_SCAN_GAP 0
 
 #include "config_ssid.h"
 #include "wps/wps.h"
@@ -589,6 +590,9 @@  struct wpa_config {
 	 */
 	int disassoc_low_ack;
 
+	/* Minimum interval between scan requests, in seconds */
+	int min_scan_gap;
+
 	/**
 	 * interworking - Whether Interworking (IEEE 802.11u) is enabled
 	 */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 59b103e..c666ea2 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1010,6 +1010,7 @@  static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 	struct wpa_ssid *ssid = NULL;
 	struct wpa_scan_results *scan_res;
 	int ap = 0;
+	struct os_time t;
 
 #ifdef CONFIG_AP
 	if (wpa_s->ap_iface)
@@ -1081,6 +1082,19 @@  static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 		return 0;
 	}
 
+	os_get_time(&t);
+	wpa_s->last_scan_rx_sec = t.sec;
+	/* Now, *if* we have (another) scan scheduled, and a min-scan-gap
+	 * configured, make sure it happens after the minimum time.  Since
+	 * one STA's scan results can be propagated to other STA on the
+	 * same radio, this is actually a common case.
+	 */
+	if (wpa_s->conf->min_scan_gap &&
+	    eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL)) {
+		/* Min gap will be applied as needed */
+		wpa_supplicant_req_scan(wpa_s, 1, 0);
+	}
+
 	wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available");
 	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
 	wpas_notify_scan_results(wpa_s);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 10a4693..d8b8ea5 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -427,7 +427,7 @@  wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s,
 }
 
 
-static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
+void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 	struct wpa_ssid *ssid;
@@ -720,6 +720,24 @@  void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
 		}
 	}
 
+	/* With lots of VIFS, we can end up trying to scan very often.
+	 * This can cause us to not be able to associate due to missing
+	 * EAPOL key messages and such.  So, allow a minimum time between
+	 * scans.
+	 */
+	if (wpa_s->conf->min_scan_gap) {
+		int mingap;
+		struct os_time t;
+		os_get_time(&t);
+
+		mingap = wpa_s->conf->min_scan_gap
+			- (t.sec - wpa_s->last_scan_rx_sec);
+		if (mingap > wpa_s->conf->min_scan_gap)
+			mingap = wpa_s->conf->min_scan_gap;
+		if (mingap > sec)
+			sec = mingap;
+	}
+
 	wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
 		sec, usec);
 	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index b0ddf97..60248f3 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -10,6 +10,7 @@ 
 #define SCAN_H
 
 int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx);
 void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
 int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
 				      int sec, int usec);
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index b608f29..f4afaaf 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -298,6 +298,7 @@  struct wpa_supplicant {
 	int key_mgmt;
 	int wpa_proto;
 	int mgmt_group_cipher;
+	int last_scan_rx_sec;
 
 	void *drv_priv; /* private data used by driver_ops */
 	void *global_drv_priv;