Remove disconnected APs from BSS table if likely out-of-range

In some cases, after a sudden AP disappearing and reconnection to
another AP in the same ESS, if another scan occurs, wpa_supplicant might
try to roam to the old AP (if it was better ranked than the new one)
because it is still saved in BSS list and the blacklist entry was
cleared in previous reconnect. This attempt is going to fail if the AP
is not present anymore and it'll cause long disconnections.

Remove an AP that is probably out of range from the BSS list to avoid
such disconnections. In particular mac80211-based drivers use the
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY reason code in locally generated
disconnection events for cases where the AP does not reply anymore.

Signed-off-by: David Spinadel <david.spinadel@intel.com>
This commit is contained in:
David Spinadel 2016-09-05 17:33:07 +03:00 committed by Jouni Malinen
parent d57ca5cd45
commit 1ac388633a
3 changed files with 21 additions and 2 deletions

View file

@ -214,8 +214,8 @@ static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s,
} }
static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
const char *reason) const char *reason)
{ {
if (wpa_s->last_scan_res) { if (wpa_s->last_scan_res) {
unsigned int i; unsigned int i;

View file

@ -113,6 +113,8 @@ void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res, struct wpa_scan_res *res,
struct os_reltime *fetch_time); struct os_reltime *fetch_time);
void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
const char *reason);
void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
int new_scan); int new_scan);
int wpa_bss_init(struct wpa_supplicant *wpa_s); int wpa_bss_init(struct wpa_supplicant *wpa_s);

View file

@ -2518,6 +2518,7 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
struct wpa_bss *fast_reconnect = NULL; struct wpa_bss *fast_reconnect = NULL;
struct wpa_ssid *fast_reconnect_ssid = NULL; struct wpa_ssid *fast_reconnect_ssid = NULL;
struct wpa_ssid *last_ssid; struct wpa_ssid *last_ssid;
struct wpa_bss *curr = NULL;
authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING; authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN); os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN);
@ -2533,6 +2534,19 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
return; return;
} }
if (!wpa_s->disconnected && wpa_s->wpa_state >= WPA_AUTHENTICATING &&
reason_code == WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY &&
locally_generated)
/*
* Remove the inactive AP (which is probably out of range) from
* the BSS list after marking disassociation. In particular
* mac80211-based drivers use the
* WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY reason code in
* locally generated disconnection events for cases where the
* AP does not reply anymore.
*/
curr = wpa_s->current_bss;
if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) { if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) {
wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - " wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
"pre-shared key may be incorrect"); "pre-shared key may be incorrect");
@ -2594,6 +2608,9 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
last_ssid = wpa_s->current_ssid; last_ssid = wpa_s->current_ssid;
wpa_supplicant_mark_disassoc(wpa_s); wpa_supplicant_mark_disassoc(wpa_s);
if (curr)
wpa_bss_remove(wpa_s, curr, "Connection to AP lost");
if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) { if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) {
sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid); sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid);
wpa_s->current_ssid = last_ssid; wpa_s->current_ssid = last_ssid;