diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 37a300ea4..06f82ce30 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -2495,35 +2495,6 @@ 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 a8a2118b1..a7d407b65 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -261,7 +261,6 @@ 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 ca11e7200..fec0e5275 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -13,6 +13,7 @@ #include "common/ieee802_11_defs.h" #include "drivers/driver.h" #include "eap_peer/eap.h" +#include "rsn_supp/wpa.h" #include "wpa_supplicant_i.h" #include "config.h" #include "notify.h" @@ -1222,22 +1223,6 @@ 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 @@ -1501,7 +1486,8 @@ static void wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, u8 mbssid_idx, const struct ieee80211_neighbor_ap_info *ap_info, - size_t len, u16 *seen, u16 *missing) + size_t len, u16 *seen, u16 *missing, + struct wpa_ssid *ssid) { const u8 *pos, *end; const u8 *mld_params; @@ -1525,12 +1511,15 @@ wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s, pos += sizeof(*ap_info); for (i = 0; i < count; i++) { + u8 bss_params; + if (bss->n_mld_links >= MAX_NUM_MLD_LINKS) return; if (end - pos < ap_info->tbtt_info_len) break; + bss_params = pos[1 + ETH_ALEN + 4]; mld_params = pos + mld_params_offset; link_id = *(mld_params + 1) & EHT_ML_LINK_ID_MSK; @@ -1546,7 +1535,13 @@ wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u", *mld_params, link_id); - if (neigh_bss) { + if (!neigh_bss) { + *missing |= BIT(link_id); + } else if (!ssid || + (bss_params & (RNR_BSS_PARAM_SAME_SSID | + RNR_BSS_PARAM_CO_LOCATED)) || + wpa_scan_res_match(wpa_s, 0, neigh_bss, + ssid, 1, 0)) { struct mld_link *l; l = &bss->mld_links[bss->n_mld_links]; @@ -1555,8 +1550,6 @@ wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s, ETH_ALEN); l->freq = neigh_bss->freq; bss->n_mld_links++; - } else { - *missing |= BIT(link_id); } } @@ -1573,6 +1566,7 @@ wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s, * @link_info: Array to store link information (or %NULL), * should be initialized and #MAX_NUM_MLD_LINKS elements long * @missing_links: Result bitmask of links that were not discovered (or %NULL) + * @ssid: Target SSID (or %NULL) * Returns: 0 on success or -1 for non-MLD or parsing failures * * Parses the Basic Multi-Link element of the BSS into @link_info using the scan @@ -1583,7 +1577,8 @@ wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s, int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, u8 *ap_mld_addr, - u16 *missing_links) + u16 *missing_links, + struct wpa_ssid *ssid) { struct ieee802_11_elems elems; struct wpabuf *mlbuf; @@ -1624,6 +1619,32 @@ int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, ml_ie_len = wpabuf_len(mlbuf); + if (ssid) { + struct wpa_ie_data ie; + + if (!elems.rsn_ie || + wpa_parse_wpa_ie(elems.rsn_ie - 2, 2 + elems.rsn_ie_len, + &ie)) { + wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RSN element"); + goto out; + } + + if (!(ie.capabilities & WPA_CAPABILITY_MFPC) || + wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION) { + wpa_dbg(wpa_s, MSG_DEBUG, + "MLD: No management frame protection"); + goto out; + } + + ie.key_mgmt &= ~(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_PSK_SHA256); + if (!(ie.key_mgmt & ssid->key_mgmt)) { + wpa_dbg(wpa_s, MSG_DEBUG, + "MLD: No valid key management"); + goto out; + } + } + /* * for ext ID + 2 control + common info len + MLD address + * link info @@ -1703,7 +1724,7 @@ int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, wpa_bss_parse_ml_rnr_ap_info(wpa_s, bss, mbssid_idx, ap_info, len, &seen, - &missing); + &missing, ssid); pos += ap_info_len; len -= ap_info_len; diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h index 7b0b24c61..bacf0a8e9 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -171,7 +171,6 @@ 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, @@ -216,7 +215,8 @@ void calculate_update_time(const struct os_reltime *fetch_time, int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, u8 *ap_mld_addr, - u16 *missing_links); + u16 *missing_links, + struct wpa_ssid *ssid); u16 wpa_bss_parse_reconf_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index b1a2fc6f9..c404f4597 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1153,7 +1153,7 @@ static bool wpas_valid_ml_bss(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { u16 removed_links; - if (wpa_bss_parse_basic_ml_element(wpa_s, bss, NULL, NULL)) + if (wpa_bss_parse_basic_ml_element(wpa_s, bss, NULL, NULL, NULL)) return true; if (bss->n_mld_links == 0) @@ -1878,7 +1878,8 @@ static int wpa_supplicant_connect_ml_missing(struct wpa_supplicant *wpa_s, /* Try to resolve any missing link information */ if (wpa_bss_parse_basic_ml_element(wpa_s, selected, NULL, - &missing_links) || !missing_links) + &missing_links, ssid) || + !missing_links) return 0; removed_links = wpa_bss_parse_reconf_ml_element(wpa_s, selected); diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 26abdc69c..9af7a368a 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -378,225 +378,6 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s, } -static void wpas_process_tbtt_info(struct wpa_supplicant *wpa_s, const u8 *data) -{ - struct wpa_bss *neigh_bss; - const u8 *bssid; - u8 bss_params; - u8 link_id; - - /* TBTT Information field - * Neighbor AP TBTT Offset[1] - * BSSID[6] - * Short SSID[4] - * BSS parameters[1] - * 20 MHz PSD[1] - * MLD Parameters[3] - * B0..B7: AP MLD ID - * B7..B11: Link ID - * B12..B19: BSS Parameters Change Count - * B20: All Updates Included - * B21: Disabled Link Indication */ - - bssid = data + 1; - bss_params = data[1 + ETH_ALEN + 4]; - - data += 13; /* MLD Parameters */ - link_id = *(data + 1) & 0xF; - - wpa_dbg(wpa_s, MSG_DEBUG, - "MLD: mld ID=%u, link ID=%u, bssid=" MACSTR ", bss_params=0x%x", - *data, link_id, MAC2STR(bssid), bss_params); - - if (*data) { - wpa_printf(MSG_DEBUG, "MLD: Reported link not part of MLD"); - return; - } - - neigh_bss = wpa_bss_get_bssid(wpa_s, bssid); - if (!neigh_bss) { - wpa_printf(MSG_DEBUG, "MLD: Neighbor not found in scan"); - return; - } - - if (!((bss_params & RNR_BSS_PARAM_SAME_SSID) && - (bss_params & RNR_BSS_PARAM_CO_LOCATED)) && - !wpa_scan_res_match(wpa_s, 0, neigh_bss, wpa_s->current_ssid, - 1, 0)) { - wpa_printf(MSG_DEBUG, - "MLD: Neighbor doesn't match current SSID - skip link"); - return; - } - - 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; -} - - -static void wpas_process_rnr(struct wpa_supplicant *wpa_s, const u8 *pos, - size_t rnr_ie_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; - /* The first TBTT Information field */ - const u8 *data = ap_info->data; - u8 tbtt_count; - size_t len; - int tbtt_i; - - if (rnr_ie_len < sizeof(struct ieee80211_neighbor_ap_info)) - break; - - tbtt_count = (ap_info->tbtt_info_hdr >> 4) + 1; - len = sizeof(struct ieee80211_neighbor_ap_info) + - ap_info->tbtt_info_len * tbtt_count; - - wpa_printf(MSG_DEBUG, "MLD: op_class=%u, channel=%u", - ap_info->op_class, ap_info->channel); - - if (len > rnr_ie_len) - break; - - if (ap_info->tbtt_info_len < 16) { - rnr_ie_len -= len; - pos += len; - continue; - } - - for (tbtt_i = 0; tbtt_i < tbtt_count; tbtt_i++) { - wpas_process_tbtt_info(wpa_s, data); - data += ap_info->tbtt_info_len; - } - - rnr_ie_len -= len; - pos += len; - } -} - - -static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, - struct wpa_ssid *ssid) -{ - struct wpabuf *mlbuf; - const u8 *rnr_ie, *rsn_ie; - struct wpa_ie_data ie; - u8 ml_ie_len; - const struct ieee80211_eht_ml *eht_ml; - const struct eht_ml_basic_common_info *ml_basic_common_info; - struct ieee802_11_elems elems; - u8 i; - const u16 control = - host_to_le16(MULTI_LINK_CONTROL_TYPE_BASIC | - BASIC_MULTI_LINK_CTRL_PRES_LINK_ID | - 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; - - if (ieee802_11_parse_elems(wpa_bss_ie_ptr(bss), - bss->ie_len, &elems, 1) == ParseFailed) - return false; - - mlbuf = ieee802_11_defrag(elems.basic_mle, elems.basic_mle_len, true); - if (!mlbuf) { - wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No ML element"); - return false; - } - - rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); - if (!rsn_ie || wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) { - wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RSN element"); - goto out; - } - - if (!(ie.capabilities & WPA_CAPABILITY_MFPC) || - wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION) { - wpa_dbg(wpa_s, MSG_DEBUG, - "MLD: No management frame protection"); - goto out; - } - - ie.key_mgmt &= ~(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | - WPA_KEY_MGMT_PSK_SHA256); - if (!(ie.key_mgmt & ssid->key_mgmt)) { - wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No valid key management"); - goto out; - } - - ml_ie_len = wpabuf_len(mlbuf); - - /* control + common info len + MLD address + MLD link information */ - if (ml_ie_len < 2 + 1 + ETH_ALEN + 1) - goto out; - - eht_ml = wpabuf_head(mlbuf); - if ((eht_ml->ml_control & control) != control) { - wpa_printf(MSG_DEBUG, "MLD: Unexpected ML element control=0x%x", - eht_ml->ml_control); - goto out; - } - - ml_basic_common_info = - (const struct eht_ml_basic_common_info *) eht_ml->variable; - - /* common info length should be valid (self, mld_addr, link_id) */ - if (ml_basic_common_info->len < 1 + ETH_ALEN + 1) - goto out; - - /* get the MLD address and MLD link ID */ - os_memcpy(wpa_s->ap_mld_addr, ml_basic_common_info->mld_addr, - ETH_ALEN); - wpa_s->mlo_assoc_link_id = ml_basic_common_info->variable[0] & - EHT_ML_LINK_ID_MSK; - - os_memcpy(wpa_s->links[wpa_s->mlo_assoc_link_id].bssid, bss->bssid, - ETH_ALEN); - wpa_s->links[wpa_s->mlo_assoc_link_id].freq = bss->freq; - - wpa_printf(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); - - ret = true; - - /* 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); - - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { - if (!(wpa_s->valid_links & BIT(i))) - continue; - - wpa_printf(MSG_DEBUG, "MLD: link=%u, bssid=" MACSTR, - i, MAC2STR(wpa_s->links[i].bssid)); - } - -out: - wpabuf_free(mlbuf); - return ret; -} - - static void wpas_ml_handle_removed_links(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { @@ -737,6 +518,27 @@ out: } +static void wpas_sme_set_mlo_links(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss) +{ + int i; + + wpa_s->valid_links = 0; + + for (i = 0; i < bss->n_mld_links; i++) { + u8 link_id = bss->mld_links[i].link_id; + const u8 *bssid = bss->mld_links[i].bssid; + + if (i == 0) + wpa_s->mlo_assoc_link_id = link_id; + wpa_s->valid_links |= BIT(link_id); + os_memcpy(wpa_s->links[link_id].bssid, bssid, ETH_ALEN); + wpa_s->links[link_id].freq = bss->mld_links[i].freq; + wpa_s->links[link_id].bss = wpa_bss_get_bssid(wpa_s, bssid); + } +} + + static void sme_send_authentication(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid, int start) @@ -769,8 +571,14 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } os_memset(¶ms, 0, sizeof(params)); - if (wpas_ml_element(wpa_s, bss, ssid)) { + + if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) && + !wpa_bss_parse_basic_ml_element(wpa_s, bss, wpa_s->ap_mld_addr, + NULL, ssid) && + bss->n_mld_links) { wpa_printf(MSG_DEBUG, "MLD: In authentication"); + wpas_sme_set_mlo_links(wpa_s, bss); + #ifdef CONFIG_TESTING_OPTIONS bss = wpas_ml_connect_pref(wpa_s, bss);