[PATCH RFC v3 2/2] wpa_auth: Use VLAN group keys for EAPOL frames and FT reassoc

Muna Sinada muna.sinada at oss.qualcomm.com
Thu May 8 17:13:07 PDT 2025


When MLO Dynamic VLAN is enabled and non-APs in a VLAN group are
exchanging EAPOL messages, the AP is providing the primary
authenticator's GTKs instead of the VLAN's GTKs. This results in STAs
being unable to decrypt the VLAN's multicast frames due to incorrect
keys.

In wpa_auth_ml_get_key_info(), if vlan_id is provided, traverse
through the wpa_group list and select the one that matches the
vlan_id. From the matched wpa_group, the correct GTKs are taken.

Similarly in the case of FT + MLO + Dynamic VLAN, handle selecting VLAN's
wpa_group for the FT protocol Reassociation Response.

Signed-off-by: Muna Sinada <muna.sinada at oss.qualcomm.com>
Signed-off-by: Pradeep Kumar Chitrapu <quic_pradeepc at quicinc.com>

---
v3: rebase to TOT

v2:
 - add description for wpa_select_vlan_wpa_group()
 - move wpa_select_vlan_wpa_group() into CONFIG_IEEE80211BE block

---
 src/ap/drv_callbacks.c |  2 +-
 src/ap/ieee802_11.c    |  3 ++-
 src/ap/wpa_auth.c      | 42 ++++++++++++++++++++++++++++++++++++++----
 src/ap/wpa_auth.h      | 10 +++++++---
 src/ap/wpa_auth_ft.c   | 13 ++++++++++---
 src/ap/wpa_auth_glue.c |  6 +++---
 6 files changed, 61 insertions(+), 15 deletions(-)

diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index f3aeb2236617..7518c83cffe2 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -744,7 +744,7 @@ skip_wpa_check:
 #ifdef CONFIG_IEEE80211R_AP
 	p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
 					sta->auth_alg, req_ies, req_ies_len,
-					!elems.rsnxe);
+					!elems.rsnxe, reassoc, sta->vlan_id);
 	if (!p) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 36f44b6b3335..e8371db48dd7 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -5197,7 +5197,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 		p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
 						buf + buflen - p,
 						sta->auth_alg, ies, ies_len,
-						omit_rsnxe);
+						omit_rsnxe, reassoc,
+						sta->vlan_id);
 		if (!p) {
 			wpa_printf(MSG_DEBUG,
 				   "FT: Failed to write AssocResp IEs");
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index f2330bc9d4b4..860fbcc578ed 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -4289,7 +4289,7 @@ static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid,
 void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
 			      struct wpa_auth_ml_link_key_info *info,
 			      bool mgmt_frame_prot, bool beacon_prot,
-			      bool rekey)
+			      bool rekey, int vlan_id)
 {
 	struct wpa_group *gsm = a->group;
 	u8 rsc[WPA_KEY_RSC_LEN];
@@ -4298,6 +4298,9 @@ void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
 		   "MLD: Get group key info: link_id=%u, IGTK=%u, BIGTK=%u",
 		   info->link_id, mgmt_frame_prot, beacon_prot);
 
+	if (vlan_id)
+		gsm = wpa_select_vlan_wpa_group(gsm, vlan_id);
+
 	info->gtkidx = gsm->GN & 0x03;
 	info->gtk = gsm->GTK[gsm->GN - 1];
 	info->gtk_len = gsm->GTK_len;
@@ -4339,12 +4342,12 @@ void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
 
 static void wpa_auth_get_ml_key_info(struct wpa_authenticator *wpa_auth,
 				     struct wpa_auth_ml_key_info *info,
-				     bool rekey)
+				     bool rekey, int vlan_id)
 {
 	if (!wpa_auth->cb->get_ml_key_info)
 		return;
 
-	wpa_auth->cb->get_ml_key_info(wpa_auth->cb_ctx, info, rekey);
+	wpa_auth->cb->get_ml_key_info(wpa_auth->cb_ctx, info, rekey, vlan_id);
 }
 
 
@@ -4429,7 +4432,8 @@ static u8 * wpa_auth_ml_group_kdes(struct wpa_state_machine *sm, u8 *pos,
 	}
 	ml_key_info.n_mld_links = i;
 
-	wpa_auth_get_ml_key_info(sm->wpa_auth, &ml_key_info, rekey);
+	wpa_auth_get_ml_key_info(sm->wpa_auth, &ml_key_info, rekey,
+				 sm->group->vlan_id);
 
 	/* Add MLO GTK KDEs */
 	for (i = 0; i < ml_key_info.n_mld_links; i++) {
@@ -7676,3 +7680,33 @@ bool wpa_auth_sm_known_sta_identification(struct wpa_state_machine *sm,
 
 	return true;
 }
+#ifdef CONFIG_IEEE80211BE
+
+/* wpa_select_vlan_wpa_group - Traverse through the wpa_group list and select
+ * the one that matches the vlan_id.
+ *
+ * @gsm: head of wpa_group list
+ * @vlan_id: vlan_id utilized to search to the group key state machine data that
+ *	     corresponds to that vlan group
+ * Returns: pointer to wpa_group that corresponds to the vlan group on success,
+ *	    pointer to head of wpa_group list that was passed in
+ */
+struct wpa_group * wpa_select_vlan_wpa_group(struct wpa_group *gsm, int vlan_id)
+{
+	struct wpa_group *vlan_gsm = gsm;
+
+	while (vlan_gsm) {
+		if (vlan_gsm->vlan_id == vlan_id)
+			break;
+
+		vlan_gsm = vlan_gsm->next;
+	}
+
+	if (!vlan_gsm) {
+		wpa_printf(MSG_DEBUG, "vlan group not found");
+		vlan_gsm = gsm;
+	}
+
+	return vlan_gsm;
+}
+#endif /* CONFIG_IEEE80211BE */
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index c412633cd719..c3e214eaff13 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -427,7 +427,7 @@ struct wpa_auth_callbacks {
 #endif /* CONFIG_PASN */
 #ifdef CONFIG_IEEE80211BE
 	int (*get_ml_key_info)(void *ctx, struct wpa_auth_ml_key_info *info,
-			       bool rekey);
+			       bool rekey, int vlan_id);
 	struct wpa_authenticator * (*next_primary_auth)(void *ctx);
 #endif /* CONFIG_IEEE80211BE */
 	int (*get_drv_flags)(void *ctx, u64 *drv_flags, u64 *drv_flags2);
@@ -553,7 +553,7 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
 u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 				 size_t max_len, int auth_alg,
 				 const u8 *req_ies, size_t req_ies_len,
-				 int omit_rsnxe);
+				 int omit_rsnxe, int reassoc, int vlan_id);
 void wpa_ft_process_auth(struct wpa_state_machine *sm,
 			 u16 auth_transaction, const u8 *ies, size_t ies_len,
 			 void (*cb)(void *ctx, const u8 *dst,
@@ -681,7 +681,7 @@ void wpa_auth_set_ml_info(struct wpa_state_machine *sm,
 void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
 			      struct wpa_auth_ml_link_key_info *info,
 			      bool mgmt_frame_prot, bool beacon_prot,
-			      bool rekey);
+			      bool rekey, int vlan_id);
 
 void wpa_release_link_auth_ref(struct wpa_state_machine *sm, u8 link_id,
 			       bool rejected);
@@ -702,5 +702,9 @@ static inline bool wpa_auth_pmf_enabled(struct wpa_auth_config *conf)
 bool wpa_auth_sm_known_sta_identification(struct wpa_state_machine *sm,
 					  const u8 *timestamp,
 					  const u8 *mic, size_t mic_len);
+#ifdef CONFIG_IEEE80211BE
+struct wpa_group * wpa_select_vlan_wpa_group(struct wpa_group *gsm,
+					     int vlan_id);
+#endif /* CONFIG_IEEE80211BE */
 
 #endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index d5400a9f77d3..912bb7862e61 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2212,7 +2212,8 @@ static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
 }
 
 
-static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
+static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len,
+			       int reassoc, int vlan_id)
 {
 	u8 *subelem;
 	struct wpa_auth_config *conf = &sm->wpa_auth->conf;
@@ -2224,6 +2225,11 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
 	const u8 *kek;
 	size_t kek_len;
 
+#ifdef CONFIG_IEEE80211BE
+	if (reassoc && vlan_id)
+		gsm = wpa_select_vlan_wpa_group(gsm, vlan_id);
+#endif /* CONFIG_IEEE80211BE */
+
 	if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
 		kek = sm->PTK.kek2;
 		kek_len = sm->PTK.kek2_len;
@@ -2545,7 +2551,7 @@ static u8 * wpa_ft_process_ric(struct wpa_state_machine *sm, u8 *pos, u8 *end,
 u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 				 size_t max_len, int auth_alg,
 				 const u8 *req_ies, size_t req_ies_len,
-				 int omit_rsnxe)
+				 int omit_rsnxe, int reassoc, int vlan_id)
 {
 	u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
 	u8 *fte_mic, *elem_count;
@@ -2635,7 +2641,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 
 	/* Fast BSS Transition Information */
 	if (auth_alg == WLAN_AUTH_FT) {
-		subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
+		subelem = wpa_ft_gtk_subelem(sm, &subelem_len, reassoc,
+					     vlan_id);
 		if (!subelem) {
 			wpa_printf(MSG_DEBUG,
 				   "FT: Failed to add GTK subelement");
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index f4653f34e2ff..e35019924609 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -1590,7 +1590,7 @@ static int hostapd_set_ltf_keyseed(void *ctx, const u8 *peer_addr,
 
 static int hostapd_wpa_auth_get_ml_key_info(void *ctx,
 					    struct wpa_auth_ml_key_info *info,
-					    bool rekey)
+					    bool rekey, int vlan_id)
 {
 	struct hostapd_data *hapd = ctx;
 	unsigned int i;
@@ -1615,7 +1615,7 @@ static int hostapd_wpa_auth_get_ml_key_info(void *ctx,
 						 &info->links[i],
 						 info->mgmt_frame_prot,
 						 info->beacon_prot,
-						 rekey);
+						 rekey, vlan_id);
 			continue;
 		}
 
@@ -1627,7 +1627,7 @@ static int hostapd_wpa_auth_get_ml_key_info(void *ctx,
 						 &info->links[i],
 						 info->mgmt_frame_prot,
 						 info->beacon_prot,
-						 rekey);
+						 rekey, vlan_id);
 			link_bss_found = true;
 			break;
 		}
-- 
2.34.1




More information about the Hostap mailing list