AP MLD: Enhance authenticator state machine

Add required ML specific members in struct wpa_authenticator and struct
wpa_state_machine to maintain self and partner link information.

Maintain state machine object in all associated link stations and
destroy/remove references from the same whenever link stations are
getting removed.

Increase the wpa_group object reference count for all links in which ML
station is getting associated and release the same whenever link
stations are getting removed.

Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
This commit is contained in:
Rameshkumar Sundaram 2024-03-28 23:46:46 +05:30 committed by Jouni Malinen
parent 19fdcf511b
commit 3ea7cf11db
6 changed files with 209 additions and 10 deletions

View file

@ -4456,6 +4456,8 @@ static int ieee80211_ml_process_link(struct hostapd_data *hapd,
}
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");
@ -4463,7 +4465,6 @@ static int ieee80211_ml_process_link(struct hostapd_data *hapd,
}
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++) {
@ -4490,9 +4491,11 @@ static int ieee80211_ml_process_link(struct hostapd_data *hapd,
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.

View file

@ -200,6 +200,28 @@ static void __ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
}
#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;
@ -317,8 +339,16 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
#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 */
@ -903,8 +933,10 @@ static void ap_sta_disconnect_common(struct hostapd_data *hapd,
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 */

View file

@ -103,6 +103,75 @@ static const u8 * wpa_auth_get_spa(const struct wpa_state_machine *sm)
}
#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)
{
@ -537,8 +606,19 @@ struct wpa_authenticator * wpa_init(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;
@ -798,6 +878,10 @@ void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)
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,
@ -821,6 +905,13 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
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);
@ -838,12 +929,20 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
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);
@ -6835,6 +6934,7 @@ void wpa_auth_set_ml_info(struct wpa_state_machine *sm, const u8 *mld_addr,
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)
@ -6849,10 +6949,30 @@ void wpa_auth_set_ml_info(struct wpa_state_machine *sm, const u8 *mld_addr,
MAC2STR(sm_link->own_addr),
MAC2STR(sm_link->peer_addr));
if (link_id != mld_assoc_link_id)
sm->n_mld_affiliated_links++;
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;
}
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;

View file

@ -285,6 +285,12 @@ struct wpa_auth_config {
* Set only in nontransmitted BSSs, i.e., is NULL for transmitted BSS
* and in BSSs that are not part of a Multi-BSSID set. */
struct wpa_authenticator *tx_bss_auth;
#ifdef CONFIG_IEEE80211BE
const u8 *mld_addr;
int link_id;
struct wpa_authenticator *first_link_auth;
#endif /* CONFIG_IEEE80211BE */
};
typedef enum {
@ -647,4 +653,13 @@ void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
struct wpa_auth_ml_link_key_info *info,
bool mgmt_frame_prot, bool beacon_prot);
void wpa_release_link_auth_ref(struct wpa_state_machine *sm,
int release_link_id);
#define for_each_sm_auth(sm, link_id) \
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) \
if (sm->mld_links[link_id].valid && \
sm->mld_links[link_id].wpa_auth && \
sm->wpa_auth != sm->mld_links[link_id].wpa_auth)
#endif /* WPA_AUTH_H */

View file

@ -1747,6 +1747,27 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
!!(hapd->iface->drv_flags2 &
WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP);
#ifdef CONFIG_IEEE80211BE
_conf.mld_addr = NULL;
_conf.link_id = -1;
_conf.first_link_auth = NULL;
if (hapd->conf->mld_ap) {
struct hostapd_data *lhapd;
_conf.mld_addr = hapd->mld->mld_addr;
_conf.link_id = hapd->mld_link_id;
for_each_mld_link(lhapd, hapd) {
if (lhapd == hapd)
continue;
if (lhapd->wpa_auth)
_conf.first_link_auth = lhapd->wpa_auth;
}
}
#endif /* CONFIG_IEEE80211BE */
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
if (hapd->wpa_auth == NULL) {
wpa_printf(MSG_ERROR, "WPA initialization failed.");

View file

@ -186,6 +186,7 @@ struct wpa_state_machine {
size_t rsne_len;
const u8 *rsnxe;
size_t rsnxe_len;
struct wpa_authenticator *wpa_auth;
} mld_links[MAX_NUM_MLD_LINKS];
#endif /* CONFIG_IEEE80211BE */
};
@ -262,6 +263,13 @@ struct wpa_authenticator {
#ifdef CONFIG_P2P
struct bitfield *ip_pool;
#endif /* CONFIG_P2P */
#ifdef CONFIG_IEEE80211BE
bool is_ml;
u8 mld_addr[ETH_ALEN];
u8 link_id;
bool primary_auth;
#endif /* CONFIG_IEEE80211BE */
};