]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
AP MLD: Support group rekeying for MLO
authorRameshkumar Sundaram <quic_ramess@quicinc.com>
Thu, 28 Mar 2024 18:16:47 +0000 (23:46 +0530)
committerJouni Malinen <j@w1.fi>
Sat, 20 Apr 2024 15:31:11 +0000 (18:31 +0300)
Group rekeying was not supported for ML stations when non-association
link initiates a group rekey. Support this by arming the group key rekey
timer on one of the affiliated links and whenever this timer fires,
rekey group keys on all the affiliated links.

Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Co-developed-by: Adil Saeed Musthafa <quic_adilm@quicinc.com>
Signed-off-by: Adil Saeed Musthafa <quic_adilm@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
src/ap/wpa_auth.c

index 69c62b4982145c4412cc1446dfceb0385a9a9e46..9aeae89faad4db287221f8c388156ac8595bbb13 100644 (file)
@@ -71,6 +71,9 @@ static void wpa_group_put(struct wpa_authenticator *wpa_auth,
                          struct wpa_group *group);
 static int ieee80211w_kde_len(struct wpa_state_machine *sm);
 static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
+static void wpa_group_update_gtk(struct wpa_authenticator *wpa_auth,
+                                struct wpa_group *group);
+
 
 static const u32 eapol_key_timeout_first = 100; /* ms */
 static const u32 eapol_key_timeout_subseq = 1000; /* ms */
@@ -105,11 +108,20 @@ static const u8 * wpa_auth_get_spa(const struct wpa_state_machine *sm)
 
 static void wpa_gkeydone_sta(struct wpa_state_machine *sm)
 {
+#ifdef CONFIG_IEEE80211BE
+       int link_id;
+#endif /* CONFIG_IEEE80211BE */
+
        if (!sm->wpa_auth)
                return;
 
        sm->wpa_auth->group->GKeyDoneStations--;
        sm->GUpdateStationKeys = false;
+
+#ifdef CONFIG_IEEE80211BE
+       for_each_sm_auth(sm, link_id)
+               sm->mld_links[link_id].wpa_auth->group->GKeyDoneStations--;
+#endif /* CONFIG_IEEE80211BE */
 }
 
 
@@ -163,10 +175,13 @@ static int wpa_get_primary_auth_cb(struct wpa_authenticator *wpa_auth,
        return 1;
 }
 
+#endif /* CONFIG_IEEE80211BE */
+
 
 static struct wpa_authenticator *
 wpa_get_primary_auth(struct wpa_authenticator *wpa_auth)
 {
+#ifdef CONFIG_IEEE80211BE
        struct wpa_get_link_auth_ctx ctx;
 
        if (!wpa_auth || !wpa_auth->is_ml || wpa_auth->primary_auth)
@@ -177,9 +192,10 @@ wpa_get_primary_auth(struct wpa_authenticator *wpa_auth)
        wpa_auth_for_each_auth(wpa_auth, wpa_get_primary_auth_cb, &ctx);
 
        return ctx.wpa_auth;
-}
-
+#else /* CONFIG_IEEE80211BE */
+       return wpa_auth;
 #endif /* CONFIG_IEEE80211BE */
+}
 
 
 static inline int wpa_auth_mic_failure_report(
@@ -447,14 +463,16 @@ static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
 }
 
 
-static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
+static void wpa_rekey_all_groups(struct wpa_authenticator *wpa_auth)
 {
-       struct wpa_authenticator *wpa_auth = eloop_ctx;
        struct wpa_group *group, *next;
 
        wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
        group = wpa_auth->group;
        while (group) {
+               wpa_printf(MSG_DEBUG, "GTK rekey start for authenticator ("
+                          MACSTR "), group vlan %d",
+                          MAC2STR(wpa_auth->addr), group->vlan_id);
                wpa_group_get(wpa_auth, group);
 
                group->GTKReKey = true;
@@ -467,6 +485,83 @@ static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
                wpa_group_put(wpa_auth, group);
                group = next;
        }
+}
+
+
+#ifdef CONFIG_IEEE80211BE
+
+static void wpa_update_all_gtks(struct wpa_authenticator *wpa_auth)
+{
+       struct wpa_group *group, *next;
+
+       group = wpa_auth->group;
+       while (group) {
+               wpa_group_get(wpa_auth, group);
+
+               wpa_group_update_gtk(wpa_auth, group);
+               next = group->next;
+               wpa_group_put(wpa_auth, group);
+               group = next;
+       }
+}
+
+
+static int wpa_update_all_gtks_cb(struct wpa_authenticator *wpa_auth, void *ctx)
+{
+       const u8 *mld_addr = ctx;
+
+       if (!ether_addr_equal(wpa_auth->mld_addr, mld_addr))
+               return 0;
+
+       wpa_update_all_gtks(wpa_auth);
+       return 0;
+}
+
+
+static int wpa_rekey_all_groups_cb(struct wpa_authenticator *wpa_auth,
+                                  void *ctx)
+{
+       const u8 *mld_addr = ctx;
+
+       if (!ether_addr_equal(wpa_auth->mld_addr, mld_addr))
+               return 0;
+
+       wpa_rekey_all_groups(wpa_auth);
+       return 0;
+}
+
+#endif /* CONFIG_IEEE80211BE */
+
+
+static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_authenticator *wpa_auth = eloop_ctx;
+
+#ifdef CONFIG_IEEE80211BE
+       if (wpa_auth->is_ml) {
+               /* Non-primary ML authenticator eloop timer for group rekey is
+                * never started and shouldn't fire. Check and warn just in
+                * case. */
+               if (!wpa_auth->primary_auth) {
+                       wpa_printf(MSG_DEBUG,
+                                  "RSN: Cannot start GTK rekey on non-primary ML authenticator");
+                       return;
+               }
+
+               /* Generate all the new group keys */
+               wpa_auth_for_each_auth(wpa_auth, wpa_update_all_gtks_cb,
+                                      wpa_auth->mld_addr);
+
+               /* Send all the generated group keys to the respective stations
+                * with group key handshake. */
+               wpa_auth_for_each_auth(wpa_auth, wpa_rekey_all_groups_cb,
+                                      wpa_auth->mld_addr);
+       } else {
+               wpa_rekey_all_groups(wpa_auth);
+       }
+#else /* CONFIG_IEEE80211BE */
+       wpa_rekey_all_groups(wpa_auth);
+#endif /* CONFIG_IEEE80211BE */
 
        if (wpa_auth->conf.wpa_group_rekey) {
                eloop_register_timeout(wpa_auth->conf.wpa_group_rekey,
@@ -672,7 +767,15 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
                                       wpa_rekey_gmk, wpa_auth, NULL);
        }
 
+#ifdef CONFIG_IEEE80211BE
+       /* For AP MLD, run group rekey timer only on one link (first) and
+        * whenever it fires do rekey on all associated ML links in one shot.
+        */
+       if ((!wpa_auth->is_ml || !conf->first_link_auth) &&
+           wpa_auth->conf.wpa_group_rekey) {
+#else /* CONFIG_IEEE80211BE */
        if (wpa_auth->conf.wpa_group_rekey) {
+#endif /* CONFIG_IEEE80211BE */
                eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, 0,
                                       wpa_rekey_gtk, wpa_auth, NULL);
        }
@@ -736,6 +839,9 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth)
        struct wpa_group *group, *prev;
 
        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);
@@ -1704,12 +1810,16 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                        wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
                                        LOGGER_INFO,
                                        "received EAPOL-Key Request for GTK rekeying");
-                       eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
+
+                       eloop_cancel_timeout(wpa_rekey_gtk,
+                                            wpa_get_primary_auth(wpa_auth),
+                                            NULL);
                        if (wpa_auth_gtk_rekey_in_process(wpa_auth))
                                wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG,
                                                "skip new GTK rekey - already in process");
                        else
-                               wpa_rekey_gtk(wpa_auth, NULL);
+                               wpa_rekey_gtk(wpa_get_primary_auth(wpa_auth),
+                                             NULL);
                }
        } else {
                /* Do not allow the same key replay counter to be reused. */
@@ -5466,17 +5576,11 @@ int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos)
 #endif /* CONFIG_WNM_AP */
 
 
-static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
-                             struct wpa_group *group)
+static void wpa_group_update_gtk(struct wpa_authenticator *wpa_auth,
+                                struct wpa_group *group)
 {
        int tmp;
 
-       wpa_printf(MSG_DEBUG,
-                  "WPA: group state machine entering state SETKEYS (VLAN-ID %d)",
-                  group->vlan_id);
-       group->changed = true;
-       group->wpa_group_state = WPA_GROUP_SETKEYS;
-       group->GTKReKey = false;
        tmp = group->GM;
        group->GM = group->GN;
        group->GN = tmp;
@@ -5490,6 +5594,25 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
         * counting the STAs that are marked with GUpdateStationKeys instead of
         * including all STAs that could be in not-yet-completed state. */
        wpa_gtk_update(wpa_auth, group);
+}
+
+
+static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
+                             struct wpa_group *group)
+{
+       wpa_printf(MSG_DEBUG,
+                  "WPA: group state machine entering state SETKEYS (VLAN-ID %d)",
+                  group->vlan_id);
+       group->changed = true;
+       group->wpa_group_state = WPA_GROUP_SETKEYS;
+       group->GTKReKey = false;
+
+#ifdef CONFIG_IEEE80211BE
+       if (wpa_auth->is_ml)
+               goto skip_update;
+#endif /* CONFIG_IEEE80211BE */
+
+       wpa_group_update_gtk(wpa_auth, group);
 
        if (group->GKeyDoneStations) {
                wpa_printf(MSG_DEBUG,
@@ -5497,6 +5620,10 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
                           group->GKeyDoneStations);
                group->GKeyDoneStations = 0;
        }
+
+#ifdef CONFIG_IEEE80211BE
+skip_update:
+#endif /* CONFIG_IEEE80211BE */
        wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, group);
        wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d",
                   group->GKeyDoneStations);
@@ -6857,8 +6984,10 @@ int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth)
 {
        if (!wpa_auth)
                return -1;
-       eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
-       return eloop_register_timeout(0, 0, wpa_rekey_gtk, wpa_auth, NULL);
+       eloop_cancel_timeout(wpa_rekey_gtk,
+                            wpa_get_primary_auth(wpa_auth), NULL);
+       return eloop_register_timeout(0, 0, wpa_rekey_gtk,
+                                     wpa_get_primary_auth(wpa_auth), NULL);
 }