wlan-ap-Telecominfraproject/feeds/qca/hostapd/patches/r01-001-hostapd-Enhance-wpa-state-machine-for-MLO-and-add-su.patch
John Crispin 008ca9618d
Some checks failed
Build OpenWrt/uCentral images / build (cig_wf186h) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cig_wf186w) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cig_wf188n) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cig_wf189) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cig_wf196) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cybertan_eww631-a1) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cybertan_eww631-b1) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap101) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap102) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap104) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap105) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap111) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap112) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_oap101) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_oap101-6e) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_oap101e) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_oap101e-6e) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4x) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4x_2) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4x_3) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4x_w) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4xe) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4xi) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4xi_w) (push) Has been cancelled
Build OpenWrt/uCentral images / build (indio_um-305ax) (push) Has been cancelled
Build OpenWrt/uCentral images / build (sercomm_ap72tip) (push) Has been cancelled
Build OpenWrt/uCentral images / build (sonicfi_rap630c-311g) (push) Has been cancelled
Build OpenWrt/uCentral images / build (sonicfi_rap630w-211g) (push) Has been cancelled
Build OpenWrt/uCentral images / build (sonicfi_rap630w-311g) (push) Has been cancelled
Build OpenWrt/uCentral images / build (udaya_a6-id2) (push) Has been cancelled
Build OpenWrt/uCentral images / build (udaya_a6-od2) (push) Has been cancelled
Build OpenWrt/uCentral images / build (wallys_dr5018) (push) Has been cancelled
Build OpenWrt/uCentral images / build (wallys_dr6018) (push) Has been cancelled
Build OpenWrt/uCentral images / build (wallys_dr6018-v4) (push) Has been cancelled
Build OpenWrt/uCentral images / build (yuncore_ax820) (push) Has been cancelled
Build OpenWrt/uCentral images / build (yuncore_ax840) (push) Has been cancelled
Build OpenWrt/uCentral images / build (yuncore_fap640) (push) Has been cancelled
Build OpenWrt/uCentral images / build (yuncore_fap650) (push) Has been cancelled
Build OpenWrt/uCentral images / build (yuncore_fap655) (push) Has been cancelled
Build OpenWrt/uCentral images / trigger-testing (push) Has been cancelled
Build OpenWrt/uCentral images / create-x64_vm-ami (push) Has been cancelled
ipq95xx: import ath12.4-cs kernel and drivers
Signed-off-by: John Crispin <john@phrozen.org>
2024-10-20 09:25:13 +02:00

1184 lines
36 KiB
Diff

From bb85c12bfdb6cc7ba55e5bc3b87ebc9a3062da83 Mon Sep 17 00:00:00 2001
From: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Date: Mon, 9 Oct 2023 09:38:00 +0530
Subject: [PATCH] hostapd: Enhance wpa state machine for MLO and add support
for ML Rekey
Currently wpa group rekey is not supported for ML Stations when
non assoc link initiates a group rekey, to support the same
following changes have been made,
Add required ML Specific members in 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.
Calculate links specific MLO GTK/IGTK and BIGTK KDE lengths based on
corresponding cipher and key instead of taking length of one link and
multiplying it by no of associated links.
For MLD, Arm group key rekey timer on one of the links and
whenever it fires do group key rekey for all links.
Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
---
src/ap/drv_callbacks.c | 2 +-
src/ap/hostapd.c | 2 -
src/ap/ieee802_11.c | 102 ++---
src/ap/sta_info.c | 35 +-
src/ap/sta_info.h | 18 +
src/ap/wpa_auth.c | 383 +++++++++++++++---
src/ap/wpa_auth.h | 8 +-
src/ap/wpa_auth_glue.c | 10 +
src/ap/wpa_auth_i.h | 6 +
src/ap/wpa_auth_ie.c | 11 +-
src/common/wpa_common.h | 1 +
tests/fuzzing/eapol-key-auth/eapol-key-auth.c | 2 +-
wpa_supplicant/ibss_rsn.c | 2 +-
13 files changed, 470 insertions(+), 112 deletions(-)
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -376,7 +376,7 @@ int hostapd_notif_assoc(struct hostapd_d
elems.rsnxe ? elems.rsnxe - 2 : NULL,
elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len,
- elems.owe_dh, elems.owe_dh_len);
+ elems.owe_dh, elems.owe_dh_len, NULL);
reason = WLAN_REASON_INVALID_IE;
status = WLAN_STATUS_INVALID_IE;
switch (res) {
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1558,7 +1558,6 @@ setup_mld:
}
if (hostapd_init_wps(hapd, conf))
return -1;
-
#ifdef CONFIG_DPP
hapd->gas = gas_query_ap_init(hapd, hapd->msg_ctx);
if (!hapd->gas)
@@ -1582,7 +1581,6 @@ setup_mld:
wpa_printf(MSG_ERROR, "Accounting initialization failed.");
return -1;
}
-
#ifdef CONFIG_INTERWORKING
if (gas_serv_init(hapd)) {
wpa_printf(MSG_ERROR, "GAS server initialization failed");
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -87,6 +87,44 @@ static int add_associated_sta(struct hos
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)
+{
+ struct hostapd_data *other_hapd = NULL;
+ struct sta_info *tmp_sta;
+
+ *assoc_hapd = hapd;
+
+ /* The station is the one on which the association was performed */
+ if (sta->mld_assoc_link_id == hapd->mld_link_id)
+ return sta;
+
+ other_hapd = hostapd_mld_get_link_bss(hapd, sta->mld_assoc_link_id);
+ if (!other_hapd) {
+ wpa_printf(MSG_DEBUG, "%s MLD: No link match for link_id=%u",
+ __func__, 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 */
+
+
u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid)
{
u8 multi_ap_val = 0;
@@ -1865,7 +1903,7 @@ void handle_auth_fils(struct hostapd_dat
elems.rsn_ie - 2, elems.rsn_ie_len + 2,
elems.rsnxe ? elems.rsnxe - 2 : NULL,
elems.rsnxe ? elems.rsnxe_len + 2 : 0,
- elems.mdie, elems.mdie_len, NULL, 0);
+ elems.mdie, elems.mdie_len, NULL, 0, NULL);
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
goto fail;
@@ -3188,10 +3226,11 @@ static void handle_auth(struct hostapd_d
#ifdef CONFIG_MESH
if (status_code == WLAN_STATUS_SUCCESS &&
hapd->conf->mesh & MESH_ENABLED) {
- if (sta->wpa_sm == NULL)
+ if (sta->wpa_sm == NULL) {
sta->wpa_sm =
wpa_auth_sta_init(hapd->wpa_auth,
sta->addr, NULL);
+ }
if (sta->wpa_sm == NULL) {
wpa_printf(MSG_DEBUG,
"SAE: Failed to initialize WPA state machine");
@@ -3714,7 +3753,7 @@ u16 owe_process_rsn_ie(struct hostapd_da
rsn_ie_len += 2;
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq, rsn_ie, rsn_ie_len,
- NULL, 0, NULL, 0, owe_dh, owe_dh_len);
+ NULL, 0, NULL, 0, owe_dh, owe_dh_len, NULL);
status = wpa_res_to_status_code(res);
if (status != WLAN_STATUS_SUCCESS)
goto end;
@@ -3802,6 +3841,8 @@ static int __check_assoc_ies(struct host
const u8 *wpa_ie;
size_t wpa_ie_len;
const u8 *p2p_dev_addr = NULL;
+ struct hostapd_data *assoc_hapd;
+ struct sta_info *assoc_sta = NULL;
const struct element *elem;
@@ -3994,7 +4035,8 @@ static int __check_assoc_ies(struct host
#ifdef CONFIG_IEEE80211BE
struct mld_info *info = &sta->mld_info;
#endif /* CONFIG_IEEE80211BE */
-
+ if (!link)
+ assoc_sta = hostapd_ml_get_assoc_sta(hapd, sta, &assoc_hapd);
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
sta->addr,
p2p_dev_addr);
@@ -4026,7 +4068,8 @@ static int __check_assoc_ies(struct host
elems->rsnxe ? elems->rsnxe_len + 2 :
0,
elems->mdie, elems->mdie_len,
- elems->owe_dh, elems->owe_dh_len);
+ elems->owe_dh, elems->owe_dh_len,
+ assoc_sta ? assoc_sta->wpa_sm : NULL);
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
@@ -4412,6 +4455,7 @@ static void ieee80211_ml_process_link(st
}
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");
@@ -4419,7 +4463,6 @@ static void ieee80211_ml_process_link(st
}
sta->mld_info.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));
@@ -4437,9 +4480,11 @@ static void ieee80211_ml_process_link(st
sta->listen_interval = origin_sta->listen_interval;
update_ht_state(hapd, sta);
- /* RSN Authenticator should always be the one on the original station */
wpa_auth_sta_deinit(sta->wpa_sm);
- sta->wpa_sm = NULL;
+ /* Maintain state machine reference on all link STAs, this is needed
+ * during Group rekey handling.
+ */
+ sta->wpa_sm = origin_sta->wpa_sm;
/*
* Do not initialize the EAPOL state machine.
@@ -4471,6 +4516,7 @@ out:
if (sta && status != WLAN_STATUS_SUCCESS)
ap_free_sta(hapd, sta);
+ /* ToDO if link is not accepted remove its data from ml info of assoc sta? */
link->resp_sta_profile_len =
ieee80211_ml_build_assoc_resp(hapd, link->status,
link->resp_sta_profile,
@@ -4519,7 +4565,7 @@ static void hostapd_process_assoc_ml_inf
struct mld_link_info *link = &sta->mld_info.links[i];
bool link_bss_found = false;
- if (!link->valid)
+ if (!link->valid || i == sta->mld_assoc_link_id)
continue;
for_each_partner_bss(bss, hapd) {
@@ -5647,44 +5693,6 @@ static void hostapd_disassoc_sta(struct
}
-#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;
-
- *assoc_hapd = hapd;
-
- /* The station is the one on which the association was performed */
- if (sta->mld_assoc_link_id == hapd->mld_link_id)
- return sta;
-
- other_hapd = hostapd_mld_get_link_bss(hapd, sta->mld_assoc_link_id);
- if (!other_hapd) {
- 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,
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -304,8 +304,16 @@ void ap_free_sta(struct hostapd_data *ha
#ifdef CONFIG_IEEE80211BE
if (!hapd->conf->mld_ap || !sta->mld_info.mld_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 refrences from partner links.*/
+ SET_EACH_PARTNER_STA_OBJ(hapd, sta, wpa_sm, NULL);
+ }
+ /* release group references in case non assoc link STA is removed
+ * before assoc link STA
+ */
+ if (sta->mld_info.mld_sta && hapd->mld_link_id != sta->mld_assoc_link_id)
+ wpa_release_link_auth_ref(sta->wpa_sm, hapd->mld_link_id);
#else
wpa_auth_sta_deinit(sta->wpa_sm);
#endif /* CONFIG_IEEE80211BE */
@@ -785,7 +793,31 @@ struct sta_info * ap_sta_add(struct host
return sta;
}
+int set_for_each_partner_link_sta(struct hostapd_data *hapd,
+ struct sta_info *psta,
+ void *data,
+ int (*cb)(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ void *data))
+{
+ struct sta_info *lsta;
+ struct hostapd_data *lhapd;
+ int ret = 0;
+
+ if (!psta->mld_info.mld_sta)
+ return 0;
+ for_each_partner_bss(lhapd, hapd) {
+ if (lhapd == hapd)
+ continue;
+ lsta = ap_get_sta(lhapd, psta->addr);
+ if (lsta)
+ ret = cb(lhapd, lsta, data);
+ if (ret)
+ return ret;
+ }
+ return ret;
+}
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
{
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@@ -879,8 +911,10 @@ void ap_sta_disassociate(struct hostapd_
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);
+ SET_EACH_PARTNER_STA_OBJ(hapd, sta, wpa_sm, NULL);
+ }
#else
wpa_auth_sta_deinit(sta->wpa_sm);
#endif /* CONFIG_IEEE80211BE */
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -358,7 +358,25 @@ struct sta_info {
/* Number of seconds to keep STA entry after it has been deauthenticated. */
#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5)
+#define DEFINE_PARTNER_STA_FUNC_CB(obj_name) \
+static inline int set_partner_sta_cb_##obj_name(struct hostapd_data *hapd, \
+ struct sta_info *sta, \
+ void *data) \
+{ \
+ sta->obj_name = data; \
+ return 0; \
+}
+#define SET_EACH_PARTNER_STA_OBJ(hapd, sta, objname, data) \
+set_for_each_partner_link_sta(hapd, sta, data, set_partner_sta_cb_##objname)
+
+DEFINE_PARTNER_STA_FUNC_CB(wpa_sm)
+int set_for_each_partner_link_sta(struct hostapd_data *hapd,
+ struct sta_info *psta,
+ void *data,
+ int (*cb)(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ void *data));
int ap_for_each_sta(struct hostapd_data *hapd,
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
void *ctx),
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -102,6 +102,81 @@ static const u8 * wpa_auth_get_spa(const
return sm->addr;
}
+#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) \
+
+void wpa_update_gkeydone(struct wpa_state_machine *sm, int update)
+{
+ int link_id;
+ struct wpa_authenticator *wpa_auth;
+
+ if (!sm || !sm->wpa_auth)
+ return;
+
+ sm->wpa_auth->group->GKeyDoneStations += update;
+
+ for_each_sm_auth(sm, link_id)
+ sm->mld_links[link_id].wpa_auth->group->GKeyDoneStations += update;
+}
+
+void wpa_release_link_auth_ref(struct wpa_state_machine *sm, int release_link_id)
+{
+ int link_id;
+
+ if (!sm || 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 {
+ 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 (os_memcmp(wpa_auth->addr, ctx->addr, ETH_ALEN) != 0)
+ return 0;
+ ctx->wpa_auth = wpa_auth;
+ return 1;
+}
+
+static int wpa_get_primary_wpa_auth_cb(struct wpa_authenticator *wpa_auth, void *data)
+{
+ struct wpa_get_link_auth_ctx *ctx = data;
+
+ if (!wpa_auth->is_ml || os_memcmp(wpa_auth->mld_addr, ctx->addr, ETH_ALEN) != 0 ||
+ !wpa_auth->primary_auth)
+ return 0;
+
+ ctx->wpa_auth = wpa_auth;
+ return 1;
+}
+
+static struct wpa_authenticator* wpa_get_primary_wpa_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_wpa_auth_cb, &ctx);
+ return ctx.wpa_auth;
+
+}
static inline int wpa_auth_mic_failure_report(
struct wpa_authenticator *wpa_auth, const u8 *addr)
@@ -364,15 +439,15 @@ static void wpa_rekey_gmk(void *eloop_ct
}
}
-
-static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
+static void wpa_rekey_all_groups(struct wpa_authenticator *wpa_auth)
{
- struct wpa_authenticator *wpa_auth = eloop_ctx;
struct wpa_group *group, *next;
wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
group = wpa_auth->group;
while (group) {
+ wpa_printf(MSG_DEBUG, "GTK rekey start for authenticator("MACSTR"), group vlan %d",
+ MAC2STR(wpa_auth->addr), group->vlan_id);
wpa_group_get(wpa_auth, group);
group->GTKReKey = true;
@@ -385,6 +460,71 @@ static void wpa_rekey_gtk(void *eloop_ct
wpa_group_put(wpa_auth, group);
group = next;
}
+}
+
+static void wpa_group_update_gtk(struct wpa_authenticator *wpa_auth,struct wpa_group *group);
+static void wpa_update_all_gtks(struct wpa_authenticator *wpa_auth)
+{
+ struct wpa_group *group, *next;
+ group = wpa_auth->group;
+ while (group) {
+ wpa_group_get(wpa_auth, group);
+
+ wpa_group_update_gtk(wpa_auth, group);
+ next = group->next;
+ wpa_group_put(wpa_auth, group);
+ group = next;
+ }
+}
+
+static int wpa_update_all_gtks_cb(struct wpa_authenticator *wpa_auth, void *ctx)
+{
+ u8 *mld_addr = ctx;
+
+ if (os_memcmp(wpa_auth->mld_addr, mld_addr, ETH_ALEN) != 0)
+ return 0;
+
+ wpa_update_all_gtks(wpa_auth);
+ return 0;
+}
+
+static int wpa_rekey_all_groups_cb(struct wpa_authenticator *wpa_auth,
+ void *ctx)
+{
+ u8 *mld_addr = ctx;
+
+ if (os_memcmp(wpa_auth->mld_addr, mld_addr, ETH_ALEN) != 0)
+ return 0;
+
+ wpa_rekey_all_groups(wpa_auth);
+ return 0;
+}
+
+static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_authenticator *wpa_auth = eloop_ctx;
+
+ if (wpa_auth->is_ml) {
+ /* Non Primary ML authenticator eloop timer for group rekey is never started and
+ * shouldn't fire too check and warn just in case
+ */
+ if (!wpa_auth->primary_auth) {
+ wpa_printf(MSG_DEBUG, "WPA: Cannot Start GTK rekey on non Primary ML authenticator");
+ return;
+ }
+ /*
+ * Generate all the new I/BIG/GTKs
+ */
+ wpa_auth_for_each_auth(wpa_auth, wpa_update_all_gtks_cb, wpa_auth->mld_addr);
+
+ /*
+ * Send all the generated I/BIG/GTKs to the respective
+ * stations via G1 messages
+ */
+ wpa_auth_for_each_auth(wpa_auth, wpa_rekey_all_groups_cb, wpa_auth->mld_addr);
+ } else {
+ wpa_rekey_all_groups(wpa_auth);
+ }
if (wpa_auth->conf.wpa_group_rekey) {
eloop_register_timeout(wpa_auth->conf.wpa_group_rekey,
@@ -392,7 +532,6 @@ static void wpa_rekey_gtk(void *eloop_ct
}
}
-
static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_authenticator *wpa_auth = eloop_ctx;
@@ -535,6 +674,12 @@ struct wpa_authenticator * wpa_init(cons
if (!wpa_auth)
return NULL;
os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
+ 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);
+ }
os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
wpa_auth->cb = cb;
wpa_auth->cb_ctx = cb_ctx;
@@ -579,7 +724,10 @@ struct wpa_authenticator * wpa_init(cons
wpa_rekey_gmk, wpa_auth, NULL);
}
- if (wpa_auth->conf.wpa_group_rekey) {
+ /* For ML AP, run Group rekey timer only on one link(first) and whenver
+ * it fires do rekey on all associated ML links at one shot.
+ */
+ if ((!wpa_auth->is_ml || !conf->first_link_auth) && wpa_auth->conf.wpa_group_rekey) {
eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, 0,
wpa_rekey_gtk, wpa_auth, NULL);
}
@@ -623,6 +771,9 @@ void wpa_deinit(struct wpa_authenticator
struct wpa_group *group, *prev;
eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL);
+ /* ToDo: assign ML Primary authenticator to next link auth and
+ * start rekey timer.
+ */
eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
pmksa_cache_auth_deinit(wpa_auth->pmksa);
@@ -773,6 +924,8 @@ void wpa_auth_sta_no_wpa(struct wpa_stat
static void wpa_free_sta_sm(struct wpa_state_machine *sm)
{
+ int link_id;
+
#ifdef CONFIG_P2P
if (WPA_GET_BE32(sm->ip_addr)) {
wpa_printf(MSG_DEBUG,
@@ -786,7 +939,7 @@ static void wpa_free_sta_sm(struct wpa_s
}
#endif /* CONFIG_P2P */
if (sm->GUpdateStationKeys) {
- sm->group->GKeyDoneStations--;
+ wpa_update_gkeydone(sm, -1);
sm->GUpdateStationKeys = false;
}
#ifdef CONFIG_IEEE80211R_AP
@@ -796,6 +949,10 @@ static void wpa_free_sta_sm(struct wpa_s
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
os_free(sm->rsnxe);
+ 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;
+ }
wpa_group_put(sm->wpa_auth, sm->group);
#ifdef CONFIG_DPP2
wpabuf_clear_free(sm->dpp_z);
@@ -803,10 +960,10 @@ static void wpa_free_sta_sm(struct wpa_s
bin_clear_free(sm, sizeof(*sm));
}
-
void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
{
struct wpa_authenticator *wpa_auth;
+ struct wpa_authenticator *primary_wpa_auth;
if (!sm)
return;
@@ -815,10 +972,15 @@ void wpa_auth_sta_deinit(struct wpa_stat
if (wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"strict rekeying - force GTK rekey since STA is leaving");
+ if (wpa_auth->is_ml && !wpa_auth->primary_auth)
+ primary_wpa_auth = wpa_get_primary_wpa_auth(wpa_auth);
+ else
+ primary_wpa_auth = wpa_auth;
+
if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk,
- wpa_auth, NULL) == -1)
+ primary_wpa_auth, NULL) == -1)
eloop_register_timeout(0, 500000, wpa_rekey_gtk,
- wpa_auth, NULL);
+ primary_wpa_auth, NULL);
}
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
@@ -1465,12 +1627,12 @@ continue_processing:
wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
LOGGER_INFO,
"received EAPOL-Key Request for GTK rekeying");
- eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
+ eloop_cancel_timeout(wpa_rekey_gtk, wpa_get_primary_wpa_auth(wpa_auth), NULL);
if (wpa_auth_gtk_rekey_in_process(wpa_auth))
wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG,
"skip new GTK rekey - already in process");
else
- wpa_rekey_gtk(wpa_auth, NULL);
+ wpa_rekey_gtk(wpa_get_primary_wpa_auth(wpa_auth), NULL);
}
} else {
/* Do not allow the same key replay counter to be reused. */
@@ -1986,7 +2148,7 @@ int wpa_auth_sm_event(struct wpa_state_m
* Reauthentication cancels the pending group key
* update for this STA.
*/
- sm->group->GKeyDoneStations--;
+ wpa_update_gkeydone(sm, -1);
sm->GUpdateStationKeys = false;
sm->PtkGroupInit = true;
}
@@ -2063,7 +2225,7 @@ SM_STATE(WPA_PTK, INITIALIZE)
sm->keycount = 0;
if (sm->GUpdateStationKeys)
- sm->group->GKeyDoneStations--;
+ wpa_update_gkeydone(sm, -1);
sm->GUpdateStationKeys = false;
if (sm->wpa == WPA_VERSION_WPA)
sm->PInitAKeys = false;
@@ -3782,35 +3944,48 @@ static void wpa_auth_get_ml_key_info(str
}
+#define KDE_HDR_LEN (1 + 1 + RSN_SELECTOR_LEN)
static size_t wpa_auth_ml_group_kdes_len(struct wpa_state_machine *sm)
{
- struct wpa_group *gsm = sm->group;
- size_t gtk_len = gsm->GTK_len;
- size_t igtk_len;
- size_t kde_len;
- unsigned int n_links;
+ size_t kde_len = 0;
+ int link_id;
if (sm->mld_assoc_link_id < 0)
return 0;
- n_links = sm->n_mld_affiliated_links + 1;
-
- /* MLO GTK KDE for each link */
- kde_len = n_links * (2 + RSN_SELECTOR_LEN + 1 + 6 + gtk_len);
+ for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
+ struct wpa_authenticator *wpa_auth;
- if (!sm->mgmt_frame_prot)
- return kde_len;
+ if (!sm->mld_links[link_id].valid)
+ continue;
- /* MLO IGTK KDE for each link */
- igtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
- kde_len += n_links * (2 + RSN_SELECTOR_LEN + 2 + 6 + 1 + igtk_len);
+ wpa_auth = sm->mld_links[link_id].wpa_auth;
+ if (!wpa_auth || !wpa_auth->group)
+ continue;
+ /* MLO GTK KDE
+ * Header + Key-idx and Link-id + PN
+ */
+ kde_len += (KDE_HDR_LEN + 1 + WPA_MLO_GTK_KDE_PN_LEN);
+ kde_len += wpa_auth->group->GTK_len;
- if (!sm->wpa_auth->conf.beacon_prot)
- return kde_len;
+ if (sm->mgmt_frame_prot) {
+ /* MLO IGTK KDE
+ * Header + Key-idx & IPN + Link-id
+ */
+ kde_len += (KDE_HDR_LEN + WPA_IGTK_KDE_PREFIX_LEN + 1);
+ kde_len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
- /* MLO BIGTK KDE for each link */
- kde_len += n_links * (2 + RSN_SELECTOR_LEN + 2 + 6 + 1 + igtk_len);
+ if (wpa_auth->conf.beacon_prot) {
+ /* MLO BIGTK KDE
+ * Header + Key-idx & IPN + Link-id
+ */
+ kde_len += (KDE_HDR_LEN + WPA_BIGTK_KDE_PREFIX_LEN + 1);
+ kde_len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+ }
+ }
+ }
+ wpa_printf(MSG_DEBUG, "MLO Group kdes len = %zu", kde_len);
return kde_len;
}
@@ -3819,6 +3994,7 @@ static u8 * wpa_auth_ml_group_kdes(struc
{
struct wpa_auth_ml_key_info ml_key_info;
unsigned int i, link_id;
+ u8 *start = pos;
/* First fetch the key information from all the authenticators */
os_memset(&ml_key_info, 0, sizeof(ml_key_info));
@@ -3869,8 +4045,10 @@ static u8 * wpa_auth_ml_group_kdes(struc
i++;
}
- if (!sm->mgmt_frame_prot)
+ if (!sm->mgmt_frame_prot) {
+ wpa_printf(MSG_DEBUG, "RSN: MLO Group kde len = %ld",pos-start);
return pos;
+ }
/* Add MLO IGTK KDEs */
for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
@@ -3908,8 +4086,10 @@ static u8 * wpa_auth_ml_group_kdes(struc
i++;
}
- if (!sm->wpa_auth->conf.beacon_prot)
+ if (!sm->wpa_auth->conf.beacon_prot) {
+ wpa_printf(MSG_DEBUG, "RSN: MLO Group kde len = %ld",pos-start);
return pos;
+ }
/* Add MLO BIGTK KDEs */
for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
@@ -3947,6 +4127,7 @@ static u8 * wpa_auth_ml_group_kdes(struc
i++;
}
+ wpa_printf(MSG_DEBUG, "RSN: MLO Group kde len = %ld",pos-start);
return pos;
}
@@ -3987,6 +4168,7 @@ static u8 * wpa_auth_ml_kdes(struct wpa_
{
#ifdef CONFIG_IEEE80211BE
u8 link_id;
+ u8 *start = pos;
if (sm->mld_assoc_link_id < 0)
return pos;
@@ -4037,6 +4219,7 @@ static u8 * wpa_auth_ml_kdes(struct wpa_
}
}
+ wpa_printf(MSG_DEBUG, "RSN: MLO Link kde len = %ld",pos-start);
pos = wpa_auth_ml_group_kdes(sm, pos);
#endif /* CONFIG_IEEE80211BE */
@@ -4802,7 +4985,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED
#endif /* CONFIG_OCV */
if (sm->GUpdateStationKeys)
- sm->group->GKeyDoneStations--;
+ wpa_update_gkeydone(sm, -1);
sm->GUpdateStationKeys = false;
sm->GTimeoutCtr = 0;
/* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */
@@ -4817,7 +5000,7 @@ SM_STATE(WPA_PTK_GROUP, KEYERROR)
{
SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group);
if (sm->GUpdateStationKeys)
- sm->group->GKeyDoneStations--;
+ wpa_update_gkeydone(sm, -1);
sm->GUpdateStationKeys = false;
sm->Disconnect = true;
sm->disconnect_reason = WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT;
@@ -4905,7 +5088,6 @@ static int wpa_gtk_update(struct wpa_aut
return ret;
}
-
static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
@@ -4930,11 +5112,35 @@ static void wpa_group_gtk_init(struct wp
static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
{
- if (ctx != NULL && ctx != sm->group)
+ int link_id;
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ struct wpa_group *group = sm->group;
+
+ for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
+ struct mld_link *sm_link = &sm->mld_links[link_id];
+
+ if (!sm_link->valid)
+ continue;
+ if (sm_link->wpa_auth && sm_link->wpa_auth->group == ctx) {
+ group = sm_link->wpa_auth->group;
+ wpa_auth = sm_link->wpa_auth;
+ break;
+ }
+ }
+
+ if (ctx != NULL && ctx != group)
+ return 0;
+
+ /* For ML STA, run rekey on primary link STA and send G1 with keys for all links
+ * This is based on assumption that for ML Authenticator (BSS) all link
+ * Authenticators will update keys in one shot and not independently or
+ * concurrently.
+ */
+ if (sm->mld_assoc_link_id >= 0 && sm->mld_assoc_link_id != wpa_auth->link_id)
return 0;
if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
- wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
LOGGER_DEBUG,
"Not in PTKINITDONE; skip Group Key update");
sm->GUpdateStationKeys = false;
@@ -4946,7 +5152,7 @@ static int wpa_group_update_sta(struct w
* Since we clear the GKeyDoneStations before the loop, the
* station needs to be counted here anyway.
*/
- wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
LOGGER_DEBUG,
"GUpdateStationKeys was already set when marking station for GTK rekeying");
}
@@ -4955,7 +5161,7 @@ static int wpa_group_update_sta(struct w
if (sm->is_wnmsleep)
return 0;
- sm->group->GKeyDoneStations++;
+ wpa_update_gkeydone(sm, 1);
sm->GUpdateStationKeys = true;
wpa_sm_step(sm);
@@ -5099,18 +5305,11 @@ int wpa_wnmsleep_bigtk_subelem(struct wp
#endif /* CONFIG_WNM_AP */
-
-static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
- struct wpa_group *group)
+static void wpa_group_update_gtk(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group)
{
int tmp;
- wpa_printf(MSG_DEBUG,
- "WPA: group state machine entering state SETKEYS (VLAN-ID %d)",
- group->vlan_id);
- group->changed = true;
- group->wpa_group_state = WPA_GROUP_SETKEYS;
- group->GTKReKey = false;
tmp = group->GM;
group->GM = group->GN;
group->GN = tmp;
@@ -5124,8 +5323,21 @@ static void wpa_group_setkeys(struct wpa
* counting the STAs that are marked with GUpdateStationKeys instead of
* including all STAs that could be in not-yet-completed state. */
wpa_gtk_update(wpa_auth, group);
+}
- if (group->GKeyDoneStations) {
+static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group)
+{
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state SETKEYS (VLAN-ID %d)",
+ group->vlan_id);
+ group->changed = true;
+ group->wpa_group_state = WPA_GROUP_SETKEYS;
+ group->GTKReKey = false;
+ if (!wpa_auth->is_ml)
+ wpa_group_update_gtk(wpa_auth, group);
+
+ if (!wpa_auth->is_ml && group->GKeyDoneStations) {
wpa_printf(MSG_DEBUG,
"wpa_group_setkeys: Unexpected GKeyDoneStations=%d when starting new GTK rekey",
group->GKeyDoneStations);
@@ -5239,6 +5451,44 @@ static void wpa_group_sm_step(struct wpa
}
}
+static void wpa_mark_group_change(struct wpa_state_machine *sm, bool change)
+{
+ int link_id;
+
+ if (!sm || !sm->wpa_auth)
+ return;
+ sm->wpa_auth->group->changed = change;
+
+ for_each_sm_auth(sm, link_id)
+ sm->mld_links[link_id].wpa_auth->group->changed = change;
+}
+
+static void wpa_group_sm_step_links(struct wpa_state_machine *sm)
+{
+ int link_id;
+
+ if (!sm || !sm->wpa_auth)
+ return;
+ wpa_group_sm_step(sm->wpa_auth, sm->wpa_auth->group);
+
+ for_each_sm_auth(sm, link_id)
+ wpa_group_sm_step(sm->mld_links[link_id].wpa_auth,
+ sm->mld_links[link_id].wpa_auth->group);
+}
+static bool wpa_group_sm_changed(struct wpa_state_machine *sm)
+{
+ int link_id;
+ bool changed;
+
+ if (!sm || !sm->wpa_auth)
+ return false;
+ changed = sm->wpa_auth->group->changed;
+
+ for_each_sm_auth(sm, link_id)
+ changed |= sm->mld_links[link_id].wpa_auth->group->changed;
+
+ return changed;
+}
static int wpa_sm_step(struct wpa_state_machine *sm)
{
@@ -5259,7 +5509,7 @@ static int wpa_sm_step(struct wpa_state_
break;
sm->changed = false;
- sm->wpa_auth->group->changed = false;
+ wpa_mark_group_change(sm, false);
SM_STEP_RUN(WPA_PTK);
if (sm->pending_deinit)
@@ -5267,8 +5517,8 @@ static int wpa_sm_step(struct wpa_state_
SM_STEP_RUN(WPA_PTK_GROUP);
if (sm->pending_deinit)
break;
- wpa_group_sm_step(sm->wpa_auth, sm->group);
- } while (sm->changed || sm->wpa_auth->group->changed);
+ wpa_group_sm_step_links(sm);
+ } while (sm->changed || wpa_group_sm_changed(sm));
sm->in_step_loop = 0;
if (sm->pending_deinit) {
@@ -6497,8 +6747,8 @@ int wpa_auth_rekey_gtk(struct wpa_authen
{
if (!wpa_auth)
return -1;
- eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
- return eloop_register_timeout(0, 0, wpa_rekey_gtk, wpa_auth, NULL);
+ eloop_cancel_timeout(wpa_get_primary_wpa_auth(wpa_auth), wpa_auth, NULL);
+ return eloop_register_timeout(0, 0, wpa_rekey_gtk, wpa_get_primary_wpa_auth(wpa_auth), NULL);
}
@@ -6596,6 +6846,7 @@ void wpa_auth_set_ml_info(struct wpa_sta
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)
@@ -6610,10 +6861,25 @@ void wpa_auth_set_ml_info(struct wpa_sta
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;
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -277,6 +277,9 @@ struct wpa_auth_config {
bool force_kdk_derivation;
bool radius_psk;
+ u8 *mld_addr;
+ int link_id;
+ struct wpa_authenticator *first_link_auth;
};
typedef enum {
@@ -419,7 +422,8 @@ wpa_validate_wpa_ie(struct wpa_authentic
const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *rsnxe, size_t rsnxe_len,
const u8 *mdie, size_t mdie_len,
- const u8 *owe_dh, size_t owe_dh_len);
+ const u8 *owe_dh, size_t owe_dh_len,
+ struct wpa_state_machine *assoc_sm);
int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *osen_ie, size_t osen_ie_len);
@@ -433,6 +437,8 @@ int wpa_auth_sta_associated(struct wpa_a
struct wpa_state_machine *sm);
void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm);
void wpa_auth_sta_deinit(struct wpa_state_machine *sm);
+void wpa_release_link_auth_ref(struct wpa_state_machine *sm,
+ int release_link_id);
void wpa_receive(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
u8 *data, size_t data_len);
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -1657,9 +1657,12 @@ int hostapd_setup_wpa(struct hostapd_dat
};
const u8 *wpa_ie;
size_t wpa_ie_len;
+ struct hostapd_data *lhapd = NULL;
hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf);
_conf.msg_ctx = hapd->msg_ctx;
+ _conf.mld_addr = hapd->conf->mld_ap ? hapd->mld->mld_addr : NULL;
+ _conf.link_id = hapd->conf->mld_ap ? hapd->mld_link_id : -1;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
_conf.tx_status = 1;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
@@ -1697,6 +1700,16 @@ int hostapd_setup_wpa(struct hostapd_dat
!!(hapd->iface->drv_flags2 &
WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP);
+ _conf.first_link_auth = NULL;
+ if (hapd->conf->mld_ap) {
+ for_each_partner_bss(lhapd, hapd) {
+ if (lhapd == hapd)
+ continue;
+
+ if (lhapd->wpa_auth)
+ _conf.first_link_auth = lhapd->wpa_auth;
+ }
+ }
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
if (hapd->wpa_auth == NULL) {
wpa_printf(MSG_ERROR, "WPA initialization failed.");
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -178,6 +178,7 @@ struct wpa_state_machine {
u8 peer_mld_addr[ETH_ALEN];
s8 mld_assoc_link_id;
u8 n_mld_affiliated_links;
+ u16 valid_links;
struct mld_link {
bool valid;
@@ -188,6 +189,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 */
};
@@ -260,6 +262,10 @@ struct wpa_authenticator {
#ifdef CONFIG_P2P
struct bitfield *ip_pool;
#endif /* CONFIG_P2P */
+ bool is_ml;
+ u8 mld_addr[ETH_ALEN];
+ u8 link_id;
+ bool primary_auth;
};
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -600,7 +600,8 @@ wpa_validate_wpa_ie(struct wpa_authentic
const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *rsnxe, size_t rsnxe_len,
const u8 *mdie, size_t mdie_len,
- const u8 *owe_dh, size_t owe_dh_len)
+ const u8 *owe_dh, size_t owe_dh_len,
+ struct wpa_state_machine *assoc_sm)
{
struct wpa_auth_config *conf = &wpa_auth->conf;
struct wpa_ie_data data;
@@ -940,6 +941,14 @@ wpa_validate_wpa_ie(struct wpa_authentic
else
sm->wpa = WPA_VERSION_WPA;
+ if (assoc_sm) {
+ /* For ML Association Link STA cannot choose a different
+ * akm or pairwise cipher from assoc STA */
+ if (sm->wpa_key_mgmt != assoc_sm->wpa_key_mgmt)
+ return WPA_INVALID_AKMP;
+ if (sm->pairwise != assoc_sm->pairwise)
+ return WPA_INVALID_PAIRWISE;
+ }
#if defined(CONFIG_IEEE80211R_AP) && defined(CONFIG_FILS)
if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256 ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA384) &&
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -22,6 +22,7 @@
#define WPA_PASN_PMK_LEN 32
#define WPA_PASN_MAX_MIC_LEN 24
#define WPA_MAX_RSNXE_LEN 4
+#define WPA_MLO_GTK_KDE_PN_LEN 6
#define OWE_DH_GROUP 19
--- a/tests/fuzzing/eapol-key-auth/eapol-key-auth.c
+++ b/tests/fuzzing/eapol-key-auth/eapol-key-auth.c
@@ -262,7 +262,7 @@ static int auth_init(struct wpa *wpa)
}
if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, 2412, supp_ie,
- supp_ie_len, NULL, 0, NULL, 0, NULL, 0) !=
+ supp_ie_len, NULL, 0, NULL, 0, NULL, 0, NULL) !=
WPA_IE_OK) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
return -1;
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -484,7 +484,7 @@ static int ibss_rsn_auth_init(struct ibs
"\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x02"
- "\x00\x00", 22, NULL, 0, NULL, 0, NULL, 0) !=
+ "\x00\x00", 22, NULL, 0, NULL, 0, NULL, 0, NULL) !=
WPA_IE_OK) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
return -1;