From: Ilan Peer <ilan.peer@xxxxxxxxx> When processing a re/association request frame and no corresponding station is found, try to find the station using the station MLD address from the basic ML element, as it is possible that the station is trying to re-associate but with different link address (in such a case the underlying driver would not perform address translations). When sending the association response, use the addresses from the request frame and not the AP MLD addresses, again, to avoid the address translation done in the driver. Signed-off-by: Ilan Peer <ilan.peer@xxxxxxxxx> Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@xxxxxxxxx> --- src/ap/ieee802_11.c | 156 +++++++++++++++++++++++++++++----------- src/ap/ieee802_11.h | 3 + src/ap/ieee802_11_eht.c | 82 +++++++++++++++++++++ 3 files changed, 198 insertions(+), 43 deletions(-) diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 85b02947a8..cc0a0582cf 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -4709,7 +4709,7 @@ static int add_associated_sta(struct hostapd_data *hapd, static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, const u8 *addr, u16 status_code, int reassoc, const u8 *ies, size_t ies_len, int rssi, - int omit_rsnxe) + int omit_rsnxe, int allow_mld_addr_trans) { int send_len; u8 *buf; @@ -4759,7 +4759,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, * Once a non-AP MLD is added to the driver, the addressing should use * MLD MAC address. */ - if (hapd->conf->mld_ap && sta && sta->mld_info.mld_sta) + if (hapd->conf->mld_ap && sta && sta->mld_info.mld_sta && + allow_mld_addr_trans) sa = hapd->mld_addr; #endif /* CONFIG_IEEE80211BE */ @@ -5125,7 +5126,7 @@ void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta) reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS, sta->fils_pending_assoc_is_reassoc, sta->fils_pending_assoc_req, - sta->fils_pending_assoc_req_len, 0, 0); + sta->fils_pending_assoc_req_len, 0, 0, 1); os_free(sta->fils_pending_assoc_req); sta->fils_pending_assoc_req = NULL; sta->fils_pending_assoc_req_len = 0; @@ -5159,6 +5160,89 @@ void fils_hlp_timeout(void *eloop_ctx, void *eloop_data) #endif /* CONFIG_FILS */ +#ifdef CONFIG_IEEE80211BE +static struct sta_info * +hostapd_ml_get_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, + struct hostapd_data **assoc_hapd) +{ + struct hostapd_data *other_hapd = NULL; + struct sta_info *tmp_sta; + + *assoc_hapd = hapd; + + /* The station is the one on which the association was performed */ + if (sta->mld_assoc_link_id == hapd->mld_link_id) + return sta; + + other_hapd = hostapd_mld_get_link_bss(hapd, sta->mld_assoc_link_id); + if (!other_hapd) { + wpa_printf(MSG_DEBUG, "MLD: No link match for link_id=%u", + sta->mld_assoc_link_id); + return sta; + } + + /* + * Iterate over the stations and find the one with the matching link ID + * and association ID. + */ + for (tmp_sta = other_hapd->sta_list; tmp_sta; tmp_sta = tmp_sta->next) { + if (tmp_sta->mld_assoc_link_id == sta->mld_assoc_link_id && + tmp_sta->aid == sta->aid) { + *assoc_hapd = other_hapd; + return tmp_sta; + } + } + + return sta; +} +#endif /* CONFIG_IEEE80211BE */ + + +static struct sta_info *handle_mlo_translate(struct hostapd_data *hapd, + struct ieee80211_mgmt *mgmt, + size_t len, int reassoc, + struct hostapd_data **assoc_hapd) +{ + struct sta_info *sta = NULL; + +#ifdef CONFIG_IEEE80211BE + struct ieee802_11_elems elems; + u8 mld_addr[ETH_ALEN]; + const u8 *pos; + + if (!hapd->iconf->ieee80211be || hapd->conf->disable_11be) + return NULL; + + if (reassoc) { + len -= IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req); + pos = mgmt->u.reassoc_req.variable; + } else { + len -= IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req); + pos = mgmt->u.assoc_req.variable; + } + + if (ieee802_11_parse_elems(pos, len, &elems, 1) == ParseFailed) + return NULL; + + if (hostapd_process_ml_assoc_req_addr(hapd, elems.basic_mle, + elems.basic_mle_len, + mld_addr)) + return NULL; + + sta = ap_get_sta(hapd, mld_addr); + if (!sta) + return NULL; + + wpa_printf(MSG_DEBUG, + "MLD: assoc: mld=" MACSTR ", link=" MACSTR, + MAC2STR(mld_addr), MAC2STR(mgmt->sa)); + + sta = hostapd_ml_get_assoc_sta(hapd, sta, assoc_hapd); +#endif /* CONFIG_IEEE80211BE */ + + return sta; +} + static void handle_assoc(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, @@ -5176,6 +5260,7 @@ static void handle_assoc(struct hostapd_data *hapd, #endif /* CONFIG_FILS */ int omit_rsnxe = 0; bool set_beacon = false; + bool mld_addrs_not_translated = false; if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) : sizeof(mgmt->u.assoc_req))) { @@ -5233,6 +5318,25 @@ static void handle_assoc(struct hostapd_data *hapd, } sta = ap_get_sta(hapd, mgmt->sa); + + /* + * It is possible that the association frame is from an associated + * non-AP MLD station, that tries to re-associate using different link + * addresses. In such a case, try to find the station based on the AP + * MLD address. + */ + if (!sta) { + struct hostapd_data *assoc_hapd; + sta = handle_mlo_translate(hapd, (struct ieee80211_mgmt *)mgmt, + len, reassoc, &assoc_hapd); + if (sta) { + wpa_printf(MSG_DEBUG, + "MLD: Switching to assoc hapd/station"); + hapd = assoc_hapd; + mld_addrs_not_translated = true; + } + } + #ifdef CONFIG_IEEE80211R_AP if (sta && sta->auth_alg == WLAN_AUTH_FT && (sta->flags & WLAN_STA_AUTH) == 0) { @@ -5553,8 +5657,12 @@ static void handle_assoc(struct hostapd_data *hapd, #endif /* CONFIG_FILS */ if (resp >= 0) - reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, - pos, left, rssi, omit_rsnxe); + reply_res = send_assoc_resp(hapd, + mld_addrs_not_translated ? + NULL : sta, + mgmt->sa, resp, reassoc, + pos, left, rssi, omit_rsnxe, + !mld_addrs_not_translated); os_free(tmp); /* @@ -5645,44 +5753,6 @@ static void hostapd_disassoc_sta(struct hostapd_data *hapd, } -#ifdef CONFIG_IEEE80211BE -static struct sta_info * -hostapd_ml_get_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, - struct hostapd_data **assoc_hapd) -{ - struct hostapd_data *other_hapd = NULL; - struct sta_info *tmp_sta; - - *assoc_hapd = hapd; - - /* The station is the one on which the association was performed */ - if (sta->mld_assoc_link_id == hapd->mld_link_id) - return sta; - - other_hapd = hostapd_mld_get_link_bss(hapd, sta->mld_assoc_link_id); - if (!other_hapd) { - wpa_printf(MSG_DEBUG, "MLD: No link match for link_id=%u", - sta->mld_assoc_link_id); - return sta; - } - - /* - * Iterate over the stations and find the one with the matching link ID - * and association ID. - */ - for (tmp_sta = other_hapd->sta_list; tmp_sta; tmp_sta = tmp_sta->next) { - if (tmp_sta->mld_assoc_link_id == sta->mld_assoc_link_id && - tmp_sta->aid == sta->aid) { - *assoc_hapd = other_hapd; - return tmp_sta; - } - } - - return sta; -} -#endif /* CONFIG_IEEE80211BE */ - - static bool hostapd_ml_handle_disconnect(struct hostapd_data *hapd, struct sta_info *sta, const struct ieee80211_mgmt *mgmt, diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index dce26c398d..3f89874e23 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -104,6 +104,9 @@ const u8 * hostapd_process_ml_auth(struct hostapd_data *hapd, u16 hostapd_process_ml_assoc_req(struct hostapd_data *hapd, struct ieee802_11_elems *elems, struct sta_info *sta); +int hostapd_process_ml_assoc_req_addr(struct hostapd_data *hapd, + const u8 *basic_mle, size_t basic_mle_len, + u8 *mld_addr); int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta); u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, const u8 *ht_capab); diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c index 3c5334a203..ed4579eac1 100644 --- a/src/ap/ieee802_11_eht.c +++ b/src/ap/ieee802_11_eht.c @@ -1040,6 +1040,88 @@ static int hostapd_mld_validate_assoc_info(struct hostapd_data *hapd, } +int hostapd_process_ml_assoc_req_addr(struct hostapd_data *hapd, + const u8 *basic_mle, size_t basic_mle_len, + u8 *mld_addr) +{ + struct wpabuf *mlbuf = ieee802_11_defrag(basic_mle, basic_mle_len, + true); + struct ieee80211_eht_ml *ml; + struct eht_ml_basic_common_info *common_info; + size_t ml_len, common_info_len; + u8 *pos; + int ret = -1; + u16 ml_control; + + if (!mlbuf) + return WLAN_STATUS_SUCCESS; + + ml = (struct ieee80211_eht_ml *)wpabuf_head(mlbuf); + ml_len = wpabuf_len(mlbuf); + + ml_control = le_to_host16(ml->ml_control); + if ((ml_control & MULTI_LINK_CONTROL_TYPE_MASK) != + MULTI_LINK_CONTROL_TYPE_BASIC) { + wpa_printf(MSG_DEBUG, "MLD: Invalid ML type=%u", + ml_control & MULTI_LINK_CONTROL_TYPE_MASK); + goto out; + } + + /* common info length and MLD address must always be present */ + common_info_len = 7; + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_LINK_ID) { + wpa_printf(MSG_DEBUG, "MLD: link ID info not expected"); + goto out; + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT) { + wpa_printf(MSG_DEBUG, "MLD: BSS params change not expected"); + goto out; + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO) { + wpa_printf(MSG_DEBUG, "MLD: sync delay not expected"); + goto out; + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) + common_info_len += 2; + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA) + common_info_len += 2; + + if (sizeof(*ml) + common_info_len > ml_len) { + wpa_printf(MSG_DEBUG, "MLD: not enough bytes for common info"); + goto out; + } + + common_info = (struct eht_ml_basic_common_info *)ml->variable; + + /* common information length includes the length octet */ + if (common_info->len != common_info_len) { + wpa_printf(MSG_DEBUG, + "MLD: invalid common info len=%u", common_info->len); + goto out; + } + + pos = common_info->variable; + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) + pos += 2; + + pos += 2; + + /* get the MLD Address */ + os_memcpy(mld_addr, common_info->mld_addr, ETH_ALEN); + ret = 0; + +out: + wpabuf_free(mlbuf); + return ret; +} + + u16 hostapd_process_ml_assoc_req(struct hostapd_data *hapd, struct ieee802_11_elems *elems, struct sta_info *sta) -- 2.38.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap