[PATCH 25/50] AP: MLO: Handle deauth/disassoc of MLD station
Andrei Otcheretianski
andrei.otcheretianski at intel.com
Wed Feb 15 15:08:39 PST 2023
From: Ilan Peer <ilan.peer at intel.com>
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 at intel.com>
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
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
More information about the Hostap
mailing list