[PATCH 3/3] SME: MLD: Handle reconfiguration Multi-Link element

Andrei Otcheretianski andrei.otcheretianski at intel.com
Mon Jun 12 12:59:50 PDT 2023


Parse the reconfiguration Multi-Link element and:

- Don't select a BSS for connection if it is part of an MLD
  and is going to be removed.
- Don't scan for missing links that are to be removed.
- Don't include removed links in association.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
 src/common/ieee802_11_defs.h |  9 ++++
 wpa_supplicant/bss.c         | 80 ++++++++++++++++++++++++++++++++++++
 wpa_supplicant/bss.h         |  2 +
 wpa_supplicant/events.c      | 36 +++++++++++++++-
 wpa_supplicant/sme.c         | 10 +++++
 5 files changed, 136 insertions(+), 1 deletion(-)

diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index e36f6db139..a93d5e742d 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -2674,6 +2674,15 @@ struct eht_ml_basic_common_info {
 #define EHT_PER_STA_CTRL_NSTR_BM_SIZE_MSK             0x0400
 #define EHT_PER_STA_CTRL_BSS_PARAM_CNT_PRESENT_MSK    0x0800
 
+#define RECONF_MULTI_LINK_CTRL_PRES_MLD_MAC_ADDR   0x0001
+
+#define EHT_PER_STA_RECONF_CTRL_LINK_ID_MSK        0x000f
+#define EHT_PER_STA_RECONF_CTRL_COMPLETE_PROFILE   0x0010
+#define EHT_PER_STA_RECONF_CTRL_MAC_ADDR           0x0020
+#define EHT_PER_STA_RECONF_CTRL_AP_REMOVAL_TIMER   0x0040
+#define EHT_PER_STA_RECONF_CTRL_OP_UPDATE_TYPE_MSK 0x0780
+#define EHT_PER_STA_RECONF_CTRL_OP_PARAMS          0x0800
+
 /* IEEE P802.11be/D2.0, 9.4.2.312.2.4 - Per-STA Profile subelement format */
 struct ieee80211_eht_per_sta_profile {
 	le16 sta_control;
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 1aa490bcbc..9d3f0fe308 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -1697,3 +1697,83 @@ out:
 	wpabuf_free(mlbuf);
 	return ret;
 }
+
+
+/*
+ * wpa_bss_parse_reconf_ml_element - Parse the reconfiguration ML element
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bss: BSS table entry
+ * Returns: The bitmap of links that are going to be removed
+ */
+u16 wpa_bss_parse_reconf_ml_element(struct wpa_supplicant *wpa_s,
+				    struct wpa_bss *bss)
+{
+	struct ieee802_11_elems elems;
+	struct wpabuf *mlbuf;
+	const u8 *pos = wpa_bss_ie_ptr(bss);
+	size_t len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+	struct ieee80211_eht_ml *ml;
+	u16 removed_links = 0;
+	u8 ml_common_len;
+
+	if (ieee802_11_parse_elems(pos, len, &elems, 1) == ParseFailed)
+		return 0;
+
+	if (!elems.reconf_mle || !elems.reconf_mle_len)
+		return 0;
+
+	mlbuf = ieee802_11_defrag_mle(&elems, MULTI_LINK_CONTROL_TYPE_RECONF);
+	if (!mlbuf)
+		return 0;
+
+	ml = (struct ieee80211_eht_ml *)wpabuf_head(mlbuf);
+	len = wpabuf_len(mlbuf);
+
+	if (len < sizeof(*ml))
+		goto out;
+
+	ml_common_len = 1;
+	if (ml->ml_control & RECONF_MULTI_LINK_CTRL_PRES_MLD_MAC_ADDR)
+		ml_common_len += ETH_ALEN;
+
+	if (len < sizeof(*ml) + ml_common_len) {
+		wpa_printf(MSG_DEBUG,
+			   "MLD: unexpected reconf ML element length: (%zu != %zu)",
+			   len, sizeof(*ml) + ml_common_len);
+		goto out;
+	}
+
+	pos = ml->variable + ml_common_len;
+	len -= sizeof(*ml) + ml_common_len;
+
+	while (len >= 2 + sizeof(struct ieee80211_eht_per_sta_profile)) {
+		size_t sub_elem_len = *(pos + 1);
+
+		if (2 + sub_elem_len > len) {
+			wpa_printf(MSG_DEBUG,
+				   "MLD: invalid link info len: %zu %zu",
+				   2 + sub_elem_len, len);
+			goto out;
+		}
+
+		if  (*pos == EHT_ML_SUB_ELEM_PER_STA_PROFILE) {
+			struct ieee80211_eht_per_sta_profile *sta_prof =
+				(struct ieee80211_eht_per_sta_profile *)
+				(pos + 2);
+			u16 control = le_to_host16(sta_prof->sta_control);
+			u8 link_id = control &
+				EHT_PER_STA_RECONF_CTRL_LINK_ID_MSK;
+
+			removed_links |= BIT(link_id);
+		}
+
+		pos += 2 + sub_elem_len;
+		len -= 2 + sub_elem_len;
+	}
+
+	wpa_printf(MSG_DEBUG, "MLD: reconfiguration: removed_links=0x%x",
+		   removed_links);
+out:
+	wpabuf_free(mlbuf);
+	return removed_links;
+}
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 291f02b912..b93a5eea46 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -215,4 +215,6 @@ int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
 				   struct wpa_bss *bss,
 				   u8 *ap_mld_addr,
 				   u16 *missing_links);
+u16 wpa_bss_parse_reconf_ml_element(struct wpa_supplicant *wpa_s,
+				    struct wpa_bss *bss);
 #endif /* BSS_H */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index b666d7b202..b8e59c727d 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1176,6 +1176,27 @@ static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 }
 
 
+static int wpas_valid_ml_bss(struct wpa_supplicant *wpa_s,
+			     struct wpa_bss *bss)
+
+{
+	u16 removed_links;
+
+	if (wpa_bss_parse_basic_ml_element(wpa_s, bss, NULL, NULL))
+		return 0;
+
+	if (bss->n_mld_links == 0)
+		return 0;
+
+	/* Check if the current BSS is going to be removed */
+	removed_links = wpa_bss_parse_reconf_ml_element(wpa_s, bss);
+	if (BIT(bss->mld_links[0].link_id) & removed_links)
+		return -1;
+
+	return 0;
+}
+
+
 int disabled_freq(struct wpa_supplicant *wpa_s, int freq)
 {
 	int i, j;
@@ -1578,6 +1599,13 @@ skip_assoc_disallow:
 		return false;
 	}
 
+	if (wpas_valid_ml_bss(wpa_s, bss) < 0) {
+		if (debug_print)
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"   skip - ML BSS going to be removed");
+		return false;
+	}
+
 	/* Matching configuration found */
 	return true;
 }
@@ -1856,7 +1884,7 @@ static int wpa_supplicant_connect_ml_missing(struct wpa_supplicant *wpa_s,
 					     struct wpa_ssid *ssid)
 {
 	int *freqs;
-	u16 missing_links = 0;
+	u16 missing_links = 0, removed_links;
 
 	if (!((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) &&
 	      (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)))
@@ -1867,6 +1895,12 @@ static int wpa_supplicant_connect_ml_missing(struct wpa_supplicant *wpa_s,
 					   &missing_links) || !missing_links)
 		return 0;
 
+	removed_links = wpa_bss_parse_reconf_ml_element(wpa_s, selected);
+	missing_links &= ~removed_links;
+
+	if (!missing_links)
+		return 0;
+
 	wpa_dbg(wpa_s, MSG_DEBUG,
 		"MLD: Doing an ML probe for missing links 0x%04x",
 		missing_links);
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 4ed0a3003f..1acd415bc5 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -541,6 +541,15 @@ out:
 }
 
 
+static void wpas_ml_handle_removed_links(struct wpa_supplicant *wpa_s,
+					 struct wpa_bss *bss)
+{
+	u16 removed_links = wpa_bss_parse_reconf_ml_element(wpa_s, bss);
+
+	wpa_s->valid_links &= ~removed_links;
+}
+
+
 static void wpas_sme_ml_auth(struct wpa_supplicant *wpa_s,
 			     union wpa_event_data *data,
 			     int ie_offset)
@@ -639,6 +648,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
 		params.mld = true;
 		params.mld_link_id = wpa_s->mlo_assoc_link_id;
 		params.ap_mld_addr = wpa_s->ap_mld_addr;
+		wpas_ml_handle_removed_links(wpa_s, bss);
 	}
 
 	if (wpa_s->sme.ssid_len != params.ssid_len ||
-- 
2.38.1




More information about the Hostap mailing list