From 5156635a1fce3602c5092406e54c525e1f831e41 Mon Sep 17 00:00:00 2001 From: Rameshkumar Sundaram Date: Thu, 2 Nov 2023 23:17:40 +0530 Subject: [PATCH] wpa_supplicant: add support to parse multiple RNRs and TBTTs Currently while parsing RNR to fetch partner link information, only first TBTT inside first RNR is checked, but an MBSSID beacon/probe responses can have multiple RNR elements & multiple TBTTs in single neighbor information. Add support to parse through them and find partners. Also mld id of partner is always assumed to be 0 but in mbssid beacon/ Probe response mld id in RNR will be the mbssid index for NON-TX ML BSS'es. Add support to fetch mbssid index for current bss and use it to find partners. Signed-off-by: Rameshkumar Sundaram --- src/common/ieee802_11_common.c | 23 +++++ src/common/ieee802_11_common.h | 1 + wpa_supplicant/bss.c | 31 ++++++ wpa_supplicant/bss.h | 2 + wpa_supplicant/sme.c | 184 ++++++++++++++++----------------- 5 files changed, 147 insertions(+), 94 deletions(-) --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -2487,6 +2487,31 @@ const u8 * get_ie(const u8 *ies, size_t /** +* get_ie_pos - Fetch a specified information element at given index from IEs buffer +* @ies: Information elements buffer +* @len: Information elements buffer length +* @eid: Information element identifier (WLAN_EID_*) +* @idx: index of entry of element to be found. +* +* Returns: Pointer to the information element (id field) at given @idx +* or %NULL if not found. +*/ +const u8 * get_ie_pos(const u8 *ies, size_t len, u8 eid, u8 idx) +{ + const struct element *elem; + + if (!ies) + return NULL; + + for_each_element(elem, ies, len) { + if (elem->id == eid && !idx--) + return &elem->id; + } + return NULL; +} + + +/** * get_ie_ext - Fetch a specified extended information element from IEs buffer * @ies: Information elements buffer * @len: Information elements buffer length --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -260,6 +260,7 @@ extern const struct oper_class_map globa extern size_t global_op_class_size; const u8 * get_ie(const u8 *ies, size_t len, u8 eid); +const u8 * get_ie_pos(const u8 *ies, size_t len, u8 eid, u8 idx); 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); --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -1208,6 +1208,40 @@ const u8 * wpa_bss_get_ie(const struct w /** + * wpa_bss_get_ie_pos - Fetch a specified information element at given index + * from a BSS entry. This can be used to iterate over an element which is present + * multiple times in ie space + * @bss: BSS table entry + * @ie: Information element identitifier (WLAN_EID_*) + * @idx: index of entry of element to be found. + * + * This function returns the @idx'th matching information element in the BSS + * entry or NULL. + */ +const u8 * wpa_bss_get_ie_pos(const struct wpa_bss *bss, u8 ie, u8 idx) +{ + return get_ie_pos(wpa_bss_ie_ptr(bss), bss->ie_len, ie, idx); +} + +/** + * wpa_bss_get_mbssid_idx - Fetch a mbssid idx of a BSS entry + * @bss: BSS table entry + * + * This function returns the mbssid idx of a BSS if MULTIPLE_BSSID_INDEX + * element is present in the BSS ie, 0 otherwise. + */ +u8 wpa_bss_get_mbssid_idx(const struct wpa_bss *bss) +{ + const u8 *mbssid_idx_ie = get_ie(wpa_bss_ie_ptr(bss), bss->ie_len, + WLAN_EID_MULTIPLE_BSSID_INDEX); + if (!mbssid_idx_ie) + return 0; + else + return mbssid_idx_ie[2]; +} + + +/** * wpa_bss_get_ie_ext - Fetch a specified extended IE from a BSS entry * @bss: BSS table entry * @ext: Information element extension identifier (WLAN_EID_EXT_*) --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -164,6 +164,8 @@ struct wpa_bss * wpa_bss_get_id(struct w 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_pos(const struct wpa_bss *bss, u8 ie, u8 idx); +u8 wpa_bss_get_mbssid_idx(const struct wpa_bss *bss); 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, --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -388,7 +388,7 @@ static bool wpas_ml_element(struct wpa_s u8 ml_ie_len, rnr_ie_len; const struct ieee80211_eht_ml *eht_ml; const struct eht_ml_basic_common_info *ml_basic_common_info; - u8 i; + u8 i, mbssid_idx = 0; const u16 control = host_to_le16(MULTI_LINK_CONTROL_TYPE_BASIC | BASIC_MULTI_LINK_CTRL_PRES_LINK_ID | @@ -462,105 +462,102 @@ static bool wpas_ml_element(struct wpa_s wpa_s->valid_links = BIT(wpa_s->mlo_assoc_link_id); params->mld = true; - 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; - } - - 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_printf(MSG_DEBUG, "MLD: op_class=%u, channel=%u", - ap_info->op_class, ap_info->channel); + i = 0; + mbssid_idx = wpa_bss_get_mbssid_idx(bss); + wpa_printf(MSG_DEBUG, "MLD: mbssid idx = %u for bss " MACSTR, mbssid_idx, MAC2STR(bss->bssid)); + while ((rnr_ie = wpa_bss_get_ie_pos(bss, WLAN_EID_REDUCED_NEIGHBOR_REPORT, i++))) { + 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 rnr_info_len = sizeof(struct ieee80211_neighbor_ap_info); + u8 tbtt_count = ((ap_info->tbtt_info_hdr & 0xF0) >> 4) + 1; + + wpa_printf(MSG_DEBUG, "MLD: op_class=%u, channel=%u tbtt_info_len %d tbtt_count %u", + ap_info->op_class, ap_info->channel, ap_info->tbtt_info_len, tbtt_count); + rnr_ie_len -= rnr_info_len; + pos += rnr_info_len; + if (ap_info->tbtt_info_len < 16) { + rnr_ie_len -= (tbtt_count * ap_info->tbtt_info_len); + pos += (tbtt_count * ap_info->tbtt_info_len); + continue; + } + while (tbtt_count--) { + const u8 *bssid = data + 1; + u16 mld_id = *(data + 13); + u8 link_id = *(data + 14) & 0xF; - if (len > rnr_ie_len) - break; + wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u", + mld_id, link_id); - if (ap_info->tbtt_info_len < 16) { - rnr_ie_len -= len; - pos += len; - continue; - } + /* For NON-MBSSID BSS and MBSSID Tx BSS, idx will be 0 */ + if (mbssid_idx != mld_id) { + wpa_printf(MSG_DEBUG, + "MLD: Reported link not part of current MLD"); + } else { + struct wpa_bss *neigh_bss = + wpa_bss_get_bssid(wpa_s, bssid); - data += 13; + wpa_printf(MSG_DEBUG, "Neighbor bssid : " MACSTR, + MAC2STR(bssid)); - wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u", - *data, *(data + 1) & 0xF); + if (neigh_bss) + wpa_printf(MSG_DEBUG, "MLD: Neighbor founded in scan"); - 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_printf(MSG_DEBUG, "Neighbor bssid : " MACSTR, - MAC2STR(ap_info->data + 1)); - - if (neigh_bss) - wpa_printf(MSG_DEBUG, "MLD: Neighbor founded in scan"); - - if (!wpa_s->current_ssid) - wpa_printf(MSG_DEBUG, "MLD: empty wpa_s->current_ssid"); - - u8 link_id = *(data + 1) & 0xF; - int partner_freq = ieee80211_chan_to_freq(NULL, ap_info->op_class, ap_info->chanel); - int curr_freq = 0; - if (partner_freq && wpa_s->conf->freq_list && wpa_s->conf->freq_list[0]) { - int i = 0; - curr_freq = wpa_s->conf->freq_list[i]; - while (curr_freq) { - i++; - wpa_printf(MSG_DEBUG, "ML Partner freq %d our scan list freq %d", partner_freq, curr_freq); - if (curr_freq == partner_freq) { - wpa_printf(MSG_DEBUG, "ML Partner freq %d is part of our scan list", partner_freq); - break; + if (!wpa_s->current_ssid) + wpa_printf(MSG_DEBUG, "MLD: empty wpa_s->current_ssid"); + + int partner_freq = ieee80211_chan_to_freq(NULL, ap_info->op_class, ap_info->channel); + int curr_freq = 0; + if (partner_freq && wpa_s->conf->freq_list && wpa_s->conf->freq_list[0]) { + int i = 0; + curr_freq = wpa_s->conf->freq_list[i]; + while (curr_freq) { + i++; + if (curr_freq == partner_freq) { + wpa_printf(MSG_DEBUG, "ML Partner freq %d is part of our scan list", partner_freq); + break; + } + curr_freq = wpa_s->conf->freq_list[i]; + } + } + if (wpa_s->conf->freq_list && wpa_s->conf->freq_list[0] && !curr_freq) { + wpa_printf(MSG_DEBUG, "ML Partner freq %d is not part of our scan list ignore this link", partner_freq); + goto cont; + } + if (neigh_bss) { + wpa_scan_res_match(wpa_s, 0, neigh_bss, + wpa_s->current_ssid, + 1, 1); + + if (true) { + wpa_s->valid_links |= BIT(link_id); + os_memcpy(wpa_s->links[link_id].bssid, + bssid, ETH_ALEN); + wpa_s->links[link_id].freq = neigh_bss->freq; + } else { + wpa_printf(MSG_DEBUG, + "MLD: Neighbor doesn't match current SSID - skip link"); + } + } else { + wpa_printf(MSG_DEBUG, + "MLD: Neighbor not found in scan, current neigh scan retry count %u", wpa_s->ml_neigh_retries); + if (wpa_s->ml_neigh_retries <= 5) { + ret = false; + goto out; + } } - curr_freq = wpa_s->conf->freq_list[i]; - } - } - if (wpa_s->conf->freq_list && wpa_s->conf->freq_list[0] && !curr_freq) { - wpa_printf(MSG_DEBUG, "ML Partner freq %d is not part of our scan list ignore this link", partner_freq); - goto cont; - } - if (neigh_bss) { - wpa_scan_res_match(wpa_s, 0, neigh_bss, - wpa_s->current_ssid, - 1, 1); - - if (true) { - 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; - } else { - wpa_printf(MSG_DEBUG, - "MLD: Neighbor doesn't match current SSID - skip link"); - } - } else { - wpa_printf(MSG_DEBUG, - "MLD: Neighbor not found in scan, current neigh scan retry count %u", wpa_s->ml_neigh_retries); - if (pa_s->ml_neigh_retries <= 5) { - ret = false; - goto out; } - } - } cont: - rnr_ie_len -= len; - pos += len; + data += ap_info->tbtt_info_len; + } + rnr_ie_len -= (data - ap_info->data); + pos += (data - ap_info->data); + } } - wpa_printf(MSG_DEBUG, "MLD: valid_links=0x%x", wpa_s->valid_links); for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {