diff mbox series

[6/9] BSS: Verify the ML common info for links

Message ID 20250618123531.962016-6-benjamin@sipsolutions.net
State Accepted
Headers show
Series [1/9] BSS: use correct AP MLD ID | expand

Commit Message

Benjamin Berg June 18, 2025, 12:35 p.m. UTC
From: Benjamin Berg <benjamin.berg@intel.com>

Add a check that the AP MLD ADDR, 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, then refuse to use the offending link.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
---
 wpa_supplicant/bss.c | 78 ++++++++++++++++++++++++++++++++++++++++++--
 wpa_supplicant/bss.h |  6 ++++
 2 files changed, 81 insertions(+), 3 deletions(-)

Comments

Jouni Malinen Oct. 2, 2025, 6:04 p.m. UTC | #1
On Wed, Jun 18, 2025 at 02:35:28PM +0200, Benjamin Berg wrote:
> Add a check that the AP MLD ADDR, 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, then refuse to use the offending link.

> diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c

> +		if (bss->mld_capa != neigh_bss->mld_capa) {
> +			wpa_dbg(wpa_s, MSG_DEBUG,
> +				"MLD: neighbors MLD Capabilities are not matching");
> +			continue;
> +		}
> +
> +		if (bss->eml_capa != neigh_bss->eml_capa) {
> +			wpa_dbg(wpa_s, MSG_DEBUG,
> +				"MLD: neighbors EML Capabilities are not matching");
> +			continue;
> +		}

These are excessive checks since there are reserved bits in those fields
and it does not seem reasonable to mandate reserved, i.e., currently
undefined, bits to have any particular value. The receiver is expected
to discard those reserved bits completely.

> +		/*
> +		 * 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.

This one on the other hand is already addressing such concerns and even
doing that for some of the defined bits.
diff mbox series

Patch

diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index b5b6305f13..ce250655a5 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -1790,6 +1790,7 @@  u16 wpa_bss_get_usable_links(struct wpa_supplicant *wpa_s,
 
 	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;
@@ -1809,6 +1810,55 @@  u16 wpa_bss_get_usable_links(struct wpa_supplicant *wpa_s,
 			continue;
 		}
 
+		/* Check that the links is 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");
+			continue;
+		}
+
+		if (!ether_addr_equal(bss->mld_addr, neigh_bss->mld_addr)) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"MLD: neighbor has a different MLD addr");
+			continue;
+		}
+
+		if (bss->mld_capa != neigh_bss->mld_capa) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"MLD: neighbors MLD Capabilities are not matching");
+			continue;
+		}
+
+		if (bss->eml_capa != neigh_bss->eml_capa) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"MLD: neighbors EML Capabilities are not matching");
+			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 P802.11be/D7.0, 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 are not matching");
+			continue;
+		}
+
 		if (ssid) {
 			int neigh_key_mgmt;
 
@@ -1921,17 +1971,25 @@  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, BSS_PARAM_CH_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;
 
 	if (le_to_host16(eht_ml->ml_control) &
 	    BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO)
 		pos += 2;
 
+	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_CAPA (always present, see control/control_mask) */
+	bss->mld_capa = WPA_GET_LE16(&ml_basic_common_info->variable[pos]);
+	pos += 2;
 
 	/* AP MLD ID from ML-Element if present (see comment below) */
 	if (le_to_host16(eht_ml->ml_control) &
@@ -1947,6 +2005,20 @@  void wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
 		ap_mld_id = 0;
 	}
 
+	/* Extended MLD Capabilities */
+	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;
 
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 4bd752fda2..8a86489a04 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -127,6 +127,12 @@  struct wpa_bss {
 	u8 mld_link_id;
 	/** For MLD, denotes if BSS is non-TX; 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;