[PATCH 17/29] EPPKE: EPP capabilities negotiation indication

Sai Pratyusha Magam smagam at qti.qualcomm.com
Thu Dec 11 05:14:31 PST 2025


Indicate the negotiated EPP capabilities in
(Re)Association Request frame via netlink
attribute @NL80211_ATTR_EPP_FLAGS in
@NL80211_CMD_SET_STATION

The Extended RSN capabilities for EPP that an EPP AP and
an EPP non-AP STA can negotiate are as per
IEEE P802.11bi/D2.0, 9.4.2.240 (RSNXE), few of which are
driver dependent, hence need them to be communicated from
userspace for later use.

Signed-off-by: Sai Pratyusha Magam <smagam at qti.qualcomm.com>
Signed-off-by: Rohan Dutta <drohan at qti.qualcomm.com>
---
 src/ap/ap_drv_ops.c          |  3 ++-
 src/ap/ap_drv_ops.h          |  2 +-
 src/ap/ieee802_11.c          |  4 +++-
 src/ap/sta_info.c            |  2 +-
 src/ap/wpa_auth.c            | 32 ++++++++++++++++++++++++++++++++
 src/ap/wpa_auth.h            |  4 +++-
 src/ap/wpa_auth_i.h          |  3 +++
 src/ap/wpa_auth_ie.c         |  3 +++
 src/drivers/driver.h         |  8 ++++++++
 src/drivers/driver_nl80211.c | 19 +++++++++++++++++++
 10 files changed, 75 insertions(+), 5 deletions(-)

diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index bb353ac35..60716ee30 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -480,7 +480,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
 		    const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
 		    u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
 		    int set, const u8 *link_addr, bool mld_link_sta,
-		    u16 eml_cap, bool epp_sta)
+		    u16 eml_cap, bool epp_sta, u32 epp_flags)
 {
 	struct hostapd_sta_add_params params;
 
@@ -512,6 +512,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
 	params.mld_link_id = -1;
 #ifdef CONFIG_ENC_ASSOC
 	params.epp_sta = epp_sta;
+	params.epp_flags = epp_flags;
 #endif
 #ifdef CONFIG_IEEE80211BE
 	/*
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 671b99042..4e8745a97 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -50,7 +50,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
 		    const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
 		    u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
 		    int set, const u8 *link_addr, bool mld_link_sta,
-		    u16 eml_cap, bool epp_sta);
+		    u16 eml_cap, bool epp_sta, u32 epp_flags);
 int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
 int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
 			     size_t elem_len);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 8140f09fb..bddaaa95a 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -5352,9 +5352,11 @@ static int add_associated_sta(struct hostapd_data *hapd,
 	const u8 *mld_link_addr = NULL;
 	bool mld_link_sta = false, epp_sta = false;
 	u16 eml_cap = 0;
+	u32 epp_flags = 0;
 
 #ifdef CONFIG_ENC_ASSOC
 	epp_sta = sta->epp_sta;
+	epp_flags = wpa_auth_get_epp_flags(sta->wpa_sm);
 #endif
 
 #ifdef CONFIG_IEEE80211BE
@@ -5448,7 +5450,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
 			    sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
 			    sta->vht_opmode, sta->p2p_ie ? 1 : 0,
 			    set, mld_link_addr, mld_link_sta, eml_cap,
-			    epp_sta)) {
+			    epp_sta, epp_flags)) {
 		hostapd_logger(hapd, sta->addr,
 			       HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
 			       "Could not %s STA to kernel driver",
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 657f04911..c981664b4 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -2026,7 +2026,7 @@ int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
 			    0, NULL, NULL, NULL, 0, NULL, 0, NULL,
 			    sta->flags, 0, 0, 0, 0,
 			    mld_link_addr, mld_link_sta, eml_cap,
-			    epp_sta)) {
+			    epp_sta, 0)) {
 		hostapd_logger(hapd, sta->addr,
 			       HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_NOTICE,
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 040efd4a4..28824438b 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -107,6 +107,16 @@ static const u8 * wpa_auth_get_spa(const struct wpa_state_machine *sm)
 }
 
 
+#ifdef CONFIG_ENC_ASSOC
+const u32  wpa_auth_get_epp_flags(struct wpa_state_machine *sm)
+{
+	if (!sm)
+		return 0;
+	return sm->epp_flags;
+}
+#endif /* CONFIG_ENC_ASSOC */
+
+
 static void wpa_gkeydone_sta(struct wpa_state_machine *sm)
 {
 #ifdef CONFIG_IEEE80211BE
@@ -7351,6 +7361,28 @@ void wpa_auth_set_rsn_selection(struct wpa_state_machine *sm, const u8 *ie,
 }
 
 
+#ifdef CONFIG_ENC_ASSOC
+void wpa_auth_ap_sta_epp_flags(struct wpa_state_machine *sm, const u8 *rsnxe)
+{
+	struct wpa_auth_config *conf;
+
+	if (!sm || !rsnxe)
+		return;
+
+	conf = &sm->wpa_auth->conf;
+
+	if (conf->assoc_frame_encryption &&
+	    ieee802_11_rsnx_capab(sm->rsnxe,
+				  WLAN_RSNX_CAPAB_ASSOC_FRAME_ENCRYPTION))
+		sm->epp_flags |= WPA_EPP_ASSOC_FRAME_ENCRYPTION;
+	if (conf->eap_using_authentication_frames &&
+	    ieee802_11_rsnx_capab(sm->rsnxe,
+				  WLAN_RSNX_CAPAB_1X_UTILIZING_AUTHENTICATION_FRAMES))
+		sm->epp_flags |= WPA_EPP_1X_UTILIZING_AUTHENTICATION_FRAMES;
+}
+#endif /* CONFIG_ENC_ASSOC */
+
+
 #ifdef CONFIG_DPP2
 void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
 {
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 4883e2db9..9d4c9a132 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -507,6 +507,8 @@ int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
 int wpa_auth_sta_fils_tk_already_set(struct wpa_state_machine *sm);
 int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
 			     struct rsn_pmksa_cache_entry *entry);
+u32 wpa_auth_get_epp_flags(struct wpa_state_machine *sm);
+
 struct rsn_pmksa_cache_entry *
 wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm);
 void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm);
@@ -558,7 +560,7 @@ void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
 int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
 void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
 				  struct wpa_state_machine *sm, int ack);
-
+void wpa_auth_ap_sta_epp_flags(struct wpa_state_machine *sm, const u8 *rsnxe);
 #ifdef CONFIG_IEEE80211R_AP
 u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 				 size_t max_len, int auth_alg,
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index e97db8c7f..f7836cc1a 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -192,6 +192,9 @@ struct wpa_state_machine {
 #endif /* CONFIG_IEEE80211BE */
 
 	bool ssid_protection;
+#ifdef CONFIG_ENC_ASSOC
+	u32 epp_flags; /* See %enum epp_flags */
+#endif /* CONFIG_ENC_ASSOC */
 
 	struct wpabuf *sae_pw_id;
 	unsigned int sae_pw_id_counter;
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 6ae1350a0..f5bbedc04 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -1388,6 +1388,9 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 		}
 		os_memcpy(sm->rsnxe, rsnxe, rsnxe_len);
 		sm->rsnxe_len = rsnxe_len;
+#ifdef CONFIG_ENC_ASSOC
+		wpa_auth_ap_sta_epp_flags(sm, rsnxe);
+#endif
 	} else {
 		os_free(sm->rsnxe);
 		sm->rsnxe = NULL;
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index e727dabf9..53fb9c81f 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2670,6 +2670,7 @@ struct hostapd_sta_add_params {
 	u32 flags_mask; /* unset bits in flags */
 #ifdef CONFIG_ENC_ASSOC
 	bool epp_sta;
+	u32 epp_flags; /* See %enum epp_flags */
 #endif
 #ifdef CONFIG_MESH
 	enum mesh_plink_state plink_state;
@@ -2738,6 +2739,13 @@ struct wpa_bss_params {
 #define WPA_STA_ASSOCIATED BIT(6)
 #define WPA_STA_SPP_AMSDU BIT(7)
 
+#ifdef CONFIG_ENC_ASSOC
+enum epp_flags {
+	WPA_EPP_ASSOC_FRAME_ENCRYPTION = BIT(0),
+	WPA_EPP_1X_UTILIZING_AUTHENTICATION_FRAMES = BIT(1)
+};
+#endif
+
 enum tdls_oper {
 	TDLS_DISCOVERY_REQ,
 	TDLS_SETUP,
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 4a38a5111..d071caa93 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5891,6 +5891,19 @@ static u32 sta_flags_nl80211(int flags)
 	return f;
 }
 
+#ifdef CONFIG_ENC_ASSOC
+static u32 epp_flags_nl80211(u32 epp_flags)
+{
+	u32 f = 0;
+
+	if (epp_flags & WPA_EPP_ASSOC_FRAME_ENCRYPTION)
+		f |= BIT(NL80211_EPP_FLAG_ASSOC_FRAME_ENCRYPTION);
+	if (epp_flags & WPA_EPP_1X_UTILIZING_AUTHENTICATION_FRAMES)
+		f |= BIT(NL80211_EPP_FLAG_1X_UTILIZING_AUTHENTICATION_FRAMES);
+
+	return f;
+}
+#endif
 
 #ifdef CONFIG_MESH
 static u32 sta_plink_state_nl80211(enum mesh_plink_state state)
@@ -6106,6 +6119,12 @@ static int wpa_driver_nl80211_sta_add(void *priv,
 			goto fail;
 	}
 
+#ifdef CONFIG_ENC_ASSOC
+	if (nla_put_u32(msg, NL80211_ATTR_EPP_FLAGS,
+			epp_flags_nl80211(params->epp_flags)))
+		goto fail;
+#endif
+
 	os_memset(&upd, 0, sizeof(upd));
 	upd.set = sta_flags_nl80211(params->flags);
 	upd.mask = upd.set | sta_flags_nl80211(params->flags_mask);
-- 
2.34.1




More information about the Hostap mailing list