Patchwork [02/15] supplicant: Allow limiting number of concurrent associations.

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

Comments

Ben Greear - March 6, 2014, 12:19 a.m.
From: Ben Greear <greearb@candelatech.com>

When using lots of virtual clients, it may be useful to
limit the number that attempt to connect to the AP at
once.  Limitting the associations per scan response is
an easy way to do this.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 wpa_supplicant/config.c |    2 ++
 wpa_supplicant/config.h |    7 +++++++
 wpa_supplicant/events.c |   28 ++++++++++++++++++++++++++--
 3 files changed, 35 insertions(+), 2 deletions(-)

Patch

diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 9a17b22..1df9213 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2983,6 +2983,7 @@  struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
 	config->wmm_ac_params[2] = ac_vi;
 	config->wmm_ac_params[3] = ac_vo;
 	config->min_scan_gap = DEFAULT_MIN_SCAN_GAP;
+	config->max_assoc_per_scan = DEFAULT_MAX_ASSOC_PER_SCAN;
 
 	if (ctrl_interface)
 		config->ctrl_interface = os_strdup(ctrl_interface);
@@ -3520,6 +3521,7 @@  static const struct global_parse_data global_fields[] = {
 	{ INT(dot11RSNAConfigPMKReauthThreshold), 0 },
 	{ INT(dot11RSNAConfigSATimeout), 0 },
 	{ INT(min_scan_gap), 0 },
+	{ INT(max_assoc_per_scan), 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 b5f23ac..690bfde 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -26,6 +26,7 @@ 
 #define DEFAULT_ACCESS_NETWORK_TYPE 15
 #define DEFAULT_SCAN_CUR_FREQ 0
 #define DEFAULT_MIN_SCAN_GAP 0
+#define DEFAULT_MAX_ASSOC_PER_SCAN 25
 
 #include "config_ssid.h"
 #include "wps/wps.h"
@@ -779,6 +780,12 @@  struct wpa_config {
 	/* Minimum interval between scan requests, in seconds */
 	int min_scan_gap;
 
+	/* Maximum number of association requests per scan results
+	 * This can be used to stop a thundering herd of hundreds of
+	 * virtual stations from all trying to associate at once.
+	 */
+	int max_assoc_per_scan;
+
 	/**
 	 * interworking - Whether Interworking (IEEE 802.11u) is enabled
 	 */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index ff857ab..46ef7af 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -82,6 +82,7 @@  static struct wpa_bss * wpa_supplicant_get_new_bss(
 	return bss;
 }
 
+static int num_assoc_reqs;
 
 static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
 {
@@ -1106,8 +1107,21 @@  int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
 			wpa_supplicant_req_new_scan(wpa_s, 10, 0);
 			return 0;
 		}
-		wpa_msg(wpa_s, MSG_DEBUG, "Request association with " MACSTR,
-			MAC2STR(selected->bssid));
+
+		if (num_assoc_reqs >= wpa_s->conf->max_assoc_per_scan) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"Deferring association attempt, reqs: %i, max: %i",
+				num_assoc_reqs, wpa_s->conf->max_assoc_per_scan);
+			return 0;
+		}
+		num_assoc_reqs++;
+
+		wpa_msg(wpa_s, MSG_DEBUG, "Request association: "
+			"reassociate: %d  selected: "MACSTR "  bssid: " MACSTR
+			"  pending: " MACSTR "  wpa_state: %s",
+			wpa_s->reassociate, MAC2STR(selected->bssid),
+			MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+			wpa_supplicant_state_txt(wpa_s->wpa_state));
 		wpa_supplicant_associate(wpa_s, selected, ssid);
 	} else {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Already associated or trying to "
@@ -1427,6 +1441,14 @@  static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
 		wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
 		ssid = wpa_supplicant_pick_new_network(wpa_s);
 		if (ssid) {
+			if (num_assoc_reqs >= wpa_s->conf->max_assoc_per_scan) {
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"Deferring association, reqs: %i, max: %i",
+					num_assoc_reqs, wpa_s->conf->max_assoc_per_scan);
+				return 0;
+			}
+			num_assoc_reqs++;
+
 			wpa_dbg(wpa_s, MSG_DEBUG, "Setup a new network");
 			wpa_supplicant_associate(wpa_s, NULL, ssid);
 			if (new_scan)
@@ -1494,6 +1516,8 @@  static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 {
 	struct wpa_supplicant *ifs;
 
+	num_assoc_reqs = 0;
+
 	if (_wpa_supplicant_event_scan_results(wpa_s, data, 1) != 0) {
 		/*
 		 * If no scan results could be fetched, then no need to