]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
VLAN: Group state machine data creation for partner AP MLD links
authorSai Pratyusha Magam <smagam@qti.qualcomm.com>
Mon, 8 Dec 2025 04:45:56 +0000 (10:15 +0530)
committerJouni Malinen <j@w1.fi>
Fri, 23 Jan 2026 13:51:20 +0000 (15:51 +0200)
In EAPOL-Key msg 3/4 and group handshake message 1, the AP needs to
populate group keys from the appropriate VLAN group state machine data
(wpa_group) for each of the setup links. In the existing dynamic VLAN
implementation, when a multi-link STA associates on a particular VLAN,
VLAN group is created for the association link, but the same is not
created for partner links. As a result, in the absence of VLAN group
state machine data in partner authenticator object, at the time of
fetching group keys for the non-association links, in
wpa_auth_ml_get_key_info(), the helper function
wpa_select_vlan_wpa_group() fetches group keys on non-association links
from the default VLAN group.

Address this by allowing the ap_sta_set_vlan() and ap_sta_bind_vlan()
functionality to repeat for each of the setup links, i.e., as part of
ap_sta_set_vlan(), perform VLAN assignment to STA object in each of the
setup links and also allow VLAN group state machine data creation in the
partner authenticators as part of ap_sta_bind_vlan().

Fixes: dd65e53c9476 ("VLAN: Use VLAN group keys for EAPOL frames and FT reassoc for MLO")
Co-developed-by: Adil Saeed Musthafa <adilm@qti.qualcomm.com>
Signed-off-by: Adil Saeed Musthafa <adilm@qti.qualcomm.com>
Signed-off-by: Sai Pratyusha Magam <smagam@qti.qualcomm.com>
src/ap/sta_info.c
src/ap/wpa_auth.c
src/ap/wpa_auth.h

index 6670174cd4144bae4c9d80f55c4b54d12329d33c..6d2bd5f1ca65504a97e6a44f1d9c2a1bfc4b9ef6 100644 (file)
@@ -1280,8 +1280,9 @@ retry:
 }
 
 
-int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
-                   struct vlan_description *vlan_desc)
+static int ap_sta_set_vlan_helper(struct hostapd_data *hapd,
+                                 struct sta_info *sta,
+                                 struct vlan_description *vlan_desc)
 {
        struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL;
        struct hostapd_data *vlan_bss = hapd;
@@ -1392,7 +1393,41 @@ done:
 }
 
 
-int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
+int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+                   struct vlan_description *vlan_desc)
+{
+       int ret;
+#ifdef CONFIG_IEEE80211BE
+       size_t i;
+#endif /* CONFIG_IEEE80211BE */
+       struct hapd_interfaces *interfaces = hapd->iface->interfaces;
+
+       ret = ap_sta_set_vlan_helper(hapd, sta, vlan_desc);
+       if (ret)
+               return ret;
+#ifdef CONFIG_IEEE80211BE
+       for (i = 0; interfaces && i < interfaces->count; i++) {
+               struct sta_info *tmp_sta;
+               struct hostapd_data *tmp_hapd = interfaces->iface[i]->bss[0];
+
+               if (!tmp_hapd->conf->mld_ap ||
+                   hapd == tmp_hapd ||
+                   !hostapd_is_ml_partner(hapd, tmp_hapd))
+                       continue;
+
+               tmp_sta = ap_get_sta(tmp_hapd, sta->addr);
+               if (tmp_sta)
+                       ap_sta_set_vlan_helper(tmp_hapd, tmp_sta, vlan_desc);
+       }
+
+#endif /* CONFIG_IEEE80211BE */
+
+       return 0;
+}
+
+
+static int ap_sta_bind_vlan_helper(struct hostapd_data *hapd,
+                                  struct sta_info *sta)
 {
 #ifndef CONFIG_NO_VLAN
        const char *iface;
@@ -1464,7 +1499,8 @@ skip_counting:
                       HOSTAPD_LEVEL_DEBUG, "binding station to interface "
                       "'%s'", iface);
 
-       if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
+       if (wpa_auth_sta_set_vlan(sta->wpa_sm, hapd->wpa_auth,
+                                 sta->vlan_id) < 0)
                wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
 
        ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id,
@@ -1487,6 +1523,37 @@ done:
 }
 
 
+int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
+{
+       int ret;
+#ifdef CONFIG_IEEE80211BE
+       size_t i;
+#endif /* CONFIG_IEEE80211BE */
+       struct hapd_interfaces *interfaces = hapd->iface->interfaces;
+
+       ret = ap_sta_bind_vlan_helper(hapd, sta);
+       if (ret)
+               return ret;
+#ifdef CONFIG_IEEE80211BE
+       for (i = 0; interfaces && i < interfaces->count; i++) {
+               struct sta_info *tmp_sta;
+               struct hostapd_data *tmp_hapd = interfaces->iface[i]->bss[0];
+
+               if (!tmp_hapd->conf->mld_ap ||
+                   hapd == tmp_hapd ||
+                   !hostapd_is_ml_partner(hapd, tmp_hapd))
+                       continue;
+
+               tmp_sta = ap_get_sta(tmp_hapd, sta->addr);
+               if (tmp_sta)
+                       ap_sta_bind_vlan_helper(tmp_hapd, tmp_sta);
+       }
+#endif /* CONFIG_IEEE80211BE */
+
+       return 0;
+}
+
+
 void ap_sta_set_sa_query_timeout(struct hostapd_data *hapd,
                                 struct sta_info *sta, int value)
 {
index b4fd2d63e292c27c7c6e72d2127330ae1bf838d7..14ec2494d6d452ac1dfa55ef42f26c948a44e63f 100644 (file)
@@ -70,6 +70,8 @@ static void wpa_group_get(struct wpa_authenticator *wpa_auth,
                          struct wpa_group *group);
 static void wpa_group_put(struct wpa_authenticator *wpa_auth,
                          struct wpa_group *group);
+static void wpa_group_put_vlan(struct wpa_authenticator *wpa_auth,
+                              int vlan_id);
 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,
@@ -141,7 +143,7 @@ void wpa_release_link_auth_ref(struct wpa_state_machine *sm, u8 link_id,
                wpa_auth = link->wpa_auth;
                if (wpa_auth) {
                        link->wpa_auth = NULL;
-                       wpa_group_put(wpa_auth, wpa_auth->group);
+                       wpa_group_put_vlan(wpa_auth, sm->group->vlan_id);
                }
        }
 }
@@ -1135,7 +1137,7 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
                wpa_auth = sm->mld_links[link_id].wpa_auth;
                sm->mld_links[link_id].wpa_auth = NULL;
                sm->mld_links[link_id].valid = false;
-               wpa_group_put(wpa_auth, wpa_auth->group);
+               wpa_group_put_vlan(wpa_auth, sm->group->vlan_id);
        }
 #endif /* CONFIG_IEEE80211BE */
        wpa_group_put(sm->wpa_auth, sm->group);
@@ -4335,8 +4337,8 @@ void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
        u8 rsc[WPA_KEY_RSC_LEN];
 
        wpa_printf(MSG_DEBUG,
-                  "MLD: Get group key info: link_id=%u, IGTK=%u, BIGTK=%u",
-                  info->link_id, mgmt_frame_prot, beacon_prot);
+                  "MLD: Get group key info: link_id=%u, IGTK=%u, BIGTK=%u VLAN ID:%d",
+                  info->link_id, mgmt_frame_prot, beacon_prot, vlan_id);
 
        if (vlan_id)
                gsm = wpa_select_vlan_wpa_group(gsm, vlan_id);
@@ -7029,6 +7031,16 @@ static void wpa_group_put(struct wpa_authenticator *wpa_auth,
 }
 
 
+static void wpa_group_put_vlan(struct wpa_authenticator *wpa_auth,
+                              int vlan_id)
+{
+       struct wpa_group *vlan_group =
+               wpa_select_vlan_wpa_group(wpa_auth->group, vlan_id);
+
+       wpa_group_put(wpa_auth, vlan_group);
+}
+
+
 /*
  * Add a group that has its references counter set to zero. Caller needs to
  * call wpa_group_get() on the return value to mark the entry in use.
@@ -7146,14 +7158,15 @@ int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id)
 }
 
 
-int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
+int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm,
+                         struct wpa_authenticator *wpa_auth, int vlan_id)
 {
        struct wpa_group *group;
 
        if (!sm || !sm->wpa_auth)
                return 0;
 
-       group = sm->wpa_auth->group;
+       group = wpa_auth->group;
        while (group) {
                if (group->vlan_id == vlan_id)
                        break;
@@ -7161,11 +7174,19 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
        }
 
        if (!group) {
-               group = wpa_auth_add_group(sm->wpa_auth, vlan_id);
+               group = wpa_auth_add_group(wpa_auth, vlan_id);
                if (!group)
                        return -1;
        }
 
+#ifdef CONFIG_IEEE80211BE
+       if (sm->mld_assoc_link_id >= 0 &&
+           (sm->mld_assoc_link_id != wpa_auth->link_id)) {
+               wpa_group_get(wpa_auth, group);
+               return 0;
+       }
+#endif /* CONFIG_IEEE80211BE */
+
        if (sm->group == group)
                return 0;
 
index 6e40b250b1c248bbb0a81fc9a68eaf632677bdb2..d5494bb4b52567c5cf04a05a4c98b95af8e137d3 100644 (file)
@@ -554,7 +554,8 @@ void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
                              struct wpa_state_machine *sm,
                              struct wpa_authenticator *wpa_auth,
                              u8 *pmkid, u8 *pmk, size_t *pmk_len);
-int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
+int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm,
+                         struct wpa_authenticator *wpa_auth, int vlan_id);
 void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
                                  struct wpa_state_machine *sm, int ack);