@@ -2609,6 +2609,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);
@@ -2981,6 +2982,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 */
@@ -24,6 +24,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"
@@ -646,6 +647,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
*/
@@ -1071,6 +1071,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_time t;
#ifdef CONFIG_AP
if (wpa_s->ap_iface)
@@ -1146,6 +1147,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);
@@ -501,7 +501,7 @@ static int shared_vif_oper_freq(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_P2P */
-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;
@@ -835,6 +835,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);
@@ -321,6 +321,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;