[PATCH 1/2] SME: Fall back from PMKSA caching if the AP rejects it with deauthentication

Louis Kotze loukot at gmail.com
Thu Jul 9 13:56:34 PDT 2026


When an association attempt uses SAE PMKSA caching, an AP that does not
accept the cached PMKSA is expected to respond to the Association
Request frame with an error status code, which makes wpa_supplicant
drop the PMKSA cache entry and fall back to a full SAE authentication.
However, some APs reject such an association attempt by
deauthenticating the STA (e.g., with reason code 9) instead of sending
an Association Response frame. That path did not drop the PMKSA cache
entry, so every subsequent connection attempt found the same entry
again, retried PMKSA caching, and was deauthenticated again. The
connection kept failing in a loop without ever falling back to SAE
authentication.

Observed with a TP-Link Deco BE65 AP MLD deauthenticating with reason
code 9 in response to an Association Request frame that used PMKSA
caching after a previous association attempt had failed.

Drop the PMKSA cache entry when the AP deauthenticates the STA during
an association attempt that used PMKSA caching, so that the next
attempt falls back to a full SAE authentication.

Signed-off-by: Louis Kotze <loukot at gmail.com>
---
 wpa_supplicant/events.c |  3 +++
 wpa_supplicant/sme.c    | 33 +++++++++++++++++++++++++++++++++
 wpa_supplicant/sme.h    |  7 +++++++
 3 files changed, 43 insertions(+)

diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 5faeddfbe..5f0b14522 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -5753,6 +5753,9 @@ static void wpas_event_deauth(struct wpa_supplicant *wpa_s,
 
 	wpa_reset_ft_completed(wpa_s->wpa);
 
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+		sme_event_deauth(wpa_s, info);
+
 	wpas_event_disconnect(wpa_s, addr, reason_code,
 			      locally_generated, ie, ie_len, 1);
 }
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 0ab66e760..7e144eacc 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -5022,6 +5022,39 @@ void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
 }
 
 
+void sme_event_deauth(struct wpa_supplicant *wpa_s,
+		      struct deauth_info *info)
+{
+#ifdef CONFIG_SAE
+	/* Some APs reject an association attempt that tries to use PMKSA
+	 * caching by deauthenticating the STA (e.g., with reason code 9)
+	 * instead of responding to the Association Request frame with an
+	 * error status code. Drop the PMKSA cache entry in that case so that
+	 * the next attempt uses a full SAE authentication instead of finding
+	 * the same PMKSA cache entry again and repeating the same failure. */
+	if (wpa_s->sme.sae_pmksa_caching && info && !info->locally_generated &&
+	    (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+	     wpa_s->wpa_state == WPA_ASSOCIATING) &&
+	    wpa_s->current_ssid &&
+	    wpa_key_mgmt_sae(wpa_s->current_ssid->key_mgmt)) {
+		const u8 *aa;
+
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"SME: PMKSA caching attempt rejected with deauthentication - drop PMKSA cache entry");
+		wpa_sm_aborted_cached(wpa_s->wpa);
+		if (wpa_s->valid_links)
+			aa = wpa_s->ap_mld_addr;
+		else if (wpa_s->current_bss)
+			aa = wpa_s->current_bss->bssid;
+		else
+			aa = NULL;
+		wpa_sm_pmksa_cache_flush_addr(wpa_s->wpa, wpa_s->current_ssid,
+					      aa);
+	}
+#endif /* CONFIG_SAE */
+}
+
+
 void sme_event_disassoc(struct wpa_supplicant *wpa_s,
 			struct disassoc_info *info)
 {
diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h
index a4521dddb..3466f8aec 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -25,6 +25,8 @@ void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
 			      union wpa_event_data *data);
 void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
 			       union wpa_event_data *data);
+void sme_event_deauth(struct wpa_supplicant *wpa_s,
+		      struct deauth_info *info);
 void sme_event_disassoc(struct wpa_supplicant *wpa_s,
 			struct disassoc_info *info);
 void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
@@ -80,6 +82,11 @@ static inline void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
 {
 }
 
+static inline void sme_event_deauth(struct wpa_supplicant *wpa_s,
+				    struct deauth_info *info)
+{
+}
+
 static inline void sme_event_disassoc(struct wpa_supplicant *wpa_s,
 				      struct disassoc_info *info)
 {
-- 
2.55.0




More information about the Hostap mailing list