diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index 602d349e0..0e1576b0f 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -224,11 +224,27 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid, } -static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, - struct os_time *fetch_time) +static void calculate_update_time(const struct os_time *fetch_time, + unsigned int age_ms, + struct os_time *update_time) { os_time_t usec; + update_time->sec = fetch_time->sec; + update_time->usec = fetch_time->usec; + update_time->sec -= age_ms / 1000; + usec = (age_ms % 1000) * 1000; + if (update_time->usec < usec) { + update_time->sec--; + update_time->usec += 1000000; + } + update_time->usec -= usec; +} + + +static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, + struct os_time *fetch_time) +{ dst->flags = src->flags; os_memcpy(dst->bssid, src->bssid, ETH_ALEN); dst->freq = src->freq; @@ -239,15 +255,7 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, dst->level = src->level; dst->tsf = src->tsf; - dst->last_update.sec = fetch_time->sec; - dst->last_update.usec = fetch_time->usec; - dst->last_update.sec -= src->age / 1000; - usec = (src->age % 1000) * 1000; - if (dst->last_update.usec < usec) { - dst->last_update.sec--; - dst->last_update.usec += 1000000; - } - dst->last_update.usec -= usec; + calculate_update_time(fetch_time, src->age, &dst->last_update); } @@ -567,6 +575,21 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, const u8 *ssid, *p2p; struct wpa_bss *bss; + if (wpa_s->conf->ignore_old_scan_res) { + struct os_time update; + calculate_update_time(fetch_time, res->age, &update); + if (os_time_before(&update, &wpa_s->scan_trigger_time)) { + struct os_time age; + os_time_sub(&wpa_s->scan_trigger_time, &update, &age); + wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS " + "table entry that is %u.%06u seconds older " + "than our scan trigger", + (unsigned int) age.sec, + (unsigned int) age.usec); + return; + } + } + ssid = wpa_scan_get_ie(res, WLAN_EID_SSID); if (ssid == NULL) { wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for " diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 1b71ca71a..0d988840d 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -3089,6 +3089,7 @@ static const struct global_parse_data global_fields[] = { { INT(dtim_period), 0 }, { INT(beacon_int), 0 }, { FUNC(ap_vendor_elements), 0 }, + { INT_RANGE(ignore_old_scan_res, 0, 1), 0 }, }; #undef FUNC diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 00990cb40..1315e7bd5 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -844,6 +844,16 @@ struct wpa_config { * elements (id+len+payload for one or more elements). */ struct wpabuf *ap_vendor_elements; + + /** + * ignore_old_scan_res - Ignore scan results older than request + * + * The driver may have a cache of scan results that makes it return + * information that is older than our scan trigger. This parameter can + * be used to configure such old information to be ignored instead of + * allowing it to update the internal BSS table. + */ + int ignore_old_scan_res; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index d5de03076..5ca6bf2c6 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1004,6 +1004,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) fprintf(f, "\n"); } } + + if (config->ignore_old_scan_res) + fprintf(f, "ignore_old_scan_res=%d\n", + config->ignore_old_scan_res); } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index f11d69e5e..ed235f1b9 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -216,8 +216,10 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, break; } } - } else + } else { + os_get_time(&wpa_s->scan_trigger_time); wpa_s->scan_res_handler = wpas_p2p_scan_res_handler; + } return ret; } @@ -970,6 +972,7 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst, d->persistent_reconnect = s->persistent_reconnect; d->max_num_sta = s->max_num_sta; d->pbc_in_m1 = s->pbc_in_m1; + d->ignore_old_scan_res = s->ignore_old_scan_res; } @@ -3550,8 +3553,10 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq) * the new scan results become available. */ ret = wpa_drv_scan(wpa_s, ¶ms); - if (!ret) + if (!ret) { + os_get_time(&wpa_s->scan_trigger_time); wpa_s->scan_res_handler = wpas_p2p_scan_res_join; + } wpabuf_free(ies); diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 1a4f6955d..8f9449d05 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -227,6 +227,7 @@ int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, wpa_supplicant_notify_scanning(wpa_s, 0); wpas_notify_scan_done(wpa_s, 0); } else { + os_get_time(&wpa_s->scan_trigger_time); wpa_s->scan_runs++; wpa_s->normal_scans++; } diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index b40706076..0935a0624 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -302,6 +302,15 @@ fast_reauth=1 # one or more elements). This is used in AP and P2P GO modes. #ap_vendor_elements=dd0411223301 +# Ignore scan results older than request +# +# The driver may have a cache of scan results that makes it return +# information that is older than our scan trigger. This parameter can +# be used to configure such old information to be ignored instead of +# allowing it to update the internal BSS table. +#ignore_old_scan_res=0 + + # Interworking (IEEE 802.11u) # Enable Interworking diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 5465c4fa4..ac745d563 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -444,6 +444,7 @@ struct wpa_supplicant { */ MANUAL_SCAN_REQ } scan_req; + struct os_time scan_trigger_time; int scan_runs; /* number of scan runs since WPS was started */ int *next_scan_freqs; int scan_interval; /* time in sec between scans to find suitable AP */