From: Ben Greear <greearb@xxxxxxxxxxxxxxx> 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@xxxxxxxxxxxxxxx> --- v2: Remove spurious debugging/logging changes. A few logging changes I left in, felt that while adding new info it was fine to change to wpa_dbg as that gives better info when running multiple stations in same supplicant. src/common/ieee802_11_common.c | 28 ++++++++ src/common/ieee802_11_common.h | 1 + wpa_supplicant/bss.c | 15 ++++ wpa_supplicant/bss.h | 1 + wpa_supplicant/sme.c | 127 +++++++++++++++++++-------------- 5 files changed, 119 insertions(+), 53 deletions(-) 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,70 +469,90 @@ 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; - } + /* 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; + 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; - 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; + if (len > rnr_ie_len) + break; - if (ap_info->tbtt_info_len < 16) { - rnr_ie_len -= len; - pos += len; - continue; - } + if (ap_info->tbtt_info_len < 16) { + rnr_ie_len -= len; + pos += len; + 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 */ - 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; - } else { + 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: Neighbor doesn't match current SSID - skip link"); + "MLD: Reported link not part of MLD"); + } else { + 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); + 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"); + } } - } 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); -- 2.40.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap