]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
VLAN: Use VLAN group keys for EAPOL frames and FT reassoc for MLO
authorMuna Sinada <muna.sinada@oss.qualcomm.com>
Mon, 9 Jun 2025 18:06:16 +0000 (11:06 -0700)
committerJouni Malinen <j@w1.fi>
Mon, 29 Sep 2025 19:46:24 +0000 (22:46 +0300)
When MLO Dynamic VLAN is enabled and non-AP MLDs in a VLAN group are
exchanging EAPOL messages, the AP MLD was 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 frame.

Signed-off-by: Muna Sinada <muna.sinada@oss.qualcomm.com>
Signed-off-by: Pradeep Kumar Chitrapu <quic_pradeepc@quicinc.com>
src/ap/drv_callbacks.c
src/ap/ieee802_11.c
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_ft.c
src/ap/wpa_auth_glue.c

index ca1210c87721abe77d1d28b477d8dc96e5567758..51badb7c16697df940a2d6b47cd34b88583bfaa5 100644 (file)
@@ -788,7 +788,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;
index d6ac425ab0ad8fd1e36fb3f18f24bab189574ab8..52547bfc02430480a11bd110fc17da3f345ce2ae 100644 (file)
@@ -5327,7 +5327,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");
index bc711f53d5bbfa10128bcbe2b7fe11d5f8d9d485..625b99969d60544d71c459227175fcd69f3e0148 100644 (file)
@@ -4296,7 +4296,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];
@@ -4305,6 +4305,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;
@@ -4346,12 +4349,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);
 }
 
 
@@ -4435,7 +4438,8 @@ 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++) {
@@ -7697,3 +7701,34 @@ void wpa_reset_assoc_sm_info(struct wpa_state_machine *assoc_sm,
        assoc_sm->mld_assoc_link_id = mld_assoc_link_id;
 #endif /* CONFIG_IEEE80211BE */
 }
+
+
+#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 used to search the group key state machine data that
+ *          corresponds to the specified VLAN group
+ * Returns: Pointer to wpa_group that corresponds to the VLAN group on success,
+ *         or pointer to the 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, "%s: VLAN group not found", __func__);
+               vlan_gsm = gsm;
+       }
+
+       return vlan_gsm;
+}
+#endif /* CONFIG_IEEE80211BE */
index 7b82b0881f1a92f499400a89716f90e258fc8c68..47a24895736a25e2f3d09ecb312cc4ca3d573892 100644 (file)
@@ -429,7 +429,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);
@@ -556,7 +556,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, bool 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,
@@ -684,7 +684,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);
@@ -712,5 +712,7 @@ 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);
+struct wpa_group * wpa_select_vlan_wpa_group(struct wpa_group *gsm,
+                                            int vlan_id);
 
 #endif /* WPA_AUTH_H */
index d5400a9f77d3a63dc18e5306b1008455a0465115..759871c27ca27824b0b66592c58de9fd46c0d839 100644 (file)
@@ -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,
+                              bool 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, bool 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");
index ca9d67df885d55e532454c9e3f13b0c18cb97c13..fc47b381b83275a041dc0caede1a51699ce72819 100644 (file)
@@ -1598,7 +1598,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;
@@ -1623,7 +1623,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;
                }
 
@@ -1635,7 +1635,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;
                }