[RFC 11/30] BSS: Parse SMD Information Element and store the data

Ilan Peer ilan.peer at intel.com
Wed Oct 21 06:43:29 PDT 2026


Add support for parsing an SMD Information Element, and
store the SMD Identifier and PTK mode as part of the
BSS object.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/common/ieee802_11_common.c | 28 ++++++++++++++++++
 src/common/ieee802_11_common.h |  1 +
 wpa_supplicant/bss.c           | 53 ++++++++++++++++++++++++++++++++++
 wpa_supplicant/bss.h           |  9 ++++++
 4 files changed, 91 insertions(+)

diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index f7076f7923df..dcb93ce7221e 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -3369,6 +3369,34 @@ bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab)
 }
 
 
+/**
+ * ieee802_11_sec_prof_rsnx_capab - Check an Extended RSN Capability in the
+ *	Extended RSN Capabilities field of a Security Profile element
+ *
+ * @sp: Security Profile element (including the element header) or %NULL
+ * @capab: Extended RSN Capability (WLAN_RSNX_CAPAB_*) to check
+ * Returns: Whether the capability is indicated
+ */
+bool ieee802_11_sec_prof_rsnx_capab(const u8 *sp, unsigned int capab)
+{
+	size_t offset;
+	u8 bitmap_len, num_vendor;
+
+	if (!sp || sp[1] < 3)
+		return false;
+
+	bitmap_len = sp[4] & 0x0f;
+	num_vendor = (sp[4] & 0xf0) >> 4;
+	offset = 5 + bitmap_len + 4 * num_vendor;
+
+	if ((size_t) sp[1] + 2 <= offset)
+		return false;
+
+	return ieee802_11_rsnx_capab_len(sp + offset, sp[1] + 2 - offset,
+					 capab);
+}
+
+
 void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
 			      int primary_channel,
 			      struct ieee80211_edmg_config *edmg)
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 81e04a04d9a5..ed9d227bc2c2 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -388,6 +388,7 @@ int ieee802_11_ext_capab(const u8 *ie, unsigned int capab);
 bool ieee802_11_rsnx_capab_len(const u8 *rsnxe, size_t rsnxe_len,
 			       unsigned int capab);
 bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab);
+bool ieee802_11_sec_prof_rsnx_capab(const u8 *sp, unsigned int capab);
 int op_class_to_bandwidth(u8 op_class);
 enum oper_chan_width op_class_to_ch_width(u8 op_class);
 int chwidth_freq2_to_ch_width(int chwidth, int freq2);
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 3f8b46e1da9f..7dd3a3422924 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -583,6 +583,58 @@ static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
 }
 
 
+static void wpa_bss_parse_smd_info(struct wpa_bss *bss)
+{
+	const u8 *ie, *sp;
+	const struct ieee80211_smd_info *smd;
+
+	os_memset(bss->smd_id, 0, ETH_ALEN);
+	bss->smd_per_ap_mld_ptk_mode = false;
+	bss->smd_max_prep_targets = 0;
+
+	if (!(bss->mld_capa & EHT_ML_MLD_CAPA_LINK_RECONF_OP_SUPPORT)) {
+		wpa_printf(MSG_DEBUG,
+			   "BSS=" MACSTR " doesn't support Link Reconfiguration Operation. mld_capa=0x%x",
+			   MAC2STR(bss->bssid), bss->mld_capa);
+		return;
+	}
+
+	/*
+	 * An AP indicates SMD support only in the Extended RSN Capabilities
+	 * field of the Security Profile element.
+	 */
+	sp = wpa_bss_get_ie_ext(bss, WLAN_EID_EXT_SECURITY_PROFILE);
+	if (!ieee802_11_sec_prof_rsnx_capab(sp, WLAN_RSNX_CAPAB_SMD)) {
+		wpa_printf(MSG_DEBUG,
+			   "BSS=" MACSTR " doesn't support SMD in Security Profile element",
+			   MAC2STR(bss->bssid));
+		return;
+	}
+
+	ie = wpa_bss_get_ie_ext(bss, WLAN_EID_EXT_SMD_INFO);
+	if (!ie || ie[1] < 1 + sizeof(*smd))
+		return;
+
+	smd = (const struct ieee80211_smd_info *)(ie + 3);
+	os_memcpy(bss->smd_id, smd->smd_id, ETH_ALEN);
+	bss->smd_per_ap_mld_ptk_mode =
+		!!(smd->smd_capabilities & SMD_CAPA_PER_AP_MLD_PTK_MODE);
+
+	/* Get the maximal allowed prepared targets */
+	bss->smd_max_prep_targets =
+		((smd->smd_capabilities &
+		  SMD_CAPA_MAX_PREP_TARGET_AP_MLDS_MASK) >>
+		 SMD_CAPA_MAX_PREP_TARGET_AP_MLDS_POS) + 1;
+
+	wpa_printf(MSG_DEBUG,
+		   "BSS=" MACSTR " in SMD: ID=" MACSTR
+		   ", PTK mode=%s, max prepared targets=%u",
+		   MAC2STR(bss->bssid), MAC2STR(bss->smd_id),
+		   bss->smd_per_ap_mld_ptk_mode ? "per-AP MLD" : "per-SMD",
+		   bss->smd_max_prep_targets);
+}
+
+
 static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
 				    const u8 *ssid, size_t ssid_len,
 				    struct wpa_scan_res *res,
@@ -607,6 +659,7 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
 	wpa_bss_set_hessid(bss);
 
 	wpa_bss_parse_basic_ml_element(wpa_s, bss);
+	wpa_bss_parse_smd_info(bss);
 
 	if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
 	    wpa_bss_remove_oldest(wpa_s) != 0) {
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index b38b5e51a809..780ea27a9639 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -145,6 +145,15 @@ struct wpa_bss {
 		bool disabled;
 	} mld_links[MAX_NUM_MLD_LINKS];
 
+	/** SMD Identifier (all zeros if not part of an SMD) */
+	u8 smd_id[ETH_ALEN];
+
+	/** SMD per-AP MLD PTK mode */
+	bool smd_per_ap_mld_ptk_mode;
+
+	/** Maximum number of target AP MLDs allowed in the prepared state */
+	u8 smd_max_prep_targets;
+
 	/* followed by ie_len octets of IEs */
 	/* followed by beacon_ie_len octets of IEs */
 	u8 ies[];
-- 
2.55.0




More information about the Hostap mailing list