[RFC] wpa_supplicant: Don't stop conn. radio work on DEAUTH

Message ID 1393851204-964-8-git-send-email-ilan.peer@intel.com
State Superseded
Headers show

Commit Message

Ilan Peer March 3, 2014, 12:53 p.m.
From: Andrei Otcheretianski <andrei.otcheretianski@intel.com>

If DEAUTH event is received while authenticating, wpas_connection_failed()
is invoked cancelling the radio work. However, the flow might continue
calling sme_disassoc_while_authenticating() which leaves the wpa_supplicant
in the AUTHENTICATING state,  thus allowing the continuation of the connection
flow (without radio work protection) in case AUTH frame is received.

This issue was seen during EAPOL connection, when the client starts the fast
association in wpas_wps_eapol_cb, where the following race occurs:

1. DEAUTH after initial EAPOL HS
2. Start fast associate and send AUTH
3. DEAUTH event rebound from kernel -> wpas_connection_failed() is called,
   stopping the connect radio work
4. SCAN is started
5. AUTH is received, and the connection flow is continued without
   radio work protection
6. SCAN_RESULTS received in the middle of association.
7. Failure in wpa_driver_nl80211_check_bss_status due to
   state mismatch - > DEAUTH with reason code 2.

Fix this by not calling wpas_connection_failed() in step 4, if the
wpa_supplicant is in authenticating state and using SME (same conditions
that result in calling sme_disassoc_while_authenticating()).

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
 wpa_supplicant/events.c |   15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)


diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index d98e4a4..bf5d9d5 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2185,8 +2185,19 @@  static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
 	bssid = wpa_s->bssid;
 	if (is_zero_ether_addr(bssid))
 		bssid = wpa_s->pending_bssid;
-	if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
-		wpas_connection_failed(wpa_s, bssid);
+	if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+		/*
+		 * The connection shouldn't be failed if we will call
+		 * sme_disassoc_while_authenticating, otherwise we may
+		 * continue the connection, without radio work
+		 * protection.
+		 */
+		if (!authenticating ||
+		    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
+			wpas_connection_failed(wpa_s, bssid);
+	}
 	if (locally_generated)
 		wpa_s->disconnect_reason = -reason_code;