]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
AP MLD: Define a new MLD-level PMKSA cache shared by all links
authorChenming Huang <quic_chenhuan@quicinc.com>
Wed, 26 Feb 2025 14:32:20 +0000 (20:02 +0530)
committerJouni Malinen <j@w1.fi>
Thu, 27 Feb 2025 10:11:42 +0000 (12:11 +0200)
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 <quic_chenhuan@quicinc.com>
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_glue.c
src/ap/wpa_auth_i.h

index 80f9984cce4a1bf43ca99739b323a2efd7210223..5939d28a5472afd9b4bf1596fd267251f75abb56 100644 (file)
@@ -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;
index 6a41755efe41efed4bfd8ac92ee4e58478f38a51..2c29baaef5cb8e5ed75a05fb772a29b46042829c 100644 (file)
@@ -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);
 };
index 83be41266ff6a0c5429f13f6a42b4e6ff3cfb503..d30e9ef3b0f0d92272593348690cc4815f38098d 100644 (file)
@@ -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,
        };
index 188f51eb84409cb9309197b81d8f2a86132e35d4..0aa25b9030ccaba67b4e17c00c6f3af99e1720dc 100644 (file)
@@ -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;