diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index bf741adbb..b3861f5be 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -2063,9 +2063,11 @@ static int wpa_driver_nl80211_authenticate( int ret = -1, i; struct nl_msg *msg; enum nl80211_auth_type type; + int count = 0; drv->associated = 0; +retry: msg = nlmsg_alloc(); if (!msg) return -1; @@ -2133,6 +2135,21 @@ static int wpa_driver_nl80211_authenticate( if (ret) { wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d " "(%s)", ret, strerror(-ret)); + count++; + if (ret == -EALREADY && count == 1 && params->bssid) { + /* + * mac80211 does not currently accept new + * authentication if we are already authenticated. As a + * workaround, force deauthentication and try again. + */ + wpa_printf(MSG_DEBUG, "nl80211: Retry authentication " + "after forced deauthentication"); + wpa_driver_nl80211_deauthenticate( + drv, params->bssid, + WLAN_REASON_PREV_AUTH_NOT_VALID); + nlmsg_free(msg); + goto retry; + } goto nla_put_failure; } ret = 0; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index f44a0e616..391725635 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1065,6 +1065,13 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s) { const u8 *bssid; +#ifdef CONFIG_SME + int authenticating; + u8 prev_pending_bssid[ETH_ALEN]; + + authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING; + os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN); +#endif /* CONFIG_SME */ if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) { /* @@ -1097,6 +1104,20 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s) } wpa_supplicant_mark_disassoc(wpa_s); bgscan_deinit(wpa_s); +#ifdef CONFIG_SME + if (authenticating && + (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) { + /* + * mac80211-workaround to force deauth on failed auth cmd, + * requires us to remain in authenticating state to allow the + * second authentication attempt to be continued properly. + */ + wpa_printf(MSG_DEBUG, "SME: Allow pending authentication to " + "proceed after disconnection event"); + wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING); + os_memcpy(wpa_s->pending_bssid, prev_pending_bssid, ETH_ALEN); + } +#endif /* CONFIG_SME */ }