From e996704201e7ef6eedf655322f8c402cf65d1539 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Tue, 21 Nov 2023 01:51:42 +0200 Subject: [PATCH] AP: Handle re-association from a non-AP MLD When processing a (Re)Association Request frame and no corresponding station is found, try to find the station using the station MLD MAC address from the Basic ML element, as it is possible that the station is trying to re-associate but with a different link address (in such a case the underlying driver would not perform address translations). When sending the (Re)Association Response frame, use the addresses from the (Re)Association Request frame and not the AP MLD MAC address, again, to avoid the address translation done in the driver. Signed-off-by: Ilan Peer Signed-off-by: Andrei Otcheretianski --- src/ap/ieee802_11.c | 86 ++++++++++++++++++++++++++++++++++++++--- src/ap/ieee802_11.h | 3 ++ src/ap/ieee802_11_eht.c | 79 +++++++++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+), 5 deletions(-) diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index e38956fe9..40dda80aa 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -85,6 +85,11 @@ static void handle_auth(struct hostapd_data *hapd, int rssi, int from_queue); static int add_associated_sta(struct hostapd_data *hapd, struct sta_info *sta, int reassoc); +#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); +#endif /* CONFIG_IEEE80211BE */ u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid) @@ -4709,7 +4714,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, bool allow_mld_addr_trans) { int send_len; u8 *buf; @@ -4759,7 +4764,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 +5131,8 @@ 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, + true); os_free(sta->fils_pending_assoc_req); sta->fils_pending_assoc_req = NULL; sta->fils_pending_assoc_req_len = 0; @@ -5160,6 +5167,48 @@ void fils_hlp_timeout(void *eloop_ctx, void *eloop_data) #endif /* CONFIG_FILS */ +#ifdef CONFIG_IEEE80211BE +static struct sta_info * handle_mlo_translate(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + size_t len, bool reassoc, + struct hostapd_data **assoc_hapd) +{ + struct sta_info *sta; + 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)); + + return hostapd_ml_get_assoc_sta(hapd, sta, assoc_hapd); +} +#endif /* CONFIG_IEEE80211BE */ + + static void handle_assoc(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, int reassoc, int rssi) @@ -5176,6 +5225,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 +5283,28 @@ static void handle_assoc(struct hostapd_data *hapd, } sta = ap_get_sta(hapd, mgmt->sa); + +#ifdef CONFIG_IEEE80211BE + /* + * 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 MAC address. + */ + if (!sta) { + struct hostapd_data *assoc_hapd; + + sta = handle_mlo_translate(hapd, 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; + } + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_IEEE80211R_AP if (sta && sta->auth_alg == WLAN_AUTH_FT && (sta->flags & WLAN_STA_AUTH) == 0) { @@ -5553,8 +5625,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); /* diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index dce26c398..3f89874e2 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 c40c19a02..fc02f1198 100644 --- a/src/ap/ieee802_11_eht.c +++ b/src/ap/ieee802_11_eht.c @@ -1050,6 +1050,85 @@ 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; + 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); + + if (ml_len < sizeof(*ml)) + goto out; + + 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 MAC Address must always be present */ + common_info_len = 1 + ETH_ALEN; + + 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 Parameters Change Count not expected"); + goto out; + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO) { + wpa_printf(MSG_DEBUG, + "MLD: Medium Synchronization Delay Information 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; + } + + /* Get the MLD MAC 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)