From 799cc8eca9ef51a485ff98f3b45a54bbcb90dc56 Mon Sep 17 00:00:00 2001 From: Chenming Huang Date: Wed, 26 Feb 2025 20:02:20 +0530 Subject: [PATCH] AP MLD: Define a new MLD-level PMKSA cache shared by all links Currently PMKSA is only cached on the association link. Subsequent connections may happen on other links if peer is a non-AP MLD. Association using SAE might get rejected due to PMKID not found in such cases. Define a new PMKSA entry list in struct wpa_authenticator which will be used in subsequent commits. Initialize ml_pmksa only on the primary link authenticator and deinitialize it when the last link authenticator is deinitialized. Other affiliated links share the same instance. Signed-off-by: Chenming Huang --- src/ap/wpa_auth.c | 61 +++++++++++++++++++++++++++++++++++++++--- src/ap/wpa_auth.h | 1 + src/ap/wpa_auth_glue.c | 16 +++++++++++ src/ap/wpa_auth_i.h | 2 ++ 4 files changed, 77 insertions(+), 3 deletions(-) diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 80f9984cc..5939d28a5 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -781,6 +781,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr, return NULL; } + /* Per-link PMKSA cache */ wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb, wpa_auth); if (!wpa_auth->pmksa) { @@ -791,12 +792,46 @@ struct wpa_authenticator * wpa_init(const u8 *addr, return NULL; } +#ifdef CONFIG_IEEE80211BE + /* MLD-level PMKSA cache */ + if (wpa_auth->is_ml && wpa_auth->primary_auth) { + wpa_auth->ml_pmksa = pmksa_cache_auth_init( + wpa_auth_pmksa_free_cb, wpa_auth); + if (!wpa_auth->ml_pmksa) { + wpa_printf(MSG_ERROR, + "MLD-level PMKSA cache initialization failed."); + os_free(wpa_auth->group); + os_free(wpa_auth->wpa_ie); + pmksa_cache_auth_deinit(wpa_auth->pmksa); + os_free(wpa_auth); + return NULL; + } + } else if (wpa_auth->is_ml) { + struct wpa_authenticator *pa = wpa_get_primary_auth(wpa_auth); + + if (!pa) { + wpa_printf(MSG_ERROR, + "Could not find primary authenticator."); + os_free(wpa_auth->group); + os_free(wpa_auth->wpa_ie); + pmksa_cache_auth_deinit(wpa_auth->pmksa); + os_free(wpa_auth); + return NULL; + } + wpa_auth->ml_pmksa = pa->ml_pmksa; + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_IEEE80211R_AP wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init(); if (!wpa_auth->ft_pmk_cache) { wpa_printf(MSG_ERROR, "FT PMK cache initialization failed."); os_free(wpa_auth->group); os_free(wpa_auth->wpa_ie); +#ifdef CONFIG_IEEE80211BE + if (wpa_auth->primary_auth) + pmksa_cache_auth_deinit(wpa_auth->ml_pmksa); +#endif /* CONFIG_IEEE80211BE */ pmksa_cache_auth_deinit(wpa_auth->pmksa); os_free(wpa_auth); return NULL; @@ -878,15 +913,35 @@ static void wpa_auth_free_conf(struct wpa_auth_config *conf) void wpa_deinit(struct wpa_authenticator *wpa_auth) { struct wpa_group *group, *prev; +#ifdef CONFIG_IEEE80211BE + struct wpa_authenticator *next_pa; +#endif /* CONFIG_IEEE80211BE */ eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL); - - /* TODO: Assign ML primary authenticator to next link authenticator and - * start rekey timer. */ eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL); pmksa_cache_auth_deinit(wpa_auth->pmksa); +#ifdef CONFIG_IEEE80211BE + if (wpa_auth->is_ml && wpa_auth->primary_auth) { + next_pa = wpa_auth->cb->next_primary_auth(wpa_auth->cb_ctx); + + if (!next_pa) { + /* Deinit PMKSA entry list if last link */ + pmksa_cache_auth_deinit(wpa_auth->ml_pmksa); + } else { + /* Assign ML primary authenticator to the next link + * authenticator and start rekey timer. + */ + next_pa->primary_auth = true; + if (next_pa->conf.wpa_group_rekey) + eloop_register_timeout( + next_pa->conf.wpa_group_rekey, + 0, wpa_rekey_gtk, next_pa, NULL); + } + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_IEEE80211R_AP wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache); wpa_auth->ft_pmk_cache = NULL; diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 6a41755ef..2c29baaef 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -428,6 +428,7 @@ struct wpa_auth_callbacks { #ifdef CONFIG_IEEE80211BE int (*get_ml_key_info)(void *ctx, struct wpa_auth_ml_key_info *info, bool rekey); + struct wpa_authenticator * (*next_primary_auth)(void *ctx); #endif /* CONFIG_IEEE80211BE */ int (*get_drv_flags)(void *ctx, u64 *drv_flags, u64 *drv_flags2); }; diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 83be41266..d30e9ef3b 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -1631,6 +1631,21 @@ static int hostapd_wpa_auth_get_ml_key_info(void *ctx, return 0; } + +static struct wpa_authenticator * hostapd_next_primary_auth(void *cb_ctx) +{ + struct hostapd_data *hapd = cb_ctx, *bss; + + for_each_mld_link(bss, hapd) { + if (bss == hapd) + continue; + if (bss->wpa_auth) + return bss->wpa_auth; + } + + return NULL; +} + #endif /* CONFIG_IEEE80211BE */ @@ -1700,6 +1715,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) #endif /* CONFIG_PASN */ #ifdef CONFIG_IEEE80211BE .get_ml_key_info = hostapd_wpa_auth_get_ml_key_info, + .next_primary_auth = hostapd_next_primary_auth, #endif /* CONFIG_IEEE80211BE */ .get_drv_flags = hostapd_wpa_auth_get_drv_flags, }; diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index 188f51eb8..0aa25b903 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -267,6 +267,8 @@ struct wpa_authenticator { #endif /* CONFIG_P2P */ #ifdef CONFIG_IEEE80211BE + /* MLD-level PMKSA cache for non-AP MLD entries only. */ + struct rsn_pmksa_cache *ml_pmksa; bool is_ml; u8 mld_addr[ETH_ALEN]; u8 link_id; -- 2.47.2