From: Ilan Peer <ilan.peer@xxxxxxxxx> When a station is deauthenticated/disassociated from an MLD AP, make sure to cleanup its state from all links. Signed-off-by: Ilan Peer <ilan.peer@xxxxxxxxx> Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@xxxxxxxxx> --- src/ap/ieee802_11.c | 220 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 187 insertions(+), 33 deletions(-) diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index b090ee6105..8dba283758 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -5462,28 +5462,39 @@ static void handle_assoc(struct hostapd_data *hapd, } -static void handle_disassoc(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len) +static void hostapd_deauth_sta(struct hostapd_data *hapd, + struct sta_info *sta, + const struct ieee80211_mgmt *mgmt) { - struct sta_info *sta; + wpa_msg(hapd->msg_ctx, MSG_DEBUG, + "deauthentication: STA=" MACSTR " reason_code=%d", + MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code)); + + ap_sta_set_authorized(hapd, sta, 0); + sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; + sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | + WLAN_STA_ASSOC_REQ_OK); + hostapd_set_sta_flags(hapd, sta); + wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, "deauthenticated"); + mlme_deauthenticate_indication( + hapd, sta, le_to_host16(mgmt->u.deauth.reason_code)); + sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; + ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); + ap_free_sta(hapd, sta); +} - if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) { - wpa_printf(MSG_INFO, "handle_disassoc - too short payload (len=%lu)", - (unsigned long) len); - return; - } - wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d", +static void hostapd_disassoc_sta(struct hostapd_data *hapd, + struct sta_info *sta, + const struct ieee80211_mgmt *mgmt) +{ + wpa_printf(MSG_DEBUG, + "disassocation: STA=" MACSTR " reason_code=%d", MAC2STR(mgmt->sa), le_to_host16(mgmt->u.disassoc.reason_code)); - sta = ap_get_sta(hapd, mgmt->sa); - if (sta == NULL) { - wpa_printf(MSG_INFO, "Station " MACSTR " trying to disassociate, but it is not associated", - MAC2STR(mgmt->sa)); - return; - } - ap_sta_set_authorized(hapd, sta, 0); sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); @@ -5527,6 +5538,162 @@ static void handle_disassoc(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; + u8 i; + + *assoc_hapd = hapd; + + /* The station is the one on which the association was performed */ + if (sta->mld_assoc_link_id == hapd->conf->mld_link_id) + return sta; + + /* Find the hapd with the corresponding link ID */ + for (i = 0; i < hapd->iface->interfaces->count; i++) { + other_hapd = hapd->iface->interfaces->iface[i]->bss[0]; + + if (hapd == other_hapd) + continue; + + if (other_hapd->conf->mld_ap && + hapd->conf->mld_id == other_hapd->conf->mld_id && + sta->mld_assoc_link_id == other_hapd->conf->mld_link_id) + break; + } + + if (!other_hapd || i == hapd->iface->interfaces->count) { + 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, + bool disassoc) +{ +#ifdef CONFIG_IEEE80211BE + struct hostapd_data *assoc_hapd, *tmp_hapd; + struct sta_info *assoc_sta; + u8 i, link_id; + + if (!hostapd_is_mld_ap(hapd)) + return false; + + /* + * Get the station on which the association was performed, as it holds + * the information about all the other links + */ + assoc_sta = hostapd_ml_get_assoc_sta(hapd, sta, &assoc_hapd); + + for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + for (i = 0; i < assoc_hapd->iface->interfaces->count; i++) { + struct sta_info *tmp_sta; + + if (!assoc_sta->mld_info.links[link_id].valid) + continue; + + tmp_hapd = + assoc_hapd->iface->interfaces->iface[i]->bss[0]; + + if (!tmp_hapd->conf->mld_ap || + assoc_hapd->conf->mld_id != tmp_hapd->conf->mld_id) + continue; + + for (tmp_sta = tmp_hapd->sta_list; tmp_sta; + tmp_sta = tmp_sta->next) { + /* + * remove the station on which the association + * was done only after all other link station + * are removed. Since there is a only a single + * station per hapd with the same association + * link simply break; + */ + if (tmp_sta == assoc_sta) + break; + + if (tmp_sta->mld_assoc_link_id != + assoc_sta->mld_assoc_link_id || + tmp_sta->aid != assoc_sta->aid) + continue; + + if (!disassoc) + hostapd_deauth_sta(tmp_hapd, tmp_sta, + mgmt); + else + hostapd_disassoc_sta(tmp_hapd, tmp_sta, + mgmt); + break; + } + } + } + + /* remove the station on which the association was performed */ + if (!disassoc) + hostapd_deauth_sta(assoc_hapd, assoc_sta, mgmt); + else + hostapd_disassoc_sta(assoc_hapd, assoc_sta, mgmt); + + return true; +#else + return false; +#endif /* CONFIG_IEEE80211BE */ +} + + +static void handle_disassoc(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, size_t len) +{ + struct sta_info *sta; + + if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) { + wpa_printf(MSG_INFO, + "handle_disassoc - too short payload (len=%lu)", + (unsigned long) len); + return; + } + + sta = ap_get_sta(hapd, mgmt->sa); + if (!sta) { + wpa_printf(MSG_INFO, + "Station " MACSTR " trying to disassociate, but it is not associated", + MAC2STR(mgmt->sa)); + return; + } + + if (hostapd_ml_handle_disconnect(hapd, sta, mgmt, true)) + return; + + hostapd_disassoc_sta(hapd, sta, mgmt); +} + + static void handle_deauth(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { @@ -5538,10 +5705,6 @@ static void handle_deauth(struct hostapd_data *hapd, return; } - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR - " reason_code=%d", - MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code)); - /* Clear the PTKSA cache entries for PASN */ ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE); @@ -5553,19 +5716,10 @@ static void handle_deauth(struct hostapd_data *hapd, return; } - ap_sta_set_authorized(hapd, sta, 0); - sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | - WLAN_STA_ASSOC_REQ_OK); - hostapd_set_sta_flags(hapd, sta); - wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "deauthenticated"); - mlme_deauthenticate_indication( - hapd, sta, le_to_host16(mgmt->u.deauth.reason_code)); - sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - ap_free_sta(hapd, sta); + if (hostapd_ml_handle_disconnect(hapd, sta, mgmt, false)) + return; + + hostapd_deauth_sta(hapd, sta, mgmt); } -- 2.38.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap