@@ -2610,6 +2610,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);
@@ -2983,6 +2984,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 */
@@ -25,6 +25,7 @@
#define DEFAULT_MAX_NUM_STA 128
#define DEFAULT_ACCESS_NETWORK_TYPE 15
#define DEFAULT_MIN_SCAN_GAP 0
+#define DEFAULT_MAX_ASSOC_PER_SCAN 25
#include "config_ssid.h"
#include "wps/wps.h"
@@ -650,6 +651,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
*/
@@ -62,6 +62,8 @@ static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
}
+static int num_assoc_reqs;
+
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid, *old_ssid;
@@ -916,6 +918,15 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
wpa_supplicant_req_new_scan(wpa_s, 10, 0);
return 0;
}
+
+ 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",
@@ -1230,6 +1241,14 @@ 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);
wpa_supplicant_rsn_preauth_scan_results(wpa_s);
@@ -1280,6 +1299,8 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
const char *rn, *rn2;
struct wpa_supplicant *ifs;
+ num_assoc_reqs = 0;
+
if (_wpa_supplicant_event_scan_results(wpa_s, data) != 0) {
/*
* If no scan results could be fetched, then no need to