@@ -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 */
@@ -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
*/
@@ -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);
@@ -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);
@@ -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);
@@ -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;