From: Sai Pratyusha Magam Date: Mon, 8 Dec 2025 04:45:56 +0000 (+0530) Subject: VLAN: Group state machine data creation for partner AP MLD links X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=db4908d1c5d6bde34636f95176309db7aab7db5c;p=thirdparty%2Fhostap.git VLAN: Group state machine data creation for partner AP MLD links 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 Signed-off-by: Adil Saeed Musthafa Signed-off-by: Sai Pratyusha Magam --- diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index 6670174cd..6d2bd5f1c 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -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) { diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index b4fd2d63e..14ec2494d 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -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; diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 6e40b250b..d5494bb4b 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -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);