Patchwork [01/15] wpa_supplicant: Support minimum interval between scan attempts.

login
register
mail settings
Submitter Ben Greear
Date March 6, 2014, 12:19 a.m.
Message ID <1394065200-20377-1-git-send-email-greearb@candelatech.com>
Download mbox | patch
Permalink /patch/327237/
State New
Headers show

Comments

Ben Greear - March 6, 2014, 12:19 a.m.
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             |   26 +++++++++++++++++++++++---
 wpa_supplicant/scan.h             |    1 +
 wpa_supplicant/wpa_supplicant_i.h |    1 +
 6 files changed, 45 insertions(+), 3 deletions(-)

Patch

diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 23aab4b..9a17b22 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2982,6 +2982,7 @@  struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
 	config->wmm_ac_params[1] = ac_bk;
 	config->wmm_ac_params[2] = ac_vi;
 	config->wmm_ac_params[3] = ac_vo;
+	config->min_scan_gap = DEFAULT_MIN_SCAN_GAP;
 
 	if (ctrl_interface)
 		config->ctrl_interface = os_strdup(ctrl_interface);
@@ -3518,6 +3519,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 de43970..b5f23ac 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -25,6 +25,7 @@ 
 #define DEFAULT_MAX_NUM_STA 128
 #define DEFAULT_ACCESS_NETWORK_TYPE 15
 #define DEFAULT_SCAN_CUR_FREQ 0
+#define DEFAULT_MIN_SCAN_GAP 0
 
 #include "config_ssid.h"
 #include "wps/wps.h"
@@ -775,6 +776,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 059ffcb..ff857ab 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1259,6 +1259,7 @@  static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 #ifndef CONFIG_NO_RANDOM_POOL
 	size_t i, num;
 #endif /* CONFIG_NO_RANDOM_POOL */
+	struct os_reltime t;
 
 #ifdef CONFIG_AP
 	if (wpa_s->ap_iface)
@@ -1320,6 +1321,19 @@  static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 		goto scan_work_done;
 	}
 
+	os_get_reltime(&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 (own=%u ext=%u)",
 		wpa_s->own_scan_running, wpa_s->external_scan_running);
 	if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index f7eb537..a2396c1 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -522,7 +522,7 @@  static void wpa_setband_scan_freqs(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;
@@ -905,8 +905,28 @@  void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec)
  */
 void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
 {
-	int res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s,
-					NULL);
+	int res;
+
+	/* 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_reltime t;
+		os_get_reltime(&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;
+	}
+
+	res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s,
+				    NULL);
 	if (res == 1) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d.%06d sec",
 			sec, usec);
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index e4c8989..59a1cff 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -13,6 +13,7 @@  int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s);
 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);
+void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx);
 int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 1314734..a430756 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -406,6 +406,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;