mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-21 11:22:50 +00:00
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
Signed-off-by: John Crispin <john@phrozen.org>
1184 lines
36 KiB
Diff
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;
|