[PATCH] supplicant: Fix MLD related IE parsing.

greearb at candelatech.com greearb at candelatech.com
Fri Oct 27 20:32:23 PDT 2023


From: Ben Greear <greearb at candelatech.com>

Now supplicant can deal with beacons containing multiple TBTT
elements.  This lets MLO connections be attempted against TPLINK
be800 AP.

This also includes a good bit of logging changes, including
conversion to wpa_dbg so that wlan name is seen in the logs.

Signed-off-by: Ben Greear <greearb at candelatech.com>
---
 src/common/ieee802_11_common.c |  42 +++++++++
 src/common/ieee802_11_common.h |   2 +
 wpa_supplicant/bss.c           |  18 ++++
 wpa_supplicant/bss.h           |   1 +
 wpa_supplicant/sme.c           | 167 ++++++++++++++++++++-------------
 5 files changed, 163 insertions(+), 67 deletions(-)

diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 8ccb24d22..74d225f7e 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1118,6 +1118,20 @@ int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
 	return count;
 }
 
+void ieee802_11_ie_print(const u8 *ies, size_t ies_len)
+{
+	const struct element *elem;
+
+	if (ies == NULL) {
+		wpa_printf(MSG_ERROR, "ie-print: ies == NULL");
+		return;
+	}
+
+	for_each_element(elem, ies, ies_len)
+		wpa_printf(MSG_ERROR, "ie-print: id: %d (0x%x)  datalen: %d",
+			   elem->id, elem->id, elem->datalen);
+}
+
 
 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
 					    u32 oui_type)
@@ -2498,6 +2512,34 @@ const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
 	return NULL;
 }
 
+/**
+ * get_ie - Fetch a specified information element from IEs buffer
+ * @ies: Information elements buffer
+ * @len: Information elements buffer length
+ * @eid: Information element identifier (WLAN_EID_*)
+ * @nth: Return the nth element of the requested type (2 returns the second)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the nth matching information element in the IEs
+ * buffer or %NULL in case the element is not found.
+ */
+const u8 * get_ie_nth(const u8 *ies, size_t len, u8 eid, int nth)
+{
+	const struct element *elem;
+	int sofar = 0;
+
+	if (!ies)
+		return NULL;
+
+	for_each_element_id(elem, eid, ies, len) {
+		if ((sofar + 1) == nth)
+			return &elem->id;
+		sofar++;
+	}
+
+	return NULL;
+}
+
 
 /**
  * get_ie_ext - Fetch a specified extended information element from IEs buffer
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index ef95c3591..9b2e2eb8b 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -198,6 +198,7 @@ ParseRes ieee802_11_parse_link_assoc_req(const u8 *start, size_t len,
 					 struct wpabuf *mlbuf,
 					 u8 link_id, bool show_errors);
 int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
+void ieee802_11_ie_print(const u8 *ies, size_t ies_len);
 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
 					    u32 oui_type);
 struct ieee80211_hdr;
@@ -262,6 +263,7 @@ extern const struct oper_class_map global_op_class[];
 extern size_t global_op_class_size;
 
 const u8 * get_ie(const u8 *ies, size_t len, u8 eid);
+const u8 * get_ie_nth(const u8 *ies, size_t len, u8 eid, int nth);
 const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext);
 const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type);
 
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 3b1646dd2..cfd107082 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -477,6 +477,9 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
 	os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len);
 	wpa_bss_set_hessid(bss);
 
+	wpa_dbg(wpa_s, MSG_DEBUG, "wpa-bss-add, ies:\n");
+	ieee802_11_ie_print(wpa_bss_ie_ptr(bss), bss->ie_len);
+
 	os_memset(bss->mld_addr, 0, ETH_ALEN);
 	ml_ie = wpa_scan_get_ml_ie(res, MULTI_LINK_CONTROL_TYPE_BASIC);
 	if (ml_ie) {
@@ -1194,6 +1197,21 @@ const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
 	return get_ie(wpa_bss_ie_ptr(bss), bss->ie_len, ie);
 }
 
+/**
+ * wpa_bss_get_ie_nth - Fetch a specified information element from a BSS entry
+ * @bss: BSS table entry
+ * @ie: Information element identitifier (WLAN_EID_*)
+ * @nth: Return the nth element of the requested type (2 returns the second)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the nth matching information element in the BSS
+ * entry.
+ */
+const u8 * wpa_bss_get_ie_nth(const struct wpa_bss *bss, u8 ie, int nth)
+{
+	return get_ie_nth(wpa_bss_ie_ptr(bss), bss->ie_len, ie, nth);
+}
+
 
 /**
  * wpa_bss_get_ie_ext - Fetch a specified extended IE from a BSS entry
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 611da8844..4580e7981 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -160,6 +160,7 @@ struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id);
 struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
 				      unsigned int idf, unsigned int idl);
 const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
+const u8 * wpa_bss_get_ie_nth(const struct wpa_bss *bss, u8 ie, int nth);
 const u8 * wpa_bss_get_ie_ext(const struct wpa_bss *bss, u8 ext);
 const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type);
 const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index acb6981d9..ef054949e 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -400,6 +400,7 @@ static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 			     BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT |
 			     BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA);
 	bool ret = false;
+	int rnr_idx = 0;
 
 	if (!(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO))
 		return false;
@@ -463,77 +464,107 @@ static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 		  ETH_ALEN);
 	wpa_s->links[wpa_s->mlo_assoc_link_id].freq = bss->freq;
 
-	wpa_printf(MSG_DEBUG, "MLD: address=" MACSTR ", link ID=%u",
+	wpa_dbg(wpa_s, MSG_DEBUG, "MLD: address=" MACSTR ", link ID=%u",
 		   MAC2STR(wpa_s->ap_mld_addr), wpa_s->mlo_assoc_link_id);
 
 	wpa_s->valid_links = BIT(wpa_s->mlo_assoc_link_id);
 
-	rnr_ie = wpa_bss_get_ie(bss, WLAN_EID_REDUCED_NEIGHBOR_REPORT);
-	if (!rnr_ie) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RNR element");
-		ret = true;
-		goto out;
-	}
+	/* Search for multiple neigh report IEs. */
+	while (true) {
+		rnr_ie = wpa_bss_get_ie_nth(bss, WLAN_EID_REDUCED_NEIGHBOR_REPORT, ++rnr_idx);
+		if (!rnr_ie) {
+			ret = true;
+			if (rnr_idx == 0) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RNR element");
+				goto out;
+			}
+			break;
+		}
 
-	rnr_ie_len = rnr_ie[1];
-	pos = rnr_ie + 2;
+		rnr_ie_len = rnr_ie[1];
+		pos = rnr_ie + 2;
 
-	while (rnr_ie_len > sizeof(struct ieee80211_neighbor_ap_info)) {
-		const struct ieee80211_neighbor_ap_info *ap_info =
-			(const struct ieee80211_neighbor_ap_info *) pos;
-		const u8 *data = ap_info->data;
-		size_t len = sizeof(struct ieee80211_neighbor_ap_info) +
-			ap_info->tbtt_info_len;
+		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: rnr-id-len: %d",
+			rnr_ie_len);
 
-		wpa_printf(MSG_DEBUG, "MLD: op_class=%u, channel=%u",
-			   ap_info->op_class, ap_info->channel);
+		while (rnr_ie_len > sizeof(struct ieee80211_neighbor_ap_info)) {
+			const struct ieee80211_neighbor_ap_info *ap_info =
+				(const struct ieee80211_neighbor_ap_info *) pos;
+			const u8 *data = ap_info->data; /* start of tbtt elements */
+			const u8 tbtt_count = ap_info->tbtt_info_hdr >> 4;
+			size_t len = ap_info->tbtt_info_len * (tbtt_count + 1) +
+				sizeof(struct ieee80211_neighbor_ap_info);
+			int tbti;
 
-		if (len > rnr_ie_len)
-			break;
+			wpa_dbg(wpa_s, MSG_DEBUG, "MLD: rnr-idx: %d op_class=%u, channel=%u len: %d  rnr_ie_len: %d  tbtt_info_len: %d",
+				rnr_idx - 1, ap_info->op_class, ap_info->channel, (int)len, rnr_ie_len,
+				ap_info->tbtt_info_len);
 
-		if (ap_info->tbtt_info_len < 16) {
-			rnr_ie_len -= len;
-			pos += len;
-			continue;
-		}
+			if (len > rnr_ie_len)
+				break;
 
-		data += 13;
+			if (ap_info->tbtt_info_len < 16) {
+				rnr_ie_len -= len;
+				pos += len;
+				continue;
+			}
 
-		wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u",
-			   *data, *(data + 1) & 0xF);
+			for (tbti = 0; tbti <= tbtt_count; tbti++) {
+				const u8* bssid = data + 1; /* one byte into the tbtt object */
 
-		if (*data) {
-			wpa_printf(MSG_DEBUG,
-				   "MLD: Reported link not part of MLD");
-		} else {
-			struct wpa_bss *neigh_bss =
-				wpa_bss_get_bssid(wpa_s, ap_info->data + 1);
-			u8 link_id = *(data + 1) & 0xF;
-
-			if (neigh_bss) {
-				if (wpa_scan_res_match(wpa_s, 0, neigh_bss,
-						       wpa_s->current_ssid,
-						       1, 0)) {
-					wpa_s->valid_links |= BIT(link_id);
-					os_memcpy(wpa_s->links[link_id].bssid,
-						  ap_info->data + 1, ETH_ALEN);
-					wpa_s->links[link_id].freq =
-						neigh_bss->freq;
+				data += 13; /* advance to mld parameters */
+
+				wpa_dbg(wpa_s, MSG_DEBUG, "MLD: tbtt idx: %d mld ID=%u, link ID=%u  data: 0x%lx bssid=" MACSTR,
+					tbti, *data, *(data + 1) & 0xF, (unsigned long)data,
+					MAC2STR(bssid));
+
+				if (*data) {
+					wpa_dbg(wpa_s, MSG_DEBUG,
+						"MLD: Reported link not part of MLD");
 				} else {
-					wpa_printf(MSG_DEBUG,
-						   "MLD: Neighbor doesn't match current SSID - skip link");
+					struct wpa_bss *neigh_bss =
+						wpa_bss_get_bssid(wpa_s, bssid);
+					u8 link_id = *(data + 1) & 0xF;
+
+					/* Intel radios won't scan 6e at first.  Would need to force
+					 * the radio to scan multiple times to fix that limitations.
+					 */
+					if (neigh_bss) {
+						u8 bss_params = *(data + (1 + 6 + 4 - 13));
+						if (((bss_params & 0x2) /* same ssid */
+						     && (bss_params & (1<<6))) || /* co-located AP */
+						    wpa_scan_res_match(wpa_s, 0, neigh_bss,
+								       wpa_s->current_ssid,
+								       1, 0)) {
+							wpa_s->valid_links |= BIT(link_id);
+							wpa_dbg(wpa_s, MSG_DEBUG,
+								"MLD: adding link id: %d  valid_links: 0x%x",
+								link_id, wpa_s->valid_links);
+							os_memcpy(wpa_s->links[link_id].bssid,
+								  bssid, ETH_ALEN);
+							if (neigh_bss)
+								wpa_s->links[link_id].freq =
+									neigh_bss->freq;
+							else
+								wpa_s->links[link_id].freq = 0;
+						} else {
+							wpa_dbg(wpa_s, MSG_DEBUG,
+								"MLD: Neighbor doesn't match current SSID - skip link");
+						}
+					} else {
+						wpa_dbg(wpa_s, MSG_DEBUG,
+							   "MLD: Neighbor not found in scan");
+					}
 				}
-			} else {
-				wpa_printf(MSG_DEBUG,
-					   "MLD: Neighbor not found in scan");
-			}
-		}
+				data += (ap_info->tbtt_info_len - 13); /* consume rest of tbtt */
+			}/* for all tbtt */
 
-		rnr_ie_len -= len;
-		pos += len;
-	}
+			rnr_ie_len -= len;
+			pos += len;
+		}/* while more neigh info */
+	}/* for all neigh report IEs */
 
-	wpa_printf(MSG_DEBUG, "MLD: valid_links=0x%x", wpa_s->valid_links);
+	wpa_dbg(wpa_s, MSG_DEBUG, "MLD: valid_links=0x%x", wpa_s->valid_links);
 
 	for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
 		if (!(wpa_s->valid_links & BIT(i)))
@@ -561,10 +592,11 @@ static void wpas_sme_ml_auth(struct wpa_supplicant *wpa_s,
 	if (!wpa_s->valid_links)
 		return;
 
+	wpa_dbg(wpa_s, MSG_DEBUG, "sme-ml-auth, parsing auth elements");
 	if (ieee802_11_parse_elems(data->auth.ies + ie_offset,
 				   data->auth.ies_len - ie_offset,
 				   &elems, 0) == ParseFailed) {
-		wpa_printf(MSG_DEBUG, "MLD: Failed parsing elements");
+		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: Failed parsing elements");
 		goto out;
 	}
 
@@ -584,17 +616,17 @@ static void wpas_sme_ml_auth(struct wpa_supplicant *wpa_s,
 	if (!mld_addr)
 		goto out;
 
-	wpa_printf(MSG_DEBUG, "MLD: mld_address=" MACSTR, MAC2STR(mld_addr));
+	wpa_dbg(wpa_s, MSG_DEBUG, "MLD: mld_address=" MACSTR, MAC2STR(mld_addr));
 
 	if (os_memcmp(wpa_s->ap_mld_addr, mld_addr, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLD: Unexpected MLD address (expected "
-			   MACSTR ")", MAC2STR(wpa_s->ap_mld_addr));
+		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: Unexpected MLD address (expected "
+			MACSTR ")", MAC2STR(wpa_s->ap_mld_addr));
 		goto out;
 	}
 
 	return;
 out:
-	wpa_printf(MSG_DEBUG, "MLD: Authentication - clearing MLD state");
+	wpa_dbg(wpa_s, MSG_DEBUG, "MLD: Authentication - clearing MLD state");
 	wpas_reset_mlo_info(wpa_s);
 }
 
@@ -1652,14 +1684,15 @@ static int sme_external_ml_auth(struct wpa_supplicant *wpa_s,
 	struct ieee802_11_elems elems;
 	const u8 *mld_addr;
 
+	wpa_dbg(wpa_s, MSG_DEBUG, "external-ml-auth, parsing auth elements");
 	if (ieee802_11_parse_elems(data + ie_offset, len - ie_offset,
 				   &elems, 0) == ParseFailed) {
-		wpa_printf(MSG_DEBUG, "MLD: Failed parsing elements");
+		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: Failed parsing elements");
 		return -1;
 	}
 
 	if (!elems.basic_mle || !elems.basic_mle_len) {
-		wpa_printf(MSG_DEBUG, "MLD: No ML element in authentication");
+		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No ML element in authentication");
 		if (status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ ||
 		    status_code == WLAN_STATUS_SUCCESS ||
 		    status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
@@ -1672,17 +1705,17 @@ static int sme_external_ml_auth(struct wpa_supplicant *wpa_s,
 
 	mld_addr = get_basic_mle_mld_addr(elems.basic_mle, elems.basic_mle_len);
 	if (!mld_addr) {
-		wpa_printf(MSG_DEBUG, "MLD: No MLD address in ML element");
+		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No MLD address in ML element");
 		return -1;
 	}
 
-	wpa_printf(MSG_DEBUG, "MLD: mld_address=" MACSTR, MAC2STR(mld_addr));
+	wpa_dbg(wpa_s, MSG_DEBUG, "MLD: mld_address=" MACSTR, MAC2STR(mld_addr));
 
 	if (os_memcmp(wpa_s->sme.ext_auth_ap_mld_addr, mld_addr, ETH_ALEN) !=
 	    0) {
-		wpa_printf(MSG_DEBUG, "MLD: Unexpected MLD address (expected "
-			   MACSTR ")",
-			   MAC2STR(wpa_s->sme.ext_auth_ap_mld_addr));
+		wpa_dbg(wpa_s, MSG_DEBUG, "MLD: Unexpected MLD address (expected "
+			MACSTR ")",
+			MAC2STR(wpa_s->sme.ext_auth_ap_mld_addr));
 		return -1;
 	}
 
-- 
2.40.1




More information about the Hostap mailing list