[PATCH wireless-next 1/2] wifi: cfg80211: indicate (Re)Association frame encryption to userspace

Kavita Kavita
2026-04-27T15:09:22Z

In SME-in-driver mode, the driver handles the entire (re)association
exchange. Userspace (e.g., wpa_supplicant) currently has no explicit
indication of whether the (re)association exchange was encrypted,
making it difficult to distinguish EPP (Enhanced Privacy Protection,
IEEE 802.11bi) associations from non-EPP associations.

When (Re)Association frame encryption is used, the (Re)Association
Response frame must contain a Key Delivery element as specified in
IEEE P802.11bi/D4.0, Table 9-65. Userspace must process this element
only when the (Re)Association Response frame is actually encrypted.
Processing it unconditionally for unencrypted frames leads to incorrect
behavior. Without an explicit indication from the driver, userspace
cannot determine whether encryption was used and whether the Key
Delivery element is valid.

Add a new flag attribute NL80211_ATTR_ASSOC_ENCRYPTED and a
corresponding field "assoc_encrypted" in cfg80211_connect_resp_params.
The driver sets this flag to indicate that the (Re)Association
Request/Response frames are transmitted encrypted over the air.
Pass the flag to userspace via NL80211_CMD_CONNECT event.

Mark NL80211_ATTR_ASSOC_ENCRYPTED with NLA_REJECT in the nl80211
policy to reject any attempt by userspace to send this attribute.

Signed-off-by: Kavita Kavita <kavita.kavita@oss.qualcomm.com>
---
include/net/cfg80211.h | 4 ++++
include/uapi/linux/nl80211.h | 9 +++++++++
net/wireless/nl80211.c | 5 ++++-
net/wireless/sme.c | 1 +
4 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9d3639ff9c28..b29fcb4e1a4b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -8835,6 +8835,9 @@ struct cfg80211_fils_resp_params {
* @links.status: per-link status code, to report a status code that's not
* %WLAN_STATUS_SUCCESS for a given link, it must also be in the
* @valid_links bitmap and may have a BSS pointer (which is then released)
+ * @assoc_encrypted: The driver should set this flag to indicate that the
+ * (Re)Association Request/Response frames are transmitted encrypted over
+ * the air.
*/
struct cfg80211_connect_resp_params {
int status;
@@ -8844,6 +8847,7 @@ struct cfg80211_connect_resp_params {
size_t resp_ie_len;
struct cfg80211_fils_resp_params fils;
enum nl80211_timeout_reason timeout_reason;
+ bool assoc_encrypted;

const u8 *ap_mld_addr;
u16 valid_links;
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 3d55bf4be36f..66af29dddb4c 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3140,6 +3140,13 @@ enum nl80211_commands {
* association response etc., since it's abridged in the beacon. Used
* for START_AP etc.
*
+ * @NL80211_ATTR_ASSOC_ENCRYPTED: Flag attribute, used only with the
+ * %NL80211_CMD_CONNECT event in SME-in-driver mode. The driver should
+ * set this flag to indicate that both the (Re)Association Request frame
+ * and the corresponding (Re)Association Response frame are transmitted
+ * encrypted over the air. Enhanced Privacy Protection (EPP), as defined
+ * in IEEE P802.11bi/D4.0, mandates this encryption.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3733,6 +3740,8 @@ enum nl80211_attrs {
NL80211_ATTR_NAN_MAX_CHAN_SWITCH_TIME,
NL80211_ATTR_NAN_PEER_MAPS,

+ NL80211_ATTR_ASSOC_ENCRYPTED,
+
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f334cdef8958..30c737376389 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1076,6 +1076,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_NAN_MAX_CHAN_SWITCH_TIME] = { .type = NLA_U16 },
[NL80211_ATTR_NAN_PEER_MAPS] =
NLA_POLICY_NESTED_ARRAY(nl80211_nan_peer_map_policy),
+ [NL80211_ATTR_ASSOC_ENCRYPTED] = { .type = NLA_REJECT },
};

/* policy for the key attributes */
@@ -20588,7 +20589,9 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
(cr->fils.pmk &&
nla_put(msg, NL80211_ATTR_PMK, cr->fils.pmk_len, cr->fils.pmk)) ||
(cr->fils.pmkid &&
- nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->fils.pmkid)))))
+ nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->fils.pmkid)))) ||
+ (cr->assoc_encrypted &&
+ nla_put_flag(msg, NL80211_ATTR_ASSOC_ENCRYPTED)))
goto nla_put_failure;

if (cr->valid_links) {
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 86e2ccaa678c..b451df3096dd 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -1066,6 +1066,7 @@ void cfg80211_connect_done(struct net_device *dev,
}
ev->cr.status = params->status;
ev->cr.timeout_reason = params->timeout_reason;
+ ev->cr.assoc_encrypted = params->assoc_encrypted;

spin_lock_irqsave(&wdev->event_lock, flags);
list_add_tail(&ev->list, &wdev->event_list);
--
2.34.1