[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