[PATCH] AP: Disconnect station when PMKSA entry expires
Jason Huang
Jason.Huang2 at infineon.com
Thu May 14 19:44:28 PDT 2026
From: Kurt Lee <kurt.lee at infineon.com>
When a PMKSA cache entry expires for a currently associated station, the
AP may keep the link up until another trigger causes reauthentication.
This delays key refresh and can leave the station connected with stale
PMKSA state.
Fix this by disconnecting the station when its PMKSA entry is freed on
expiration. The disconnect causes the STA to immediately start a new
authentication exchange and complete a fresh association/4-way handshake.
Also add plumbing for dot11RSNAConfigPMKLifetime into the authenticator
context so the configured PMK lifetime is propagated to the lower layers.
Signed-off-by: Kurt Lee <kurt.lee at infineon.com>
Signed-off-by: Jason Huang <jason.huang2 at infineon.com>
---
hostapd/config_file.c | 2 ++
src/ap/ap_config.h | 1 +
src/ap/ieee802_11.c | 1 +
src/ap/wpa_auth.c | 12 ++++++++++--
src/ap/wpa_auth.h | 2 ++
src/ap/wpa_auth_i.h | 1 +
wpa_supplicant/ap.c | 2 ++
7 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index d34b4aa83..9568090b1 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3756,6 +3756,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->max_listen_interval = atoi(pos);
} else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
bss->disable_pmksa_caching = atoi(pos);
+ } else if (os_strcmp(buf, "dot11RSNAConfigPMKLifetime") == 0) {
+ bss->dot11RSNAConfigPMKLifetime = atoi(pos);
} else if (os_strcmp(buf, "okc") == 0) {
bss->okc = atoi(pos);
#ifdef CONFIG_WPS
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 3fe2206b9..79904c4e3 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -1007,6 +1007,7 @@ struct hostapd_bss_config {
unsigned int pmksa_caching_privacy:1;
unsigned int eap_using_authentication_frames:1;
#endif /* CONFIG_ENC_ASSOC */
+ unsigned int dot11RSNAConfigPMKLifetime;
};
/**
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index d01f42d82..8ba912fd7 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1340,6 +1340,7 @@ void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
sta->sae->peer_commit_scalar = NULL;
+ wpa_auth_set_pmk_life_time(hapd->wpa_auth,hapd->conf->dot11RSNAConfigPMKLifetime);
wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
sta->sae->pmk, sta->sae->pmk_len,
sta->sae->pmkid, sta->sae->akmp,
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 42344a2bd..e1326a170 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -701,6 +701,7 @@ static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
entry);
}
#else /* CONFIG_IEEE80211BE */
+ wpa_sta_disconnect(wpa_auth, entry->spa, WLAN_REASON_PREV_AUTH_NOT_VALID);
wpa_auth_for_each_sta(wpa_auth, wpa_auth_pmksa_clear_cb, entry);
#endif /* CONFIG_IEEE80211BE */
@@ -6855,6 +6856,12 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
}
+void wpa_auth_set_pmk_life_time(struct wpa_authenticator *wpa_auth, unsigned int pmk_life_time)
+{
+ wpa_auth->pmk_life_time = pmk_life_time;
+}
+
+
int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
int akmp, bool is_ml, int vlan_id)
@@ -6877,8 +6884,9 @@ int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
}
#endif /* CONFIG_IEEE80211BE */
- entry = pmksa_cache_auth_add(pmksa, pmk, pmk_len, pmkid, NULL, 0,
- aa, addr, 0, NULL, akmp);
+ entry = pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
+ NULL, 0, wpa_auth->addr, addr,
+ wpa_auth->pmk_life_time, NULL, akmp);
if (!entry)
return -1;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 97f55e67a..97e48789a 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -531,6 +531,8 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
const u8 *pmk, size_t len, const u8 *sta_addr,
int session_timeout,
struct eapol_state_machine *eapol);
+void wpa_auth_set_pmk_life_time(struct wpa_authenticator *wpa_auth,
+ unsigned int pmk_life_time);
int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
int akmp, bool is_ml, int vlan_id);
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index c9427bb72..3661d3b3e 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -279,6 +279,7 @@ struct wpa_authenticator {
u8 link_id;
bool primary_auth;
#endif /* CONFIG_IEEE80211BE */
+ unsigned int pmk_life_time;
};
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index d0a1a96fd..39ab1adb3 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -649,6 +649,8 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
}
bss->sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
+
+ bss->dot11RSNAConfigPMKLifetime = wpa_s->conf->dot11RSNAConfigPMKLifetime;
#endif /* CONFIG_SAE */
if (wpa_s->conf->go_interworking) {
--
2.25.1
More information about the Hostap
mailing list