]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
BSS: Verify the ML common info for links
authorBenjamin Berg <benjamin.berg@intel.com>
Wed, 18 Jun 2025 12:35:28 +0000 (14:35 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 2 Oct 2025 17:35:44 +0000 (20:35 +0300)
Add a check that the AP MLD MAC address, the link ID, the MLD
Capabilities and Operations, the Extended MLD Capabilities as well as
the EML Capabilities match between links. If this is not the case,
refuse to use the offending link.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
src/common/ieee802_11_defs.h
wpa_supplicant/bss.c
wpa_supplicant/bss.h

index 278e03c342b0c766ed235711a5eb63910c0906e6..d1e0e86c2dff86cc56043461dd1ca31465ad6bc8 100644 (file)
@@ -2866,6 +2866,7 @@ struct eht_ml_basic_common_info {
 #define EHT_ML_EML_CAPA_EMLMR_SUPP               0x0080
 #define EHT_ML_EML_CAPA_EMLMR_DELAY_MASK         0x0700
 #define EHT_ML_EML_CAPA_TRANSITION_TIMEOUT_MASK  0x7800
+#define EHT_ML_EML_CAPA_RESERVED                 0x8780
 
 #define EHT_ML_MLD_CAPA_MAX_NUM_SIM_LINKS_MASK        0x000f
 #define EHT_ML_MLD_CAPA_SRS_SUPP                      0x0010
@@ -2876,6 +2877,8 @@ struct eht_ml_basic_common_info {
 #define EHT_ML_MLD_CAPA_FREQ_SEP_FOR_STR_MASK         0x0f80
 #define EHT_ML_MLD_CAPA_AAR_SUPP                      0x1000
 #define EHT_ML_MLD_CAPA_LINK_RECONF_OP_SUPPORT        0x2000
+#define EHT_ML_MLD_CAPA_ALIGNED_TWT_SUPPORT           0x4000
+#define EHT_ML_MLD_CAPA_RESERVED                      0x8000
 
 #define EHT_ML_EXT_MLD_CAPA_OP_PARAM_UPDATE           0x0001
 #define EHT_ML_EXT_MLD_CAPA_OP_RECO_MAX_LINKS_MASK    0x001e
index c778973d6ab27035cff6ae2abadf4fdaf969426c..7b58a229d427998ebf7f95abe5ddf951e29c3783 100644 (file)
@@ -1788,6 +1788,7 @@ u16 wpa_bss_get_usable_links(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 
        for_each_link(bss->valid_links, link_id) {
                struct wpa_bss *neigh_bss;
+               u16 ext_mld_capa_mask;
 
                if (link_id == bss->mld_link_id)
                        continue;
@@ -1807,6 +1808,65 @@ u16 wpa_bss_get_usable_links(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                        continue;
                }
 
+               /* Check that the affiliated links are for the same AP MLD and
+                * the information matches */
+               if (!neigh_bss->valid_links) {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "MLD: Neighbor without Multi-Link support");
+                       continue;
+               }
+
+               if (neigh_bss->mld_link_id != link_id) {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "MLD: Neighbor has unexpected link ID (%d != %d)",
+                               neigh_bss->mld_link_id, link_id);
+                       continue;
+               }
+
+               if (!ether_addr_equal(bss->mld_addr, neigh_bss->mld_addr)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "MLD: Neighbor has a different MLD MAC address ("
+                               MACSTR " != " MACSTR ")",
+                               MAC2STR(neigh_bss->mld_addr),
+                               MAC2STR(bss->mld_addr));
+                       continue;
+               }
+
+               if ((bss->mld_capa & ~EHT_ML_MLD_CAPA_RESERVED) !=
+                   (neigh_bss->mld_capa & ~EHT_ML_MLD_CAPA_RESERVED)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "MLD: Neighbor's MLD Capabilities do not match (0x%04x != 0x%04x)",
+                               neigh_bss->mld_capa, bss->mld_capa);
+                       continue;
+               }
+
+               if ((bss->eml_capa & ~EHT_ML_EML_CAPA_RESERVED) !=
+                   (neigh_bss->eml_capa & ~EHT_ML_EML_CAPA_RESERVED)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "MLD: Neighbor's EML Capabilities do not match (0x%04x != 0x%04x",
+                               neigh_bss->eml_capa, bss->eml_capa);
+                       continue;
+               }
+
+               /*
+                * Check well-defined values in Extended MLD Capabilities.
+                * In particular the Recommended Max Simultaneous Links
+                * subfield may change over time and is reserved depending on
+                * the frame that it is carried in.
+                * See IEEE Std 802.11be-2024, Table 9-417o.
+                */
+               ext_mld_capa_mask =
+                       EHT_ML_EXT_MLD_CAPA_OP_PARAM_UPDATE |
+                       EHT_ML_EXT_MLD_CAPA_NSTR_UPDATE |
+                       EHT_ML_EXT_MLD_CAPA_EMLSR_ENA_ONE_LINK;
+               if ((bss->ext_mld_capa & ext_mld_capa_mask) !=
+                   (neigh_bss->ext_mld_capa & ext_mld_capa_mask)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "MLD: Neighbors Extended MLD Capabilities do not match (0x%04x != 0x%04x)",
+                               neigh_bss->ext_mld_capa, bss->ext_mld_capa);
+                       continue;
+               }
+
                if (ssid) {
                        int neigh_key_mgmt;
 
@@ -1915,17 +1975,29 @@ void wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
            sizeof(*ml_basic_common_info) + 1 + 1 + 2)
                goto out;
 
-       /* LINK_ID, BSS_PARAM_CH_COUNT, MLD_CAPA (see control/control_mask) */
+       /* Link ID Info, BSS Parameters Change Count (see control/control_mask)
+        */
        link_id = ml_basic_common_info->variable[0] & EHT_ML_LINK_ID_MSK;
-       pos = 1 + 1 + 2;
+       pos = 1 + 1;
 
+       /* Medium Synchronization Delay Information */
        if (le_to_host16(eht_ml->ml_control) &
            BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO)
                pos += 2;
 
+       /* EML Capabilities */
+       bss->eml_capa = 0;
        if (le_to_host16(eht_ml->ml_control) &
-           BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA)
+           BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) {
+               bss->eml_capa =
+                       WPA_GET_LE16(&ml_basic_common_info->variable[pos]);
                pos += 2;
+       }
+
+       /* MLD Capabilities And Operations (always present, see
+        * control/control_mask) */
+       bss->mld_capa = WPA_GET_LE16(&ml_basic_common_info->variable[pos]);
+       pos += 2;
 
        /* AP MLD ID from MLE if present (see comment below) */
        if (le_to_host16(eht_ml->ml_control) &
@@ -1941,6 +2013,20 @@ void wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
                ap_mld_id = 0;
        }
 
+       /* Extended MLD Capabilities And Operations */
+       bss->ext_mld_capa = 0;
+       if (le_to_host16(eht_ml->ml_control) &
+           BASIC_MULTI_LINK_CTRL_PRES_EXT_MLD_CAP) {
+               if (ml_basic_common_info->len <
+                   sizeof(*ml_basic_common_info) + pos + 2)
+                       goto out;
+
+               bss->ext_mld_capa =
+                       WPA_GET_LE16(&ml_basic_common_info->variable[pos]);
+
+               pos += 2;
+       }
+
        if (ml_basic_common_info->len < sizeof(*ml_basic_common_info) + pos)
                goto out;
 
index 77b7d0a3c18b38772244a3c24f67fdce41f8b888..d9d0401cef32e1f62937fc173f11a9920f0bb16a 100644 (file)
@@ -128,6 +128,12 @@ struct wpa_bss {
        /** For MLD, denotes whether the BSS is a non-transmitted one; useful
         * for ML probe */
        bool mld_bss_non_transmitted;
+       /** MLD Capabilities And Operations */
+       u16 mld_capa;
+       /** Extended MLD Capabilities And Operations */
+       u16 ext_mld_capa;
+       /** EML Capabilities */
+       u16 eml_capa;
 
        /** An array of MLD links, any link found in the RNR is "valid" */
        u16 valid_links;