[PATCH] supplicant: Fix MLD related IE parsing.
Ben Greear
greearb at candelatech.com
Sat Oct 28 16:26:52 PDT 2023
On 10/28/23 10:01 AM, Jouni Malinen wrote:
> On Sat, Oct 28, 2023 at 08:32:29AM -0700, Ben Greear wrote:
>> Is it worth posting the changes to debugging as separate patch, or do you
>> not want those at all?
>
> I did not go through the details for those once I realized that the
> patch was too complex to figure out what all was happening and what was
> part of the fix and what was something else.. But at least the part
> about dumping all IEs at ERROR verbosity would certainly be something
> that I would not want. As far as changing MLD related items to use
> wpa_dbg() is concerned, that would also seem a bit odd for more normal
> use cases, so it might be easier to skip those as well. If there were
> other types of debugging changes, I don't have an easy answer for those
> before the changes were identified in an easier to review form.
>
>
Here's a diff -w of the v2 patch. There are two new loops, so whitespace
changes makes it look more complicated than it is:
[greearb at v-f36-64 hostap]$ git diff -w HEAD~1
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 8ccb24d22..e4516f8f1 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -2498,6 +2498,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..b35ce777b 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -262,6 +262,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..0162c142d 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -1194,6 +1194,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..c595014c5 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;
@@ -468,12 +469,17 @@ static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
wpa_s->valid_links = BIT(wpa_s->mlo_assoc_link_id);
- rnr_ie = wpa_bss_get_ie(bss, WLAN_EID_REDUCED_NEIGHBOR_REPORT);
+ /* 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) {
- wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RNR element");
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;
@@ -481,12 +487,14 @@ static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
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;
+ 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;
- wpa_printf(MSG_DEBUG, "MLD: op_class=%u, channel=%u",
- ap_info->op_class, ap_info->channel);
+ wpa_dbg(wpa_s, MSG_DEBUG, "MLD: rnr-idx: %d op_class=%u, channel=%u\n",
+ rnr_idx - 1, ap_info->op_class, ap_info->channel);
if (len > rnr_ie_len)
break;
@@ -497,26 +505,36 @@ static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
continue;
}
- data += 13;
+ for (tbti = 0; tbti <= tbtt_count; tbti++) {
+ const u8* bssid = data + 1; /* one byte into the tbtt object */
- wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u",
- *data, *(data + 1) & 0xF);
+ 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_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);
+ 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) {
- if (wpa_scan_res_match(wpa_s, 0, 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);
os_memcpy(wpa_s->links[link_id].bssid,
- ap_info->data + 1, ETH_ALEN);
+ bssid, ETH_ALEN);
wpa_s->links[link_id].freq =
neigh_bss->freq;
} else {
@@ -528,10 +546,13 @@ static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
"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;
- }
+ }/* while more neigh info */
+ }/* for all neigh report IEs */
wpa_printf(MSG_DEBUG, "MLD: valid_links=0x%x", wpa_s->valid_links);
[greearb at v-f36-64 hostap]$
--
Ben Greear <greearb at candelatech.com>
Candela Technologies Inc http://www.candelatech.com
More information about the Hostap
mailing list