}
sta->flags |= origin_sta->flags | WLAN_STA_ASSOC_REQ_OK;
+ sta->mld_assoc_link_id = origin_sta->mld_assoc_link_id;
+
status = __check_assoc_ies(hapd, sta, NULL, 0, &elems, reassoc, true);
if (status != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG, "MLD: link: Element check failed");
}
ap_sta_set_mld(sta, true);
- sta->mld_assoc_link_id = origin_sta->mld_assoc_link_id;
os_memcpy(&sta->mld_info, &origin_sta->mld_info, sizeof(sta->mld_info));
for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
ieee802_11_update_beacons(hapd->iface);
}
- /* RSN Authenticator should always be the one on the original station */
+ /* Maintain state machine reference on all link STAs, this is needed
+ * during group rekey handling.
+ */
wpa_auth_sta_deinit(sta->wpa_sm);
- sta->wpa_sm = NULL;
+ sta->wpa_sm = origin_sta->wpa_sm;
/*
* Do not initialize the EAPOL state machine.
}
+#ifdef CONFIG_IEEE80211BE
+static void clear_wpa_sm_for_each_partner_link(struct hostapd_data *hapd,
+ struct sta_info *psta)
+{
+ struct sta_info *lsta;
+ struct hostapd_data *lhapd;
+
+ if (!ap_sta_is_mld(hapd, psta))
+ return;
+
+ for_each_mld_link(lhapd, hapd) {
+ if (lhapd == hapd)
+ continue;
+
+ lsta = ap_get_sta(lhapd, psta->addr);
+ if (lsta)
+ lsta->wpa_sm = NULL;
+ }
+}
+#endif /* CONFIG_IEEE80211BE */
+
+
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_beacon = 0;
#ifdef CONFIG_IEEE80211BE
if (!ap_sta_is_mld(hapd, sta) ||
- hapd->mld_link_id == sta->mld_assoc_link_id)
+ hapd->mld_link_id == sta->mld_assoc_link_id) {
wpa_auth_sta_deinit(sta->wpa_sm);
+ /* Remove references from partner links. */
+ clear_wpa_sm_for_each_partner_link(hapd, sta);
+ }
+
+ /* Release group references in case non-association link STA is removed
+ * before association link STA */
+ if (hostapd_sta_is_link_sta(hapd, sta))
+ wpa_release_link_auth_ref(sta->wpa_sm, hapd->mld_link_id);
#else /* CONFIG_IEEE80211BE */
wpa_auth_sta_deinit(sta->wpa_sm);
#endif /* CONFIG_IEEE80211BE */
ieee802_1x_free_station(hapd, sta);
#ifdef CONFIG_IEEE80211BE
if (!hapd->conf->mld_ap ||
- hapd->mld_link_id == sta->mld_assoc_link_id)
+ hapd->mld_link_id == sta->mld_assoc_link_id) {
wpa_auth_sta_deinit(sta->wpa_sm);
+ clear_wpa_sm_for_each_partner_link(hapd, sta);
+ }
#else /* CONFIG_IEEE80211BE */
wpa_auth_sta_deinit(sta->wpa_sm);
#endif /* CONFIG_IEEE80211BE */
}
+#ifdef CONFIG_IEEE80211BE
+
+void wpa_release_link_auth_ref(struct wpa_state_machine *sm,
+ int release_link_id)
+{
+ int link_id;
+
+ if (!sm || release_link_id >= MAX_NUM_MLD_LINKS)
+ return;
+
+ for_each_sm_auth(sm, link_id) {
+ if (link_id == release_link_id) {
+ wpa_group_put(sm->mld_links[link_id].wpa_auth,
+ sm->mld_links[link_id].wpa_auth->group);
+ sm->mld_links[link_id].wpa_auth = NULL;
+ }
+ }
+}
+
+
+struct wpa_get_link_auth_ctx {
+ const u8 *addr;
+ struct wpa_authenticator *wpa_auth;
+};
+
+static int wpa_get_link_sta_auth(struct wpa_authenticator *wpa_auth, void *data)
+{
+ struct wpa_get_link_auth_ctx *ctx = data;
+
+ if (!ether_addr_equal(wpa_auth->addr, ctx->addr))
+ return 0;
+ ctx->wpa_auth = wpa_auth;
+ return 1;
+}
+
+
+static int wpa_get_primary_auth_cb(struct wpa_authenticator *wpa_auth,
+ void *data)
+{
+ struct wpa_get_link_auth_ctx *ctx = data;
+
+ if (!wpa_auth->is_ml ||
+ !ether_addr_equal(wpa_auth->mld_addr, ctx->addr) ||
+ !wpa_auth->primary_auth)
+ return 0;
+
+ ctx->wpa_auth = wpa_auth;
+ return 1;
+}
+
+
+static struct wpa_authenticator *
+wpa_get_primary_auth(struct wpa_authenticator *wpa_auth)
+{
+ struct wpa_get_link_auth_ctx ctx;
+
+ if (!wpa_auth || !wpa_auth->is_ml || wpa_auth->primary_auth)
+ return wpa_auth;
+
+ ctx.addr = wpa_auth->mld_addr;
+ ctx.wpa_auth = NULL;
+ wpa_auth_for_each_auth(wpa_auth, wpa_get_primary_auth_cb, &ctx);
+
+ return ctx.wpa_auth;
+}
+
+#endif /* CONFIG_IEEE80211BE */
+
+
static inline int wpa_auth_mic_failure_report(
struct wpa_authenticator *wpa_auth, const u8 *addr)
{
wpa_auth = os_zalloc(sizeof(struct wpa_authenticator));
if (!wpa_auth)
return NULL;
+
os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
+
+#ifdef CONFIG_IEEE80211BE
+ if (conf->mld_addr) {
+ wpa_auth->is_ml = true;
+ wpa_auth->link_id = conf->link_id;
+ wpa_auth->primary_auth = !conf->first_link_auth;
+ os_memcpy(wpa_auth->mld_addr, conf->mld_addr, ETH_ALEN);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
wpa_auth->cb = cb;
wpa_auth->cb_ctx = cb_ctx;
static void wpa_free_sta_sm(struct wpa_state_machine *sm)
{
+#ifdef CONFIG_IEEE80211BE
+ int link_id;
+#endif /* CONFIG_IEEE80211BE */
+
#ifdef CONFIG_P2P
if (WPA_GET_BE32(sm->ip_addr)) {
wpa_printf(MSG_DEBUG,
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
os_free(sm->rsnxe);
+#ifdef CONFIG_IEEE80211BE
+ for_each_sm_auth(sm, link_id) {
+ wpa_group_put(sm->mld_links[link_id].wpa_auth,
+ sm->mld_links[link_id].wpa_auth->group);
+ sm->mld_links[link_id].wpa_auth = NULL;
+ }
+#endif /* CONFIG_IEEE80211BE */
wpa_group_put(sm->wpa_auth, sm->group);
#ifdef CONFIG_DPP2
wpabuf_clear_free(sm->dpp_z);
wpa_auth = sm->wpa_auth;
if (wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
+ struct wpa_authenticator *primary_auth = wpa_auth;
+
wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"strict rekeying - force GTK rekey since STA is leaving");
+
+#ifdef CONFIG_IEEE80211BE
+ if (wpa_auth->is_ml && !wpa_auth->primary_auth)
+ primary_auth = wpa_get_primary_auth(wpa_auth);
+#endif /* CONFIG_IEEE80211BE */
+
if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk,
- wpa_auth, NULL) == -1)
+ primary_auth, NULL) == -1)
eloop_register_timeout(0, 500000, wpa_rekey_gtk,
- wpa_auth, NULL);
+ primary_auth, NULL);
}
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
struct mld_link_info *link = &info->links[link_id];
struct mld_link *sm_link = &sm->mld_links[link_id];
+ struct wpa_get_link_auth_ctx ctx;
sm_link->valid = link->valid;
if (!link->valid)
MAC2STR(sm_link->own_addr),
MAC2STR(sm_link->peer_addr));
- if (link_id != mld_assoc_link_id)
+ ml_rsn_info.links[i++].link_id = link_id;
+
+ if (link_id != mld_assoc_link_id) {
sm->n_mld_affiliated_links++;
+ ctx.addr = link->local_addr;
+ ctx.wpa_auth = NULL;
+ wpa_auth_for_each_auth(sm->wpa_auth,
+ wpa_get_link_sta_auth, &ctx);
+ if (ctx.wpa_auth) {
+ sm_link->wpa_auth = ctx.wpa_auth;
+ wpa_group_get(sm_link->wpa_auth,
+ sm_link->wpa_auth->group);
+ }
+ } else {
+ sm_link->wpa_auth = sm->wpa_auth;
+ }
- ml_rsn_info.links[i++].link_id = link_id;
+ if (!sm_link->wpa_auth)
+ wpa_printf(MSG_ERROR,
+ "Unable to find authenticator object for ML STA "
+ MACSTR " on link " MACSTR " link id %d",
+ MAC2STR(sm->own_mld_addr),
+ MAC2STR(sm_link->own_addr),
+ link_id);
}
ml_rsn_info.n_mld_links = i;