Chromium Code Reviews| Index: wpa_supplicant/events.c |
| diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c |
| index 85f7558d414529355c7ef4a9f2c8de312fb2afd8..1499378b4624d1cdc7e24ed9d73b38b4ce7f1616 100644 |
| --- a/wpa_supplicant/events.c |
| +++ b/wpa_supplicant/events.c |
| @@ -884,9 +884,13 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, |
| struct wpa_bss *selected; |
| struct wpa_ssid *ssid = NULL; |
| struct wpa_scan_results *scan_res; |
| + int was_fast_reconnect; |
| wpa_supplicant_notify_scanning(wpa_s, 0); |
| + was_fast_reconnect = wpa_s->fast_reconnect; |
| + wpa_s->fast_reconnect = FALSE; |
| + |
| scan_res = wpa_supplicant_get_scan_results(wpa_s, |
| data ? &data->scan_info : |
| NULL, 1); |
| @@ -950,6 +954,14 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, |
| if (skip) |
| return; |
| wpa_supplicant_connect(wpa_s, selected, ssid); |
| + } else if (was_fast_reconnect) { |
| + /* |
| + * Processed deferred disassoc work on a failed |
| + * fast reconnect. |
| + */ |
| + wpa_printf(MSG_INFO, "Fast reconnect failed"); |
| + wpa_scan_results_free(scan_res); |
| + wpa_supplicant_mark_disassoc(wpa_s); |
| } else { |
| wpa_scan_results_free(scan_res); |
| wpa_printf(MSG_DEBUG, "No suitable network found"); |
| @@ -1245,10 +1257,47 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, |
| } |
| +/* |
| + * Try to return to the same AP immediately. Directly scan |
| + * on the current channel for the current BSSID and try to |
| + * reassociate. If the station is not present we will clock |
| + * the state machine to DISCONNECTED in wpa_supplicant_event_scan_results |
| + * which will notify external agents. |
| + */ |
| +static int wpa_supplicant_fast_reconnect(struct wpa_supplicant *wpa_s, |
| + const u8 *bssid) |
| +{ |
| + struct wpa_driver_scan_params params; |
| + int freqs[2]; |
| + |
| + wpa_s->reassociate = 1; |
| + wpa_s->fast_reconnect = 1; |
| + |
| + os_memset(¶ms, 0, sizeof(params)); |
| + params.num_ssids = 1; |
| + params.ssids[0].ssid = wpa_s->current_ssid->ssid; |
| + params.ssids[0].ssid_len = wpa_s->current_ssid->ssid_len; |
| + freqs[0] = wpa_s->assoc_freq; |
| + freqs[1] = 0; |
| + params.freqs = freqs; |
| + |
| + wpa_msg(wpa_s, MSG_INFO, "Fast reconnect bssid=" MACSTR |
| + " ssid=%.*s freq=%d", MAC2STR(bssid), |
| + params.ssids[0].ssid_len, params.ssids[0].ssid, |
| + params.freqs[0]); |
| + |
| + bgscan_deinit(wpa_s); |
|
Paul Stewart
2011/02/22 21:56:25
Nit: Any reason why instead of adding these two li
|
| + wpa_s->bgscan_ssid = NULL; |
| + |
| + return wpa_supplicant_trigger_scan(wpa_s, ¶ms); |
| +} |
| + |
| + |
| static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s, |
| u16 reason_code) |
| { |
| const u8 *bssid; |
| + int fast_reconnect; |
| #ifdef CONFIG_SME |
| int authenticating; |
| u8 prev_pending_bssid[ETH_ALEN]; |
| @@ -1273,18 +1322,29 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s, |
| wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - " |
| "pre-shared key may be incorrect"); |
| } |
| - if (wpa_s->wpa_state >= WPA_ASSOCIATING) |
| - wpa_supplicant_req_scan(wpa_s, 0, 100000); |
| - bssid = wpa_s->bssid; |
| - if (is_zero_ether_addr(bssid)) |
| - bssid = wpa_s->pending_bssid; |
| /* |
| - * Don't blacklist the AP on normal/expected disconnects. |
| + * If in a COMPLETED state and we were dropped for a reason |
| + * we can directly recover from directly re-join the AP without |
| + * clocking the state machine and/or notifying external agents. |
| + * |
| + * TODO(sleffler) guard against looping (should be only if AP is busted) |
| */ |
| - if (reason_code != WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY && |
| - reason_code != WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA && |
| - reason_code != WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA) |
| + fast_reconnect = |
| + wpa_s->wpa_state == WPA_COMPLETED && |
| + (reason_code == WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY || |
| + reason_code == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA || |
| + reason_code == WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); |
| + bssid = wpa_s->bssid; |
| + if (is_zero_ether_addr(bssid)) { |
| + bssid = wpa_s->pending_bssid; |
| + fast_reconnect = FALSE; /* XXX can this happen? */ |
| + wpa_printf(MSG_DEBUG, "Do not reconnect; pending bssid switch"); |
| + } |
| + if (!fast_reconnect) { |
| + if (wpa_s->wpa_state >= WPA_ASSOCIATING) |
| + wpa_supplicant_req_scan(wpa_s, 0, 100000); |
| wpa_blacklist_add(wpa_s, bssid); |
| + } |
| wpa_sm_notify_disassoc(wpa_s->wpa); |
| wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR |
| " reason=%d", |
| @@ -1294,6 +1354,13 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s, |
| wpa_s->keys_cleared = 0; |
| wpa_clear_keys(wpa_s, wpa_s->bssid); |
| } |
| + if (fast_reconnect) { |
| + if (wpa_supplicant_fast_reconnect(wpa_s, bssid) == 0) |
| + return; |
| + /* NB: fall through to slow path */ |
| + wpa_printf(MSG_DEBUG, "Fast reconnect: Failed to trigger scan"); |
| + wpa_supplicant_req_scan(wpa_s, 0, 100000); |
| + } |
| wpa_supplicant_mark_disassoc(wpa_s); |
| bgscan_deinit(wpa_s); |
| wpa_s->bgscan_ssid = NULL; |