[PATCH v2 1/2] SME: Fall back from PMKSA caching if the AP deauthenticates
Louis Kotze
loukot at gmail.com
Tue Jul 28 02:25:20 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.
sme_event_assoc_reject() already does this for the case where the AP
responds with an error status code. The new handler mirrors that cache
handling, but not the reconnection that follows it there: the AP has
already deauthenticated in this case, so wpas_event_disconnect() runs
immediately afterwards and drives the reconnection. The additional
checks on wpa_state and info->locally_generated are needed because,
unlike an association reject, a deauthentication event can arrive at
any point.
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 2b6eb2a88..bcbe55ec3 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -5892,6 +5892,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 253716609..bbf5ebb48 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -4985,6 +4985,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