From 99a8dd04952decbfa54c7883e559fbcf156b6fc7 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Sat, 28 Oct 2023 16:24:35 -0700 Subject: [PATCH] MLD: Support multiple RNR elements Beacon frames are allowed to optionally include one more more Reduced Neighbor Report elements. Only the first one was parsed previously. Extend this to use a loop to go through all included RNR elements. Signed-off-by: Ben Greear --- src/common/ieee802_11_common.c | 29 +++++++++++++++++++++++++++++ src/common/ieee802_11_common.h | 1 + wpa_supplicant/bss.c | 16 ++++++++++++++++ wpa_supplicant/bss.h | 1 + wpa_supplicant/sme.c | 25 +++++++++++++++++-------- 5 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 093339cb4..70d56ffbf 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -2495,6 +2495,35 @@ const u8 * get_ie(const u8 *ies, size_t len, u8 eid) } +/** + * get_ie_nth - 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) { + sofar++; + if (sofar == nth) + return &elem->id; + } + + return NULL; +} + + /** * get_ie_ext - Fetch a specified extended information element from IEs buffer * @ies: Information elements buffer diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index f8cede008..00dc2fb10 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -261,6 +261,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 2ad74f3a4..26cdeaf28 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -1220,6 +1220,22 @@ const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 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 * @bss: BSS table entry diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h index 39dad868e..9e673db0d 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -169,6 +169,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 9a9ada251..4448a8d3c 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -454,6 +454,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; if (!(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO)) return false; @@ -519,14 +520,23 @@ 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); - if (!rnr_ie) { - wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RNR element"); - ret = true; - goto out; - } + ret = true; - wpas_process_rnr(wpa_s, rnr_ie + 2, rnr_ie[1]); + /* Process all Reduced Neighbor Report elements */ + for (rnr_idx = 1; ; rnr_idx++) { + rnr_ie = wpa_bss_get_ie_nth(bss, + WLAN_EID_REDUCED_NEIGHBOR_REPORT, + rnr_idx); + if (!rnr_ie) { + if (rnr_idx == 0) { + wpa_dbg(wpa_s, MSG_DEBUG, + "MLD: No RNR element"); + goto out; + } + break; + } + wpas_process_rnr(wpa_s, rnr_ie + 2, rnr_ie[1]); + } wpa_printf(MSG_DEBUG, "MLD: valid_links=0x%x", wpa_s->valid_links); @@ -538,7 +548,6 @@ static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, i, MAC2STR(wpa_s->links[i].bssid)); } - ret = true; out: wpabuf_free(mlbuf); return ret;