Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH wireless-next 3/3] wifi: mac80211_hwsim: Advertise support for IEEE 802.1X authentication protocol
From: Kavita Kavita @ 2026-02-26 13:50 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <3ecb3d440ed3ab4fe4cd3765e0c8457ef58fd6b6.camel@sipsolutions.net>



On 2/26/2026 2:06 PM, Johannes Berg wrote:
> On Thu, 2026-02-26 at 12:24 +0530, Kavita Kavita wrote:
>> Advertise support for the IEEE 802.1X authentication protocol in
>> mac80211_hwsim to enable testing scenarios.
> 
> Do we even need this in drivers vs. mac80211 just setting it?
> 
> All the code for it is in mac80211, so it shouldn't matter?
> 
> I'd actually argue NL80211_EXT_FEATURE_EPPKE is the same, mac80211
> should set it instead of the driver (I didn't merge [1] yet anyway) and
> only NL80211_EXT_FEATURE_ASSOC_FRAME_ENCRYPTION should be in the driver?


For (Re)Association frame encryption, additional changes are required in the
driver and firmware. Because of this dependency, we initially thought it was
best to let the driver set the EPPKE and IEEE 802.1X Authentication feature
flags as well.
However, since no lower-layer changes are actually needed for EPPKE and
IEEE 802.1X Authentication, these can safely be advertised directly in mac80211.
The driver should only set the (Re)Association frame encryption feature flag,
and mac80211 can then conditionally enable the EPPKE and IEEE 802.1X Authentication
feature flags based on that indication. 

I will send the updated patch set with these changes. Thank you.


> 
> 
> [1] https://patchwork.kernel.org/project/linux-wireless/patch/20260114111900.2196941-10-kavita.kavita@oss.qualcomm.com/
> 
> johannes


^ permalink raw reply

* Re: [PATCH] mac80211: update outdated comment
From: Johannes Berg @ 2026-02-26 11:05 UTC (permalink / raw)
  To: Lachlan Hodges, kexinsun
  Cc: linux-wireless, linux-kernel, julia.lawall, xutong.ma, yunbolyu,
	ratnadiraw
In-Reply-To: <b6tb5zvgfnu2tbttnd6fqlnwkvj2lzgoiwl4wz7urobdeptivs@xiefjb2zch4r>

On Thu, 2026-02-26 at 21:57 +1100, Lachlan Hodges wrote:
> On Tue, Feb 24, 2026 at 10:15:48AM +0800, kexinsun wrote:
> > The function ieee80211_start_scan() was refactored and replaced by
> > __ieee80211_start_scan() in commit f3b85252f081 ("mac80211: fix scan
> > races and rework scanning"). Update the comment in
> > ieee80211_tx_h_check_assoc() accordingly.
> > 
> > Signed-off-by: kexinsun <kexinsun@smail.nju.edu.cn>
> > ---
> >  net/mac80211/tx.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
> > index 8cdbd417d7be..85c48b42474c 100644
> > --- a/net/mac80211/tx.c
> > +++ b/net/mac80211/tx.c
> > @@ -288,7 +288,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
> >  		 * sent and we should not get here, but if we do
> >  		 * nonetheless, drop them to avoid sending them
> >  		 * off-channel. See the link below and
> > -		 * ieee80211_start_scan() for more.
> > +		 * __ieee80211_start_scan() for more.
> >  		 *
> >  		 * http://article.gmane.org/gmane.linux.kernel.wireless.general/30089
> 
> Might be good to remove that link aswell and update the comment? Looks
> to be dead.

Hm, yeah, I can't say what this link was now.

I did find where it came from though:
https://lore.kernel.org/all/1237368810.5100.15.camel@johannes.local/

I suspect that maybe it was meant to point to
https://lore.kernel.org/all/20090316085741.GA29986@jm.kir.nu/

but I don't really know.

johannes

^ permalink raw reply

* Re: [PATCH] mac80211: update outdated comment
From: Lachlan Hodges @ 2026-02-26 10:57 UTC (permalink / raw)
  To: kexinsun
  Cc: johannes, linux-wireless, linux-kernel, julia.lawall, xutong.ma,
	yunbolyu, ratnadiraw
In-Reply-To: <20260224021548.1394-1-kexinsun@smail.nju.edu.cn>

On Tue, Feb 24, 2026 at 10:15:48AM +0800, kexinsun wrote:
> The function ieee80211_start_scan() was refactored and replaced by
> __ieee80211_start_scan() in commit f3b85252f081 ("mac80211: fix scan
> races and rework scanning"). Update the comment in
> ieee80211_tx_h_check_assoc() accordingly.
> 
> Signed-off-by: kexinsun <kexinsun@smail.nju.edu.cn>
> ---
>  net/mac80211/tx.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
> index 8cdbd417d7be..85c48b42474c 100644
> --- a/net/mac80211/tx.c
> +++ b/net/mac80211/tx.c
> @@ -288,7 +288,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
>  		 * sent and we should not get here, but if we do
>  		 * nonetheless, drop them to avoid sending them
>  		 * off-channel. See the link below and
> -		 * ieee80211_start_scan() for more.
> +		 * __ieee80211_start_scan() for more.
>  		 *
>  		 * http://article.gmane.org/gmane.linux.kernel.wireless.general/30089

Might be good to remove that link aswell and update the comment? Looks
to be dead.

lachlan 

^ permalink raw reply

* Re: [PATCH wireless-next 3/3] wifi: mac80211_hwsim: Advertise support for IEEE 802.1X authentication protocol
From: Johannes Berg @ 2026-02-26  8:36 UTC (permalink / raw)
  To: Kavita Kavita; +Cc: linux-wireless
In-Reply-To: <20260226065442.4182232-4-kavita.kavita@oss.qualcomm.com>

On Thu, 2026-02-26 at 12:24 +0530, Kavita Kavita wrote:
> Advertise support for the IEEE 802.1X authentication protocol in
> mac80211_hwsim to enable testing scenarios.

Do we even need this in drivers vs. mac80211 just setting it?

All the code for it is in mac80211, so it shouldn't matter?

I'd actually argue NL80211_EXT_FEATURE_EPPKE is the same, mac80211
should set it instead of the driver (I didn't merge [1] yet anyway) and
only NL80211_EXT_FEATURE_ASSOC_FRAME_ENCRYPTION should be in the driver?


[1] https://patchwork.kernel.org/project/linux-wireless/patch/20260114111900.2196941-10-kavita.kavita@oss.qualcomm.com/

johannes

^ permalink raw reply

* [PATCH wireless-next 3/3] wifi: mac80211_hwsim: Advertise support for IEEE 802.1X authentication protocol
From: Kavita Kavita @ 2026-02-26  6:54 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, kavita.kavita
In-Reply-To: <20260226065442.4182232-1-kavita.kavita@oss.qualcomm.com>

Advertise support for the IEEE 802.1X authentication protocol in
mac80211_hwsim to enable testing scenarios.

Signed-off-by: Kavita Kavita <kavita.kavita@oss.qualcomm.com>
---
 drivers/net/wireless/virtual/mac80211_hwsim.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
index 4d9f5f87e814..c86ceb5f6703 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
@@ -5640,6 +5640,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
 	wiphy_ext_feature_set(hw->wiphy,
 			      NL80211_EXT_FEATURE_BSS_COLOR);
 
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_IEEE8021X_AUTH);
+
 	hw->wiphy->interface_modes = param->iftypes;
 
 	/* ask mac80211 to reserve space for magic */
-- 
2.34.1


^ permalink raw reply related

* [PATCH wireless-next 2/3] wifi: mac80211: Add support for IEEE 802.1X authentication protocol in non-AP STA mode
From: Kavita Kavita @ 2026-02-26  6:54 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, kavita.kavita
In-Reply-To: <20260226065442.4182232-1-kavita.kavita@oss.qualcomm.com>

Add support for the IEEE 802.1X authentication protocol in non-AP STA
mode, as specified in "IEEE P802.11bi/D4.0, 12.16.5".

IEEE 802.1X authentication involves multiple Authentication frame
exchanges, with the non-AP STA and AP alternating transaction
sequence numbers. The number of Authentication frame exchanges
depends on the EAP method in use. For IEEE 802.1X authentication,
process only Authentication frames with the expected transaction
sequence number.

For IEEE 802.1X Authentication, Table 9-71 specifies that the
Encapsulation Length field as specified in Clause 9.4.1.82 shall be
present in all IEEE 802.1X Authentication frames. Drop the frame in
the mac80211 if the Encapsulation Length field is missing.

After receiving the final Authentication frame with status code
WLAN_STATUS_8021X_AUTH_SUCCESS from the AP, mac80211 marks the state
as authenticated, as it indicates the EAP handshake has completed
successfully over the Authentication frames as specified in
Clause 12.16.5.

In the PMKSA caching case, only two Authentication frames are
exchanged if the AP identifies a valid PMKSA, then as specified
in Clause 12.16.8.3, the AP shall set the Status Code to
WLAN_STATUS_SUCCESS in the final Authentication frame and must not
include an encapsulated EAPOL PDU. This frame will be the final
Authentication frame from the AP when PMKSA caching is enabled,
and mac80211 marks the state as authenticated.

In case of authentication success or failure, forward the
Authentication frame to userspace(e.g. wpa_supplicant), and let
userspace validate the Authentication frame from the AP as per the
specification.

Signed-off-by: Kavita Kavita <kavita.kavita@oss.qualcomm.com>
---
 include/linux/ieee80211.h |  1 +
 net/mac80211/mlme.c       | 78 ++++++++++++++++++++++++++++++++++++---
 2 files changed, 73 insertions(+), 6 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 1bf806f85372..3651b2e6c518 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1508,6 +1508,7 @@ enum ieee80211_statuscode {
 	WLAN_STATUS_SAE_PK = 127,
 	WLAN_STATUS_DENIED_TID_TO_LINK_MAPPING = 133,
 	WLAN_STATUS_PREF_TID_TO_LINK_MAPPING_SUGGESTED = 134,
+	WLAN_STATUS_8021X_AUTH_SUCCESS = 153,
 };
 
 
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index e83582b2c377..a073451b0c94 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -4920,7 +4920,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
 				   struct ieee80211_mgmt *mgmt, size_t len)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	u16 auth_alg, auth_transaction, status_code;
+	u16 auth_alg, auth_transaction, status_code, encap_len;
 	struct ieee80211_event event = {
 		.type = MLME_EVENT,
 		.u.mlme.data = AUTH_EVENT,
@@ -4929,6 +4929,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
 		.subtype = IEEE80211_STYPE_AUTH,
 	};
 	bool sae_need_confirm = false;
+	bool auth_fail = false;
 
 	lockdep_assert_wiphy(sdata->local->hw.wiphy);
 
@@ -4945,6 +4946,15 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
 	auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
 	status_code = le16_to_cpu(mgmt->u.auth.status_code);
 
+	/*
+	 * IEEE 802.1X Authentication:
+	 * Header + Authentication Algorithm Number(2 byte) + Authentication
+	 * Transaction Sequence Number(2 byte) + Status Code(2 byte) +
+	 * Encapsulation Length(2 byte).
+	 */
+	if (auth_alg == WLAN_AUTH_IEEE8021X && len < 24 + 8)
+		return;
+
 	info.link_id = ifmgd->auth_data->link_id;
 
 	if (auth_alg != ifmgd->auth_data->algorithm ||
@@ -4960,7 +4970,24 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
 		goto notify_driver;
 	}
 
-	if (status_code != WLAN_STATUS_SUCCESS) {
+	switch (auth_alg) {
+	case WLAN_AUTH_IEEE8021X:
+		if (status_code != WLAN_STATUS_SUCCESS &&
+		    status_code != WLAN_STATUS_8021X_AUTH_SUCCESS)
+			auth_fail = true;
+
+		if (!auth_fail) {
+			/* Indicates length of encapsulated EAPOL PDU */
+			encap_len = get_unaligned_le16(mgmt->u.auth.variable);
+		}
+		break;
+	default:
+		if (status_code != WLAN_STATUS_SUCCESS)
+			auth_fail = true;
+		break;
+	}
+
+	if (auth_fail) {
 		cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
 
 		if (auth_alg == WLAN_AUTH_SAE &&
@@ -4997,6 +5024,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
 	case WLAN_AUTH_FILS_SK_PFS:
 	case WLAN_AUTH_FILS_PK:
 	case WLAN_AUTH_EPPKE:
+	case WLAN_AUTH_IEEE8021X:
 		break;
 	case WLAN_AUTH_SHARED_KEY:
 		if (ifmgd->auth_data->expected_transaction != 4) {
@@ -5017,8 +5045,37 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
 	if (ifmgd->auth_data->algorithm != WLAN_AUTH_SAE ||
 	    (auth_transaction == 2 &&
 	     ifmgd->auth_data->expected_transaction == 2)) {
-		if (!ieee80211_mark_sta_auth(sdata))
-			return; /* ignore frame -- wait for timeout */
+		switch (ifmgd->auth_data->algorithm) {
+		case WLAN_AUTH_IEEE8021X:
+			/*
+			 * IEEE 802.1X authentication:
+			 * - When the full EAP handshake completes over the
+			 *   Authentication process, the responder sets the
+			 *   Status Code to WLAN_STATUS_8021X_AUTH_SUCCESS as
+			 *   specified in "IEEE P802.11bi/D4.0, 12.16.5".
+			 *
+			 * - In the PMKSA caching case, only two Authentication
+			 *   frames are exchanged if the responder (e.g., AP)
+			 *   identifies a valid PMKSA, then as specified in
+			 *   "IEEE P802.11bi/D4.0, 12.16.8.3", the responder
+			 *   shall set the Status Code to SUCCESS in the final
+			 *   Authentication frame and must not include an
+			 *   encapsulated EAPOL PDU.
+			 *
+			 * Both conditions are treated as successful
+			 * authentication, so mark the state to Authenticated.
+			 */
+			if (status_code != WLAN_STATUS_8021X_AUTH_SUCCESS &&
+			    !(status_code == WLAN_STATUS_SUCCESS &&
+			      encap_len == 0))
+				break;
+			fallthrough;
+		default:
+			if (!ieee80211_mark_sta_auth(sdata))
+				return; /* ignore frame -- wait for timeout */
+
+			break;
+		}
 	} else if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE &&
 		   auth_transaction == 1) {
 		sae_need_confirm = true;
@@ -8457,6 +8514,10 @@ static int ieee80211_auth(struct ieee80211_sub_if_data *sdata)
 	} else if (auth_data->algorithm == WLAN_AUTH_EPPKE) {
 		trans = auth_data->trans;
 		status = auth_data->status;
+	} else if (auth_data->algorithm == WLAN_AUTH_IEEE8021X) {
+		trans = auth_data->trans;
+		status = auth_data->status;
+		auth_data->expected_transaction = trans + 1;
 	}
 
 	if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
@@ -9114,7 +9175,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
 		}
 
 		if (ifmgd->auth_data &&
-		    ifmgd->auth_data->algorithm == WLAN_AUTH_EPPKE)
+		    (ifmgd->auth_data->algorithm == WLAN_AUTH_EPPKE ||
+		     ifmgd->auth_data->algorithm == WLAN_AUTH_IEEE8021X))
 			new_sta->sta.epp_peer = true;
 
 		new_sta->sta.mlo = mlo;
@@ -9374,6 +9436,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 	case NL80211_AUTHTYPE_EPPKE:
 		auth_alg = WLAN_AUTH_EPPKE;
 		break;
+	case NL80211_AUTHTYPE_IEEE8021X:
+		auth_alg = WLAN_AUTH_IEEE8021X;
+		break;
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -9399,7 +9464,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 
 	if (req->auth_data_len >= 4) {
 		if (req->auth_type == NL80211_AUTHTYPE_SAE ||
-		    req->auth_type == NL80211_AUTHTYPE_EPPKE) {
+		    req->auth_type == NL80211_AUTHTYPE_EPPKE ||
+		    req->auth_type == NL80211_AUTHTYPE_IEEE8021X) {
 			__le16 *pos = (__le16 *) req->auth_data;
 
 			auth_data->trans = le16_to_cpu(pos[0]);
-- 
2.34.1


^ permalink raw reply related

* [PATCH wireless-next 1/3] wifi: cfg80211: add support for IEEE 802.1X Authentication Protocol
From: Kavita Kavita @ 2026-02-26  6:54 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, kavita.kavita
In-Reply-To: <20260226065442.4182232-1-kavita.kavita@oss.qualcomm.com>

Add an extended feature flag NL80211_EXT_FEATURE_IEEE8021X_AUTH to
allow a driver to indicate support for the IEEE 802.1X authentication
protocol in non-AP STA mode, as defined in
"IEEE P802.11bi/D4.0, 12.16.5".

In case of SME in userspace, the Authentication frame body is prepared
in userspace while the driver finalizes the Authentication frame once
it receives the required fields and elements. The driver indicates
support for IEEE 802.1X authentication using the extended feature flag
so that userspace can initiate IEEE 802.1X authentication.

When the feature flag is set, process IEEE 802.1X Authentication frames
from userspace in non-AP STA mode. If the flag is not set, reject
IEEE 802.1X Authentication frames.

Define a new authentication type NL80211_AUTHTYPE_IEEE8021X for
IEEE 802.1X authentication.

Signed-off-by: Kavita Kavita <kavita.kavita@oss.qualcomm.com>
---
 include/linux/ieee80211.h    |  1 +
 include/uapi/linux/nl80211.h |  9 +++++++++
 net/wireless/nl80211.c       | 14 ++++++++++++--
 3 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 0aa2fb8f88de..1bf806f85372 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1358,6 +1358,7 @@ struct ieee80211_tdls_data {
 #define WLAN_AUTH_FILS_SK 4
 #define WLAN_AUTH_FILS_SK_PFS 5
 #define WLAN_AUTH_FILS_PK 6
+#define WLAN_AUTH_IEEE8021X 8
 #define WLAN_AUTH_EPPKE 9
 #define WLAN_AUTH_LEAP 128
 
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index b63f71850906..6802e6884800 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -5466,6 +5466,8 @@ enum nl80211_bss_status {
  * @NL80211_AUTHTYPE_FILS_SK_PFS: Fast Initial Link Setup shared key with PFS
  * @NL80211_AUTHTYPE_FILS_PK: Fast Initial Link Setup public key
  * @NL80211_AUTHTYPE_EPPKE: Enhanced Privacy Protection Key Exchange
+ * @NL80211_AUTHTYPE_IEEE8021X: IEEE 802.1X authentication utilizing
+ *	Authentication frames
  * @__NL80211_AUTHTYPE_NUM: internal
  * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
  * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
@@ -5482,6 +5484,7 @@ enum nl80211_auth_type {
 	NL80211_AUTHTYPE_FILS_SK_PFS,
 	NL80211_AUTHTYPE_FILS_PK,
 	NL80211_AUTHTYPE_EPPKE,
+	NL80211_AUTHTYPE_IEEE8021X,
 
 	/* keep last */
 	__NL80211_AUTHTYPE_NUM,
@@ -6795,6 +6798,11 @@ enum nl80211_feature_flags {
  *	frames in both non‑AP STA and AP mode as specified in
  *	"IEEE P802.11bi/D3.0, 12.16.6".
  *
+ * @NL80211_EXT_FEATURE_IEEE8021X_AUTH: Driver supports IEEE 802.1X
+ *	authentication utilizing Authentication frames with user space SME
+ *	(NL80211_CMD_AUTHENTICATE) in non-AP STA mode, as specified in
+ *	"IEEE P802.11bi/D4.0, 12.16.5".
+ *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
  */
@@ -6873,6 +6881,7 @@ enum nl80211_ext_feature_index {
 	NL80211_EXT_FEATURE_BEACON_RATE_EHT,
 	NL80211_EXT_FEATURE_EPPKE,
 	NL80211_EXT_FEATURE_ASSOC_FRAME_ENCRYPTION,
+	NL80211_EXT_FEATURE_IEEE8021X_AUTH,
 
 	/* add new features before the definition below */
 	NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 6e58b238a1f8..3258ef2e3631 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6542,6 +6542,10 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
 					     NL80211_EXT_FEATURE_EPPKE) &&
 		    auth_type == NL80211_AUTHTYPE_EPPKE)
 			return false;
+		if (!wiphy_ext_feature_isset(&rdev->wiphy,
+					     NL80211_EXT_FEATURE_IEEE8021X_AUTH) &&
+		    auth_type == NL80211_AUTHTYPE_IEEE8021X)
+			return false;
 		return true;
 	case NL80211_CMD_CONNECT:
 		if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
@@ -6563,6 +6567,10 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
 					     NL80211_EXT_FEATURE_EPPKE) &&
 		    auth_type == NL80211_AUTHTYPE_EPPKE)
 			return false;
+		if (!wiphy_ext_feature_isset(&rdev->wiphy,
+					     NL80211_EXT_FEATURE_IEEE8021X_AUTH) &&
+		    auth_type == NL80211_AUTHTYPE_IEEE8021X)
+			return false;
 		return true;
 	case NL80211_CMD_START_AP:
 		if (!wiphy_ext_feature_isset(&rdev->wiphy,
@@ -12077,7 +12085,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
 	     auth_type == NL80211_AUTHTYPE_FILS_SK ||
 	     auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
 	     auth_type == NL80211_AUTHTYPE_FILS_PK ||
-	     auth_type == NL80211_AUTHTYPE_EPPKE) &&
+	     auth_type == NL80211_AUTHTYPE_EPPKE ||
+	     auth_type == NL80211_AUTHTYPE_IEEE8021X) &&
 	    !info->attrs[NL80211_ATTR_AUTH_DATA])
 		return -EINVAL;
 
@@ -12086,7 +12095,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
 		    auth_type != NL80211_AUTHTYPE_FILS_SK &&
 		    auth_type != NL80211_AUTHTYPE_FILS_SK_PFS &&
 		    auth_type != NL80211_AUTHTYPE_FILS_PK &&
-		    auth_type != NL80211_AUTHTYPE_EPPKE)
+		    auth_type != NL80211_AUTHTYPE_EPPKE &&
+		    auth_type != NL80211_AUTHTYPE_IEEE8021X)
 			return -EINVAL;
 		req.auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
 		req.auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
-- 
2.34.1


^ permalink raw reply related

* [PATCH wireless-next 0/3] wifi: cfg80211/mac80211: Add support for IEEE 802.1X Authentication Protocol
From: Kavita Kavita @ 2026-02-26  6:54 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, kavita.kavita

Add support for the new IEEE 802.1X authentication protocol using
Authentication frames, both without (Re)Association frame encryption
as specified in "IEEE P802.11bi/D4.0, 12.16.5" and with
(Re)Association frame encryption as specified in
"IEEE P802.11bi/D4.0, 12.16.8.2".

This patch series introduces the required changes for non-AP STA mode.
For the AP mode, no additional changes are required for this
functionality. These patches have been tested end-to-end using the
Hwsim test tool.

Note: The patches apply cleanly and do not introduce any build issues
on their own. However, the IEEE 802.1X Authentication protocol depends
on (Re)Association frame encryption support introduced during EPPKE
feature development. Without this encryption support, the IEEE 802.1X
authentication functionality will not work properly, even though the
series itself builds independently.

Functional dependencies:
- [PATCH wireless-next v4 9/9] wifi: mac80211_hwsim: Declare support
  for EPPKE authentication protocol
  Link: https://lore.kernel.org/linux-wireless/20260114111900.2196941-10-kavita.kavita@oss.qualcomm.com/T/#m69c7b20e0e9242b40bfa888082f87a8c9211d46e
- [PATCH wireless-next v4] wifi: mac80211: Fix AAD/Nonce computation
  for management frames with MLO
  Link: https://lore.kernel.org/linux-wireless/20260226042959.3766157-1-sai.magam@oss.qualcomm.com/T/#u

Both functional dependencies are under review, and until they are
merged, this series cannot be fully functional.

Kavita Kavita (3):
  wifi: cfg80211: add support for IEEE 802.1X Authentication Protocol
  wifi: mac80211: Add support for IEEE 802.1X authentication protocol in
    non-AP STA mode
  wifi: mac80211_hwsim: Advertise support for IEEE 802.1X authentication
    protocol

 drivers/net/wireless/virtual/mac80211_hwsim.c |  2 +
 include/linux/ieee80211.h                     |  2 +
 include/uapi/linux/nl80211.h                  |  9 +++
 net/mac80211/mlme.c                           | 78 +++++++++++++++++--
 net/wireless/nl80211.c                        | 14 +++-
 5 files changed, 97 insertions(+), 8 deletions(-)


base-commit: 8bf22c33e7a172fbc72464f4cc484d23a6b412ba
-- 
2.34.1


^ permalink raw reply

* [PATCH ath-next] wifi: ath12k: account TX stats only when ACK/BA status is present
From: Sarika Sharma @ 2026-02-26  5:19 UTC (permalink / raw)
  To: ath12k; +Cc: linux-wireless, Sarika Sharma

The fields tx_retry_failed, tx_retry_count, and tx_duration are
currently updated outside the HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS
flag check. In certain scenarios, firmware delivers multiple PPDU
statistics for the same PPDU, first without BA/ACK information, and
later with BA/ACK status once it becomes available. As the same PPDU
is processed again, these counters are updated a second time,
resulting in duplicate TX statistics.

To address this, move the accounting of tx_retry_failed and
tx_retry_count under the ACK/BA status flag check, and similarly gate
tx_duration on the same path. This ensures that each PPDU contributes
to these counters exactly once, avoids double counting, and provides
consistent reporting in userspace tools such as station dump.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1

Fixes: a0b963e1da5b ("wifi: ath12k: fetch tx_retry and tx_failed from htt_ppdu_stats_user_cmpltn_common_tlv")
Signed-off-by: Sarika Sharma <sarika.sharma@oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath12k/dp_htt.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/dp_htt.c b/drivers/net/wireless/ath/ath12k/dp_htt.c
index cc71c5c5de5a..61c1c3b2350e 100644
--- a/drivers/net/wireless/ath/ath12k/dp_htt.c
+++ b/drivers/net/wireless/ath/ath12k/dp_htt.c
@@ -205,16 +205,9 @@ ath12k_update_per_peer_tx_stats(struct ath12k_pdev_dp *dp_pdev,
 	if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE)))
 		return;
 
-	if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) {
+	if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON))
 		is_ampdu =
 			HTT_USR_CMPLTN_IS_AMPDU(usr_stats->cmpltn_cmn.flags);
-		tx_retry_failed =
-			__le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_tried) -
-			__le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_success);
-		tx_retry_count =
-			HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) +
-			HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags);
-	}
 
 	if (usr_stats->tlv_flags &
 	    BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS)) {
@@ -223,10 +216,19 @@ ath12k_update_per_peer_tx_stats(struct ath12k_pdev_dp *dp_pdev,
 					  HTT_PPDU_STATS_ACK_BA_INFO_NUM_MSDU_M);
 		tid = le32_get_bits(usr_stats->ack_ba.info,
 				    HTT_PPDU_STATS_ACK_BA_INFO_TID_NUM);
-	}
 
-	if (common->fes_duration_us)
-		tx_duration = le32_to_cpu(common->fes_duration_us);
+		if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) {
+			tx_retry_failed =
+				__le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_tried) -
+				__le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_success);
+			tx_retry_count =
+				HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) +
+				HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags);
+		}
+
+		if (common->fes_duration_us)
+			tx_duration = le32_to_cpu(common->fes_duration_us);
+	}
 
 	user_rate = &usr_stats->rate;
 	flags = HTT_USR_RATE_PREAMBLE(user_rate->rate_flags);

base-commit: 62f9b9b19939138c34ce0ac1e5d4969d617ecbb6
-- 
2.34.1


^ permalink raw reply related

* [PATCH wireless-next v4] wifi: mac80211: Fix AAD/Nonce computation for management frames with MLO
From: Sai Pratyusha Magam @ 2026-02-26  4:29 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, sai.magam, quic_drohan

Per IEEE Std 802.11be-2024, 12.5.2.3.3, if the MPDU is an
individually addressed Data frame between an AP MLD and a
non-AP MLD associated with the AP MLD, then A1/A2/A3
will be MLD MAC addresses. Otherwise, Al/A2/A3 will be
over-the-air link MAC addresses.

Currently, during AAD and Nonce computation for software based
encryption/decryption cases, mac80211 directly uses the addresses it
receives in the skb frame header. However, after the first
authentication, management frame addresses for non-AP MLD stations
are translated to MLD addresses from over the air link addresses in
software. This means that the skb header could contain translated MLD
addresses, which when used as is, can lead to incorrect AAD/Nonce
computation.

In the following manner, ensure that the right set of addresses are used:

In the receive path, stash the pre-translated link addresses in
ieee80211_rx_data and use them for the AAD/Nonce computations
when required.

In the transmit path, offload the encryption for a CCMP/GCMP key
to the hwsim driver that can then ensure that encryption and hence
the AAD/Nonce computations are performed on the frame containing the
right set of addresses, i.e, MLD addresses if unicast data frame and
link addresses otherwise.

To do so, register the set key handler in hwsim driver so mac80211 is
aware that it is the driver that would take care of encrypting the
frame. Offload encryption for a CCMP/GCMP key, while keeping the
encryption for WEP/TKIP and MMIE generation for a AES_CMAC or a
AES_GMAC key still at the SW crypto in mac layer

Co-developed-by: Rohan Dutta <quic_drohan@quicinc.com>
Signed-off-by: Rohan Dutta <quic_drohan@quicinc.com>
Signed-off-by: Sai Pratyusha Magam <sai.magam@oss.qualcomm.com>
---
v3 -> v4:
With SW crypto, mac80211 took care of setting below features 
by default in ieee80211_alloc_hw_nm and now with driver ops 
set_key , i.e, encryption offload to driver, it is the driver 
that needs to explicitly set these ext features
NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT
NL80211_EXT_FEATURE_CAN_REPLACE_PTK0
NL80211_EXT_FEATURE_EXT_KEY_ID

v2 -> v3:
Added support for data tx encryption offload and removed the
logic around additional key flag(IEEE80211_KEY_FLAG_MGMT_TX_ENC_OFFLOAD)

v1 -> v2:
Removed the additional address translation to link addresses approach
in the encrypt/decrypt path for management frames and instead the rx
path uses the stashed pre-translated link addresses for decryption and
in the tx path, encryption for mgmt frames is offloaded to hwsim driver

 drivers/net/wireless/virtual/mac80211_hwsim.c | 46 ++++++++++++++-
 include/net/mac80211.h                        |  7 +++
 net/mac80211/ieee80211_i.h                    |  2 +
 net/mac80211/rx.c                             |  3 +
 net/mac80211/tx.c                             | 32 +++++++++++
 net/mac80211/wpa.c                            | 57 +++++++++++++++----
 6 files changed, 134 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
index 4d9f5f87e814..2b5ef58a4582 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
@@ -1955,6 +1955,25 @@ mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data,
 	return NULL;
 }
 
+static int mac80211_hwsim_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+				  struct ieee80211_vif *vif,
+				  struct ieee80211_sta *sta,
+				  struct ieee80211_key_conf *key)
+{
+	switch (key->cipher) {
+	case WLAN_CIPHER_SUITE_CCMP:
+	case WLAN_CIPHER_SUITE_CCMP_256:
+	case WLAN_CIPHER_SUITE_GCMP:
+	case WLAN_CIPHER_SUITE_GCMP_256:
+		break;
+	default:
+		return 1;
+	}
+
+	key->flags |= IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
+	return 0;
+}
+
 static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
 			      struct ieee80211_tx_control *control,
 			      struct sk_buff *skb)
@@ -1965,7 +1984,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
 	struct ieee80211_chanctx_conf *chanctx_conf;
 	struct ieee80211_channel *channel;
 	struct ieee80211_vif *vif = txi->control.vif;
-	bool ack;
+	bool ack, unicast_data;
 	enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT;
 	u32 _portid, i;
 
@@ -1975,6 +1994,16 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
 		return;
 	}
 
+	unicast_data = is_unicast_ether_addr(hdr->addr1) &&
+		       ieee80211_is_data(hdr->frame_control);
+
+	if (unicast_data && ieee80211_encrypt_tx_skb(skb) < 0) {
+		ieee80211_free_txskb(hw, skb);
+		return;
+	}
+	/* re-assign hdr since skb data may have shifted after encryption */
+	hdr = (void *)skb->data;
+
 	if (vif && vif->type == NL80211_IFTYPE_NAN && !data->tmp_chan) {
 		/* For NAN Device simulation purposes, assume that NAN is always
 		 * on channel 6 or channel 149, unless a ROC is in progress (for
@@ -2060,6 +2089,13 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
 		}
 	}
 
+	if (!unicast_data && ieee80211_encrypt_tx_skb(skb) < 0) {
+		ieee80211_free_txskb(hw, skb);
+		return;
+	}
+	/* re-assign hdr since skb data may have shifted after encryption */
+	hdr = (void *)skb->data;
+
 	if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) {
 		ieee80211_free_txskb(hw, skb);
 		return;
@@ -4189,6 +4225,7 @@ static int mac80211_hwsim_change_nan_config(struct ieee80211_hw *hw,
 	.start_nan = mac80211_hwsim_start_nan,                  \
 	.stop_nan = mac80211_hwsim_stop_nan,                    \
 	.nan_change_conf = mac80211_hwsim_change_nan_config,    \
+	.set_key = mac80211_hwsim_set_key,                     \
 	HWSIM_DEBUGFS_OPS
 
 #define HWSIM_NON_MLO_OPS					\
@@ -5621,6 +5658,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
 			    WIPHY_FLAG_AP_UAPSD |
 			    WIPHY_FLAG_SUPPORTS_5_10_MHZ |
 			    WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
 	hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
 			       NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
 			       NL80211_FEATURE_STATIC_SMPS |
@@ -5639,6 +5677,12 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
 			      NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT);
 	wiphy_ext_feature_set(hw->wiphy,
 			      NL80211_EXT_FEATURE_BSS_COLOR);
+	wiphy_ext_feature_set(hw->wiphy,
+			      NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT);
+	wiphy_ext_feature_set(hw->wiphy,
+			      NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
+	wiphy_ext_feature_set(hw->wiphy,
+			      NL80211_EXT_FEATURE_EXT_KEY_ID);
 
 	hw->wiphy->interface_modes = param->iftypes;
 
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 7f9d96939a4e..bfd7d2a781ec 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -7962,4 +7962,11 @@ int ieee80211_emulate_switch_vif_chanctx(struct ieee80211_hw *hw,
  * Return: %true iff the vif is a NAN interface and NAN is started
  */
 bool ieee80211_vif_nan_started(struct ieee80211_vif *vif);
+
+/**
+ * ieee80211_encrypt_tx_skb - Encrypt the transmit skb
+ * @skb: the skb
+ * Return: 0 if success and non-zero on error
+ */
+int ieee80211_encrypt_tx_skb(struct sk_buff *skb);
 #endif /* MAC80211_H */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index e60b814dd89e..a4babf7624e5 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -256,6 +256,8 @@ struct ieee80211_rx_data {
 			u8 pn[IEEE80211_CCMP_PN_LEN];
 		} ccm_gcm;
 	};
+
+	u8 link_addrs[3 * ETH_ALEN];
 };
 
 struct ieee80211_csa_settings {
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 11d6c56c9d7e..e8eb38cbafc6 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -5127,6 +5127,9 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
 		hdr = (struct ieee80211_hdr *)rx->skb->data;
 	}
 
+	/* Store a copy of the pre-translated link addresses */
+	memcpy(rx->link_addrs, &hdr->addrs, 3 * ETH_ALEN);
+
 	if (unlikely(rx->sta && rx->sta->sta.mlo) &&
 	    is_unicast_ether_addr(hdr->addr1) &&
 	    !ieee80211_is_probe_resp(hdr->frame_control) &&
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 007f5a368d41..3562d9a6b70a 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -5316,6 +5316,38 @@ static int ieee80211_beacon_protect(struct sk_buff *skb,
 	return 0;
 }
 
+int ieee80211_encrypt_tx_skb(struct sk_buff *skb)
+{
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_sub_if_data *sdata;
+	struct sk_buff *check_skb;
+	struct ieee80211_tx_data tx;
+	ieee80211_tx_result res;
+
+	if (!info->control.hw_key)
+		return 0;
+
+	memset(&tx, 0, sizeof(tx));
+	tx.key = container_of(info->control.hw_key, struct ieee80211_key, conf);
+	/* NULL it out now so we do full SW crypto */
+	info->control.hw_key = NULL;
+	__skb_queue_head_init(&tx.skbs);
+	__skb_queue_tail(&tx.skbs, skb);
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
+	tx.sdata = sdata;
+	tx.local = sdata->local;
+	res = ieee80211_tx_h_encrypt(&tx);
+	check_skb = __skb_dequeue(&tx.skbs);
+	/* we may crash after this, but it'd be a bug in crypto */
+	WARN_ON(check_skb != skb);
+	if (WARN_ON_ONCE(res != TX_CONTINUE))
+		return -EINVAL;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ieee80211_encrypt_tx_skb);
+
 static void
 ieee80211_beacon_get_finish(struct ieee80211_hw *hw,
 			    struct ieee80211_vif *vif,
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index fdf98c21d32c..2a66765b5c88 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -315,7 +315,8 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
  * Calculate AAD for CCMP/GCMP, returning qos_tid since we
  * need that in CCMP also for b_0.
  */
-static u8 ccmp_gcmp_aad(struct sk_buff *skb, u8 *aad, bool spp_amsdu)
+static u8 ccmp_gcmp_aad(struct sk_buff *skb, u8 *aad, bool spp_amsdu,
+			bool aad_nonce_computed)
 {
 	struct ieee80211_hdr *hdr = (void *)skb->data;
 	__le16 mask_fc;
@@ -358,7 +359,8 @@ static u8 ccmp_gcmp_aad(struct sk_buff *skb, u8 *aad, bool spp_amsdu)
 	 * FC | A1 | A2 | A3 | SC | [A4] | [QC] */
 	put_unaligned_be16(len_a, &aad[0]);
 	put_unaligned(mask_fc, (__le16 *)&aad[2]);
-	memcpy(&aad[4], &hdr->addrs, 3 * ETH_ALEN);
+	if (!aad_nonce_computed)
+		memcpy(&aad[4], &hdr->addrs, 3 * ETH_ALEN);
 
 	/* Mask Seq#, leave Frag# */
 	aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f;
@@ -377,10 +379,10 @@ static u8 ccmp_gcmp_aad(struct sk_buff *skb, u8 *aad, bool spp_amsdu)
 }
 
 static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad,
-				bool spp_amsdu)
+				bool spp_amsdu, bool aad_nonce_computed)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	u8 qos_tid = ccmp_gcmp_aad(skb, aad, spp_amsdu);
+	u8 qos_tid = ccmp_gcmp_aad(skb, aad, spp_amsdu, aad_nonce_computed);
 
 	/* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
 	 * mode authentication are not allowed to collide, yet both are derived
@@ -395,7 +397,8 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad,
 	 * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
 	 */
 	b_0[1] = qos_tid | (ieee80211_is_mgmt(hdr->frame_control) << 4);
-	memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
+	if (!aad_nonce_computed)
+		memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
 	memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN);
 }
 
@@ -488,7 +491,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb,
 
 	pos += IEEE80211_CCMP_HDR_LEN;
 	ccmp_special_blocks(skb, pn, b_0, aad,
-			    key->conf.flags & IEEE80211_KEY_FLAG_SPP_AMSDU);
+			    key->conf.flags & IEEE80211_KEY_FLAG_SPP_AMSDU,
+			    false);
 	return ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
 					 skb_put(skb, mic_len));
 }
@@ -566,9 +570,23 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx,
 		if (!(status->flag & RX_FLAG_DECRYPTED)) {
 			u8 aad[2 * AES_BLOCK_SIZE];
 			u8 b_0[AES_BLOCK_SIZE];
+			bool aad_nonce_computed = false;
+			bool unicast_data = is_unicast_ether_addr(hdr->addr1) &&
+					    ieee80211_is_data(hdr->frame_control);
+
+			if (!unicast_data) {
+				/* AAD computation */
+				memcpy(&aad[4], rx->link_addrs, 3 * ETH_ALEN);
+				/* Nonce computation */
+				ether_addr_copy(&b_0[2],
+						&rx->link_addrs[ETH_ALEN]);
+				aad_nonce_computed = true;
+			}
+
 			/* hardware didn't decrypt/verify MIC */
 			ccmp_special_blocks(skb, pn, b_0, aad,
-					    key->conf.flags & IEEE80211_KEY_FLAG_SPP_AMSDU);
+					    key->conf.flags & IEEE80211_KEY_FLAG_SPP_AMSDU,
+					    aad_nonce_computed);
 
 			if (ieee80211_aes_ccm_decrypt(
 				    key->u.ccmp.tfm, b_0, aad,
@@ -593,14 +611,15 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx,
 }
 
 static void gcmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *j_0, u8 *aad,
-				bool spp_amsdu)
+				bool spp_amsdu, bool aad_nonce_computed)
 {
 	struct ieee80211_hdr *hdr = (void *)skb->data;
 
-	memcpy(j_0, hdr->addr2, ETH_ALEN);
+	if (!aad_nonce_computed)
+		memcpy(j_0, hdr->addr2, ETH_ALEN);
 	memcpy(&j_0[ETH_ALEN], pn, IEEE80211_GCMP_PN_LEN);
 
-	ccmp_gcmp_aad(skb, aad, spp_amsdu);
+	ccmp_gcmp_aad(skb, aad, spp_amsdu, aad_nonce_computed);
 }
 
 static inline void gcmp_pn2hdr(u8 *hdr, const u8 *pn, int key_id)
@@ -690,7 +709,8 @@ static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 
 	pos += IEEE80211_GCMP_HDR_LEN;
 	gcmp_special_blocks(skb, pn, j_0, aad,
-			    key->conf.flags & IEEE80211_KEY_FLAG_SPP_AMSDU);
+			    key->conf.flags & IEEE80211_KEY_FLAG_SPP_AMSDU,
+			    false);
 	return ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len,
 					 skb_put(skb, IEEE80211_GCMP_MIC_LEN));
 }
@@ -763,9 +783,22 @@ ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx)
 		if (!(status->flag & RX_FLAG_DECRYPTED)) {
 			u8 aad[2 * AES_BLOCK_SIZE];
 			u8 j_0[AES_BLOCK_SIZE];
+			bool aad_nonce_computed = false;
+			bool unicast_data = is_unicast_ether_addr(hdr->addr1) &&
+					    ieee80211_is_data(hdr->frame_control);
+
+			if (!unicast_data) {
+				/* AAD computation */
+				memcpy(&aad[4], rx->link_addrs, 3 * ETH_ALEN);
+				/* Nonce computation */
+				ether_addr_copy(&j_0[0],
+						&rx->link_addrs[ETH_ALEN]);
+				aad_nonce_computed = true;
+			}
 			/* hardware didn't decrypt/verify MIC */
 			gcmp_special_blocks(skb, pn, j_0, aad,
-					    key->conf.flags & IEEE80211_KEY_FLAG_SPP_AMSDU);
+					    key->conf.flags & IEEE80211_KEY_FLAG_SPP_AMSDU,
+					    aad_nonce_computed);
 
 			if (ieee80211_aes_gcm_decrypt(
 				    key->u.gcmp.tfm, j_0, aad,

base-commit: 8bf22c33e7a172fbc72464f4cc484d23a6b412ba
-- 
2.34.1


^ permalink raw reply related

* [PATCH ath-next] wifi: ath12k: Fix the assignment of logical link index
From: Roopni Devanathan @ 2026-02-26  4:19 UTC (permalink / raw)
  To: ath12k; +Cc: linux-wireless, Manish Dharanenthiran, Roopni Devanathan

From: Manish Dharanenthiran <manish.dharanenthiran@oss.qualcomm.com>

Per-link logical index is assigned from the global counter,
ahsta->num_peer. This logical index is sent to firmware during peer
association. If there is a failure in creating a link station,
ath12k_mac_free_unassign_link_sta() clears the link, but does not decrement
the logical link index. This will result in a higher logical link index for
the next link station created. Also, if there is a leak in logical link
index as we assign the incremented num_peer, then the index can exceed the
maximum valid value of 15.

As an example, let's say we have a 2 GHz + 5 GHz + 6 GHz MLO setup. So the
logical link indices that they have are 0, 1 and 2, respectively. If the
5 GHz link is removed, logical link index 1 becomes available, and num_peer
is not reduced to 2 and still remains at 3. If a new 5 GHz link is added
later, it gets the index 3, instead of reusing link index 1. Also,
num_peer is increased to 4, though only 3 links are present.

To resolve these, create a bitmap, free_logical_link_idx, that tracks the
available logical link indices. When a link station is created, select the
first free logical index and when a link station is removed, mark its
logical link index as available by setting the bit.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01181-QCAHKSWPL_SILICONZ-1

Signed-off-by: Manish Dharanenthiran <manish.dharanenthiran@oss.qualcomm.com>
Signed-off-by: Roopni Devanathan <roopni.devanathan@oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath12k/core.h |  2 +-
 drivers/net/wireless/ath/ath12k/mac.c  | 16 ++++++++++++++--
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 990934ec92fc..5498ff285102 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -522,7 +522,7 @@ struct ath12k_sta {
 	u16 links_map;
 	u8 assoc_link_id;
 	u16 ml_peer_id;
-	u8 num_peer;
+	u16 free_logical_link_idx_map;
 
 	enum ieee80211_sta_state state;
 };
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 68431a0e128e..db1b098b67d0 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -6784,6 +6784,8 @@ static void ath12k_mac_free_unassign_link_sta(struct ath12k_hw *ah,
 		return;
 
 	ahsta->links_map &= ~BIT(link_id);
+	ahsta->free_logical_link_idx_map |= BIT(arsta->link_idx);
+
 	rcu_assign_pointer(ahsta->link[link_id], NULL);
 	synchronize_rcu();
 
@@ -7102,6 +7104,7 @@ static int ath12k_mac_assign_link_sta(struct ath12k_hw *ah,
 	struct ieee80211_sta *sta = ath12k_ahsta_to_sta(ahsta);
 	struct ieee80211_link_sta *link_sta;
 	struct ath12k_link_vif *arvif;
+	int link_idx;
 
 	lockdep_assert_wiphy(ah->hw->wiphy);
 
@@ -7120,8 +7123,16 @@ static int ath12k_mac_assign_link_sta(struct ath12k_hw *ah,
 
 	ether_addr_copy(arsta->addr, link_sta->addr);
 
-	/* logical index of the link sta in order of creation */
-	arsta->link_idx = ahsta->num_peer++;
+	if (!ahsta->free_logical_link_idx_map)
+		return -ENOSPC;
+
+	/*
+	 * Allocate a logical link index by selecting the first available bit
+	 * from the free logical index map
+	 */
+	link_idx = __ffs(ahsta->free_logical_link_idx_map);
+	ahsta->free_logical_link_idx_map &= ~BIT(link_idx);
+	arsta->link_idx = link_idx;
 
 	arsta->link_id = link_id;
 	ahsta->links_map |= BIT(arsta->link_id);
@@ -7630,6 +7641,7 @@ int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
 	if (old_state == IEEE80211_STA_NOTEXIST &&
 	    new_state == IEEE80211_STA_NONE) {
 		memset(ahsta, 0, sizeof(*ahsta));
+		ahsta->free_logical_link_idx_map = U16_MAX;
 
 		arsta = &ahsta->deflink;
 

base-commit: 62f9b9b19939138c34ce0ac1e5d4969d617ecbb6
-- 
2.43.0


^ permalink raw reply related

* [PATCH ath-next] wifi: ath11k: Pass the correct value of each TID during a stop AMPDU session
From: Reshma Immaculate Rajkumar @ 2026-02-26  4:05 UTC (permalink / raw)
  To: ath11k; +Cc: linux-wireless, Reshma Immaculate Rajkumar

During ongoing traffic, a request to stop an AMPDU session
for one TID could incorrectly affect other active sessions.
This can happen because an incorrect TID reference would be
passed when updating the BA session state, causing the wrong
session to be stopped. As a result, the affected session would
be reduced to a minimal BA size, leading to a noticeable
throughput degradation.

Fix this issue by passing the correct argument from
ath11k_dp_rx_ampdu_stop() to ath11k_peer_rx_tid_reo_update()
during a stop AMPDU session. Instead of passing peer->tx_tid, which
is the base address of the array, corresponding to TID 0; pass
the value of &peer->rx_tid[params->tid], where the different TID numbers
are accounted for.

Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.9.0.1-02146-QCAHKSWPL_SILICONZ-1

Fixes: d5c65159f2895 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
Signed-off-by: Reshma Immaculate Rajkumar <reshma.rajkumar@oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath11k/dp_rx.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index b9e976ddcbbf..d0a737995220 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -1110,9 +1110,8 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
 	struct ath11k_base *ab = ar->ab;
 	struct ath11k_peer *peer;
 	struct ath11k_sta *arsta = ath11k_sta_to_arsta(params->sta);
+	struct dp_rx_tid *rx_tid;
 	int vdev_id = arsta->arvif->vdev_id;
-	dma_addr_t paddr;
-	bool active;
 	int ret;
 
 	spin_lock_bh(&ab->base_lock);
@@ -1124,15 +1123,14 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
 		return -ENOENT;
 	}
 
-	paddr = peer->rx_tid[params->tid].paddr;
-	active = peer->rx_tid[params->tid].active;
+	rx_tid = &peer->rx_tid[params->tid];
 
-	if (!active) {
+	if (!rx_tid->active) {
 		spin_unlock_bh(&ab->base_lock);
 		return 0;
 	}
 
-	ret = ath11k_peer_rx_tid_reo_update(ar, peer, peer->rx_tid, 1, 0, false);
+	ret = ath11k_peer_rx_tid_reo_update(ar, peer, rx_tid, 1, 0, false);
 	spin_unlock_bh(&ab->base_lock);
 	if (ret) {
 		ath11k_warn(ab, "failed to update reo for rx tid %d: %d\n",
@@ -1141,7 +1139,7 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
 	}
 
 	ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id,
-						     params->sta->addr, paddr,
+						     params->sta->addr, rx_tid->paddr,
 						     params->tid, 1, 1);
 	if (ret)
 		ath11k_warn(ab, "failed to send wmi to delete rx tid %d\n",

base-commit: 8bf22c33e7a172fbc72464f4cc484d23a6b412ba
-- 
2.34.1


^ permalink raw reply related

* Re: [GIT PULL] wireless-2026-02-25
From: Jakub Kicinski @ 2026-02-26  3:57 UTC (permalink / raw)
  To: Johannes Berg; +Cc: netdev, linux-wireless
In-Reply-To: <20260225113159.360574-3-johannes@sipsolutions.net>

On Wed, 25 Feb 2026 12:30:47 +0100 Johannes Berg wrote:
> So for some reason a whole bunch of fixes came in recently,
> including quite a few (potential) crashes and similar. Most
> even are long-standing issues.
> 
> Please pull and let us know if there's any problem.

Pulled, thanks!

^ permalink raw reply

* [syzbot] [wireless?] WARNING in ieee80211_set_active_links (3)
From: syzbot @ 2026-02-26  3:22 UTC (permalink / raw)
  To: johannes, linux-kernel, linux-wireless, netdev, syzkaller-bugs

Hello,

syzbot found the following issue on:

HEAD commit:    7dff99b35460 Remove WARN_ALL_UNSEEDED_RANDOM kernel config..
git tree:       upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=113428d6580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=af6ed0125ed44356
dashboard link: https://syzkaller.appspot.com/bug?extid=582469b3a9ef5f13606b
compiler:       gcc (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44

Unfortunately, I don't have any reproducer for this issue yet.

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/45c7b6686727/disk-7dff99b3.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/36fcc9cd6296/vmlinux-7dff99b3.xz
kernel image: https://storage.googleapis.com/syzbot-assets/fe952fd2745b/bzImage-7dff99b3.xz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+582469b3a9ef5f13606b@syzkaller.appspotmail.com

wlan1: Created IBSS using preconfigured BSSID 50:50:50:50:50:50
wlan1: Creating new IBSS network, BSSID 50:50:50:50:50:50
------------[ cut here ]------------
wlan0: Failed check-sdata-in-driver check, flags: 0x0
WARNING: net/mac80211/driver-ops.h:1723 at drv_can_activate_links net/mac80211/driver-ops.h:1723 [inline], CPU#0: kworker/u10:3/11668
WARNING: net/mac80211/driver-ops.h:1723 at ieee80211_set_active_links+0x2d0/0x9d0 net/mac80211/link.c:595, CPU#0: kworker/u10:3/11668
Modules linked in:
CPU: 0 UID: 0 PID: 11668 Comm: kworker/u10:3 Tainted: G     U       L      syzkaller #0 PREEMPT(full) 
Tainted: [U]=USER, [L]=SOFTLOCKUP
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2026
Workqueue: events_unbound cfg80211_wiphy_work
RIP: 0010:drv_can_activate_links net/mac80211/driver-ops.h:1723 [inline]
RIP: 0010:ieee80211_set_active_links+0x2d7/0x9d0 net/mac80211/link.c:595
Code: 06 00 00 e8 fb 8e 05 f7 48 8b 34 24 48 81 c6 20 01 00 00 48 89 34 24 e8 e7 8e 05 f7 48 8d 3d 20 ef e7 05 48 8b 34 24 44 89 fa <67> 48 0f b9 3a e9 e0 fe ff ff e8 ca 8e 05 f7 0f b7 c5 4c 8d bb 30
RSP: 0018:ffffc90004947af0 EFLAGS: 00010293
RAX: 0000000000000000 RBX: ffff888029d2aa90 RCX: ffffffff8b026bfe
RDX: 0000000000000000 RSI: ffff888029d28120 RDI: ffffffff90ea5b80
RBP: 000000000000000a R08: 0000000000000005 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000000 R12: ffff888029d297f8
R13: 0000000000000000 R14: ffff8881446c8e80 R15: 0000000000000000
FS:  0000000000000000(0000) GS:ffff888124351000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00005641c1b014d8 CR3: 000000002d732000 CR4: 00000000003526f0
Call Trace:
 <TASK>
 ieee80211_if_parse_active_links+0xbb/0x120 net/mac80211/debugfs_netdev.c:732
 wiphy_locked_debugfs_write_work+0xe6/0x1c0 net/wireless/debugfs.c:248
 cfg80211_wiphy_work+0x446/0x5c0 net/wireless/core.c:440
 process_one_work+0x9d7/0x1920 kernel/workqueue.c:3275
 process_scheduled_works kernel/workqueue.c:3358 [inline]
 worker_thread+0x5da/0xe40 kernel/workqueue.c:3439
 kthread+0x370/0x450 kernel/kthread.c:467
 ret_from_fork+0x754/0xd80 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
 </TASK>
----------------
Code disassembly (best guess), 1 bytes skipped:
   0:	00 00                	add    %al,(%rax)
   2:	e8 fb 8e 05 f7       	call   0xf7058f02
   7:	48 8b 34 24          	mov    (%rsp),%rsi
   b:	48 81 c6 20 01 00 00 	add    $0x120,%rsi
  12:	48 89 34 24          	mov    %rsi,(%rsp)
  16:	e8 e7 8e 05 f7       	call   0xf7058f02
  1b:	48 8d 3d 20 ef e7 05 	lea    0x5e7ef20(%rip),%rdi        # 0x5e7ef42
  22:	48 8b 34 24          	mov    (%rsp),%rsi
  26:	44 89 fa             	mov    %r15d,%edx
* 29:	67 48 0f b9 3a       	ud1    (%edx),%rdi <-- trapping instruction
  2e:	e9 e0 fe ff ff       	jmp    0xffffff13
  33:	e8 ca 8e 05 f7       	call   0xf7058f02
  38:	0f b7 c5             	movzwl %bp,%eax
  3b:	4c                   	rex.WR
  3c:	8d                   	.byte 0x8d
  3d:	bb                   	.byte 0xbb
  3e:	30                   	.byte 0x30


---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.

If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title

If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)

If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report

If you want to undo deduplication, reply with:
#syz undup

^ permalink raw reply

* Re: [RFC PATCH 2/2] wifi: ath10k: only wait for response to SET_KEY
From: Baochen Qiang @ 2026-02-26  2:59 UTC (permalink / raw)
  To: Jeff Johnson, James Prestwood, Richard Acayan, linux-wireless,
	ath10k
In-Reply-To: <3e1274fd-fe95-420c-94e3-ac34f497b7ae@oss.qualcomm.com>



On 2/13/2026 1:56 AM, Jeff Johnson wrote:
> On 2/11/2026 6:11 PM, James Prestwood wrote:
>> On 2/9/26 6:12 PM, Richard Acayan wrote:
>>> When sending DELETE_KEY, the driver times out waiting for a response
>>> that doesn't come. Only wait for a response when sending SET_KEY.
>>
>> We've run into the exact same thing on the QCA6174 and have been 
>> carrying an identical patch to this for at least a year.
>>
>> https://lore.kernel.org/linux-wireless/b2838a23-ea30-4dee-b513-f5471d486af2@gmail.com/
> 
> Baochen,
> Were we ever able to reproduce this?

unfortunately no

> Do we normally always get a response to DELETE_KEY but in some instances it
> comes very late (or not at all)?

In my tests, I never hit this issue so seems can always get a response.

> If we remove the wait, is there any concern that a late arriving DELETE_KEY
> response might be processed as a response to a subsequent SET_KEY command?

I would suggest not to remove the wait, but instead reduce the timeout to like 1s, just
like the patch "[RFC 0/1] wifi: ath10k: improvement on key removal failure".

> 
> /jeff


^ permalink raw reply

* Re: [PATCH ath-next v2 2/4] wifi: ath12k: avoid long fw_stats waits on vdev stats hot path
From: Baochen Qiang @ 2026-02-26  1:50 UTC (permalink / raw)
  To: m.limarencko, jjohnson; +Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <20260212121746.329619-3-m.limarencko@yandex.ru>



On 2/12/2026 8:17 PM, m.limarencko@yandex.ru wrote:
> From: Mikhail Limarenko <m.limarencko@yandex.ru>
> 
> Station info requests can trigger frequent VDEV stat pulls from
> 
> user space (iw/NM polling).
> 
> On affected firmware, waiting 3 seconds for fw_stats_done causes
> 
> repeated stalls and visible hitches.
> 
> Use a short timeout for VDEV_STAT requests and skip unnecessary
> 
> waits for stats types that do not need completion
> 
> synchronization.

once again, can you please try

https://lore.kernel.org/ath12k/20260129-ath12k-fw-stats-fixes-v1-0-55d66064f4d5@oss.qualcomm.com/

> 
> Tested-on: QCNFA765 (WCN785x), kernel 6.18.5+deb13-amd64
> Signed-off-by: Mikhail Limarenko <m.limarencko@yandex.ru>
> ---
>  drivers/net/wireless/ath/ath12k/mac.c | 22 ++++++++++++++++++++--
>  1 file changed, 20 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 095b49a..1b550e9 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -4829,6 +4829,7 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar,
>  {
>  	struct ath12k_base *ab = ar->ab;
>  	struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
> +	unsigned long done_timeout = 3 * HZ;
>  	unsigned long time_left;
>  	int ret;
>  
> @@ -4859,15 +4860,32 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar,
>  		return -ETIMEDOUT;
>  	}
>  
> +	/* VDEV stats are queried frequently from station info paths (e.g. iw/NM).
> +	 * On buggy firmware this path can timeout repeatedly and block callers for
> +	 * multiple seconds; keep the hot path responsive while preserving behavior
> +	 * for other stats types.
> +	 */
> +	if (param->stats_id & WMI_REQUEST_VDEV_STAT)
> +		done_timeout = msecs_to_jiffies(200);
> +
> +	/* Non-vdev/bcn stats are handled in a single event. */
> +	if (!(param->stats_id & (WMI_REQUEST_VDEV_STAT | WMI_REQUEST_BCN_STAT)))
> +		return 0;
> +
>  	/* Firmware sends WMI_UPDATE_STATS_EVENTID back-to-back
>  	 * when stats data buffer limit is reached. fw_stats_complete
>  	 * is completed once host receives first event from firmware, but
>  	 * still there could be more events following. Below is to wait
>  	 * until firmware completes sending all the events.
>  	 */
> -	time_left = wait_for_completion_timeout(&ar->fw_stats_done, 3 * HZ);
> +	time_left = wait_for_completion_timeout(&ar->fw_stats_done, done_timeout);
>  	if (!time_left) {
> -		ath12k_warn(ab, "time out while waiting for fw stats done\n");
> +		if (param->stats_id & WMI_REQUEST_VDEV_STAT)
> +			ath12k_dbg(ab, ATH12K_DBG_WMI,
> +				   "time out while waiting for fw stats done (stats_id 0x%x)\n",
> +				   param->stats_id);
> +		else
> +			ath12k_warn(ab, "time out while waiting for fw stats done\n");
>  		return -ETIMEDOUT;
>  	}
>  


^ permalink raw reply

* Re: [PATCH ath-next] wifi: ath12k: Fix legacy rate mapping for monitor mode capture
From: Baochen Qiang @ 2026-02-26  1:48 UTC (permalink / raw)
  To: Thiraviyam Mariyappan, ath12k; +Cc: linux-wireless, P Praneesh
In-Reply-To: <20260209054924.2713072-1-thiraviyam.mariyappan@oss.qualcomm.com>



On 2/9/2026 1:49 PM, Thiraviyam Mariyappan wrote:
> From: P Praneesh <praneesh.p@oss.qualcomm.com>
> 
> The current implementation incorrectly reports legacy CCK and OFDM rates
> in monitor mode radiotap headers. The rate field displays wrong values,
> for example showing 11 Mbps when the actual rate is 1 Mbps. This occurs
> because the HAL layer uses a unified enum for both CCK and OFDM rates
> without distinguishing between long/short preamble variants and proper
> rate mapping to hardware rate indices.
> 
> The root cause is threefold:
> 
> 1. The hal_rx_legacy_rate enum conflates CCK and OFDM rates into a
>    single enumeration, making it impossible to differentiate between
>    802.11b CCK rates (with long/short preamble variants) and 802.11a/g
>    OFDM rates.
> 
> 2. The L-SIG-B parsing function maps hardware rate values to the wrong
>    enum values. For CCK rates, it incorrectly combines long and short
>    preamble cases (e.g., cases 2 and 5 both map to 2 Mbps), losing
>    preamble information critical for proper rate identification.
> 
> 3. The mac layer's rate-to-index conversion function does not properly
>    handle the precedence between long preamble, short preamble, and
>    OFDM rates when matching hardware rate values.
> 
> Split the hal_rx_legacy_rate enum into two separate enumerations:
> hal_rx_legacy_rate for CCK rates with explicit long preamble (LP) and
> short preamble (SP) variants, and hal_rx_legacy_rates_ofdm for OFDM
> rates. This separation allows proper identification of rate types and
> preamble modes.
> 
> Introduce a new mapping ath12k_wifi7_hal_mon_map_legacy_rate_to_hw_rate()
> that converts HAL CCK rate enums to hardware rate indices defined in
> ath12k_hw_rate_cck. This ensures the rate field in ppdu_info contains
> the correct hardware rate index that matches the mac layer's expectations.
> 
> Update the L-SIG-B parsing to map each hardware rate value (1-7) to its
> corresponding CCK rate enum with proper preamble designation:
> - Cases 1-4: Long preamble (1, 2, 5.5, 11 Mbps)
> - Cases 5-7: Short preamble (2, 5.5, 11 Mbps)
> 
> Update the L-SIG-A parsing to use the new OFDM-specific enum values,
> maintaining the existing rate mapping for 802.11a/g OFDM rates.
> 
> Refactor the mac layer's ath12k_mac_hw_rate_to_idx() function to
> implement proper matching precedence:
> 1. First match OFDM rates using the IEEE80211_RATE_MANDATORY_A flag
> 2. Then match CCK short preamble rates
> 3. Finally match CCK long preamble rates as fallback
> 
> Add helper macros ATH12K_MAC_RATE_A_M and ATH12K_MAC_RATE_B to improve
> readability of the rate table initialization and ensure the mandatory
> flag is set for OFDM rates.
> 
> This fix ensures monitor mode captures display accurate rate information
> in the radiotap header, correctly distinguishing between 1 Mbps and
> 11 Mbps, and properly identifying preamble types for CCK rates.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01181-QCAHKSWPL_SILICONZ-1
> 
> Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices")
> Signed-off-by: P Praneesh <praneesh.p@oss.qualcomm.com>
> Signed-off-by: Thiraviyam Mariyappan <thiraviyam.mariyappan@oss.qualcomm.com>
> ---
>  drivers/net/wireless/ath/ath12k/hal.h         | 31 +++++---
>  drivers/net/wireless/ath/ath12k/mac.c         | 51 +++++++------
>  .../net/wireless/ath/ath12k/wifi7/dp_mon.c    | 76 +++++++++++++++----
>  3 files changed, 108 insertions(+), 50 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h
> index 43e3880f8257..bf4f7dbae866 100644
> --- a/drivers/net/wireless/ath/ath12k/hal.h
> +++ b/drivers/net/wireless/ath/ath12k/hal.h
> @@ -268,21 +268,28 @@ enum hal_rx_reception_type {
>  };
>  
>  enum hal_rx_legacy_rate {
> -	HAL_RX_LEGACY_RATE_1_MBPS,
> -	HAL_RX_LEGACY_RATE_2_MBPS,
> -	HAL_RX_LEGACY_RATE_5_5_MBPS,
> -	HAL_RX_LEGACY_RATE_6_MBPS,
> -	HAL_RX_LEGACY_RATE_9_MBPS,
> -	HAL_RX_LEGACY_RATE_11_MBPS,
> -	HAL_RX_LEGACY_RATE_12_MBPS,
> -	HAL_RX_LEGACY_RATE_18_MBPS,
> -	HAL_RX_LEGACY_RATE_24_MBPS,
> -	HAL_RX_LEGACY_RATE_36_MBPS,
> -	HAL_RX_LEGACY_RATE_48_MBPS,
> -	HAL_RX_LEGACY_RATE_54_MBPS,
> +	HAL_RX_LEGACY_RATE_LP_1_MBPS,
> +	HAL_RX_LEGACY_RATE_LP_2_MBPS,
> +	HAL_RX_LEGACY_RATE_LP_5_5_MBPS,
> +	HAL_RX_LEGACY_RATE_LP_11_MBPS,
> +	HAL_RX_LEGACY_RATE_SP_2_MBPS,
> +	HAL_RX_LEGACY_RATE_SP_5_5_MBPS,
> +	HAL_RX_LEGACY_RATE_SP_11_MBPS,
>  	HAL_RX_LEGACY_RATE_INVALID,
>  };
>  
> +enum hal_rx_legacy_rates_ofdm {
> +	HAL_RX_LEGACY_RATE_OFDM_48_MBPS,
> +	HAL_RX_LEGACY_RATE_OFDM_24_MBPS,
> +	HAL_RX_LEGACY_RATE_OFDM_12_MBPS,
> +	HAL_RX_LEGACY_RATE_OFDM_6_MBPS,
> +	HAL_RX_LEGACY_RATE_OFDM_54_MBPS,
> +	HAL_RX_LEGACY_RATE_OFDM_36_MBPS,
> +	HAL_RX_LEGACY_RATE_OFDM_18_MBPS,
> +	HAL_RX_LEGACY_RATE_OFDM_9_MBPS,
> +	HAL_RX_LEGACY_RATE_OFDM_INVALID,
> +};
> +
>  enum hal_ring_type {
>  	HAL_REO_DST,
>  	HAL_REO_EXCEPTION,
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 6c534f0d59ce..035937dde5c6 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -164,30 +164,31 @@ static const struct ieee80211_channel ath12k_6ghz_channels[] = {
>  	CHAN6G(233, 7115, 0),
>  };
>  
> +#define ATH12K_MAC_RATE_A_M(bps, code) \
> +	{ .bitrate = (bps), .hw_value = (code),\
> +	  .flags = IEEE80211_RATE_MANDATORY_A }
> +
> +#define ATH12K_MAC_RATE_B(bps, code, code_short) \
> +	{ .bitrate = (bps), .hw_value = (code), .hw_value_short = (code_short),\
> +	  .flags = IEEE80211_RATE_SHORT_PREAMBLE }
> +
>  static struct ieee80211_rate ath12k_legacy_rates[] = {
>  	{ .bitrate = 10,
>  	  .hw_value = ATH12K_HW_RATE_CCK_LP_1M },
> -	{ .bitrate = 20,
> -	  .hw_value = ATH12K_HW_RATE_CCK_LP_2M,
> -	  .hw_value_short = ATH12K_HW_RATE_CCK_SP_2M,
> -	  .flags = IEEE80211_RATE_SHORT_PREAMBLE },
> -	{ .bitrate = 55,
> -	  .hw_value = ATH12K_HW_RATE_CCK_LP_5_5M,
> -	  .hw_value_short = ATH12K_HW_RATE_CCK_SP_5_5M,
> -	  .flags = IEEE80211_RATE_SHORT_PREAMBLE },
> -	{ .bitrate = 110,
> -	  .hw_value = ATH12K_HW_RATE_CCK_LP_11M,
> -	  .hw_value_short = ATH12K_HW_RATE_CCK_SP_11M,
> -	  .flags = IEEE80211_RATE_SHORT_PREAMBLE },
> -
> -	{ .bitrate = 60, .hw_value = ATH12K_HW_RATE_OFDM_6M },
> -	{ .bitrate = 90, .hw_value = ATH12K_HW_RATE_OFDM_9M },
> -	{ .bitrate = 120, .hw_value = ATH12K_HW_RATE_OFDM_12M },
> -	{ .bitrate = 180, .hw_value = ATH12K_HW_RATE_OFDM_18M },
> -	{ .bitrate = 240, .hw_value = ATH12K_HW_RATE_OFDM_24M },
> -	{ .bitrate = 360, .hw_value = ATH12K_HW_RATE_OFDM_36M },
> -	{ .bitrate = 480, .hw_value = ATH12K_HW_RATE_OFDM_48M },
> -	{ .bitrate = 540, .hw_value = ATH12K_HW_RATE_OFDM_54M },
> +	ATH12K_MAC_RATE_B(20, ATH12K_HW_RATE_CCK_LP_2M,
> +			  ATH12K_HW_RATE_CCK_SP_2M),
> +	ATH12K_MAC_RATE_B(55, ATH12K_HW_RATE_CCK_LP_5_5M,
> +			  ATH12K_HW_RATE_CCK_SP_5_5M),
> +	ATH12K_MAC_RATE_B(110, ATH12K_HW_RATE_CCK_LP_11M,
> +			  ATH12K_HW_RATE_CCK_SP_11M),
> +	ATH12K_MAC_RATE_A_M(60, ATH12K_HW_RATE_OFDM_6M),
> +	ATH12K_MAC_RATE_A_M(90, ATH12K_HW_RATE_OFDM_9M),
> +	ATH12K_MAC_RATE_A_M(120, ATH12K_HW_RATE_OFDM_12M),
> +	ATH12K_MAC_RATE_A_M(180, ATH12K_HW_RATE_OFDM_18M),
> +	ATH12K_MAC_RATE_A_M(240, ATH12K_HW_RATE_OFDM_24M),
> +	ATH12K_MAC_RATE_A_M(360, ATH12K_HW_RATE_OFDM_36M),
> +	ATH12K_MAC_RATE_A_M(480, ATH12K_HW_RATE_OFDM_48M),
> +	ATH12K_MAC_RATE_A_M(540, ATH12K_HW_RATE_OFDM_54M),
>  };
>  
>  static const int
> @@ -732,11 +733,17 @@ u8 ath12k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
>  		if (ath12k_mac_bitrate_is_cck(rate->bitrate) != cck)
>  			continue;
>  
> -		if (rate->hw_value == hw_rate)
> +		/* To handle 802.11a PPDU type */
> +		if ((!cck) && (rate->hw_value == hw_rate) &&
> +		    (rate->flags & IEEE80211_RATE_MANDATORY_A))
>  			return i;
> +		/* To handle 802.11b short PPDU type */
>  		else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE &&
>  			 rate->hw_value_short == hw_rate)
>  			return i;
> +		/* To handle 802.11b long PPDU type */
> +		else if (rate->hw_value == hw_rate)
> +			return i;
>  	}
>  
>  	return 0;
> diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
> index bd741532b7dc..074df2ab6bbf 100644
> --- a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
> +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
> @@ -405,6 +405,42 @@ ath12k_wifi7_dp_mon_hal_rx_parse_user_info(const struct hal_receive_user_info *r
>  	}
>  }
>  
> +static __always_inline u8
> +ath12k_wifi7_hal_mon_map_legacy_rate_to_hw_rate(u8 rate)
> +{
> +	u8 ath12k_rate;
> +
> +	/* Map hal_rx_legacy_rate to ath12k_hw_rate_cck */
> +	switch (rate) {
> +	case HAL_RX_LEGACY_RATE_LP_1_MBPS:
> +		ath12k_rate = ATH12K_HW_RATE_CCK_LP_1M;
> +		break;
> +	case HAL_RX_LEGACY_RATE_LP_2_MBPS:
> +		ath12k_rate = ATH12K_HW_RATE_CCK_LP_2M;
> +		break;
> +	case HAL_RX_LEGACY_RATE_LP_5_5_MBPS:
> +		ath12k_rate = ATH12K_HW_RATE_CCK_LP_5_5M;
> +		break;
> +	case HAL_RX_LEGACY_RATE_LP_11_MBPS:
> +		ath12k_rate = ATH12K_HW_RATE_CCK_LP_11M;
> +		break;
> +	case HAL_RX_LEGACY_RATE_SP_2_MBPS:
> +		ath12k_rate = ATH12K_HW_RATE_CCK_SP_2M;
> +		break;
> +	case HAL_RX_LEGACY_RATE_SP_5_5_MBPS:
> +		ath12k_rate = ATH12K_HW_RATE_CCK_SP_5_5M;
> +		break;
> +	case HAL_RX_LEGACY_RATE_SP_11_MBPS:
> +		ath12k_rate = ATH12K_HW_RATE_CCK_SP_11M;
> +		break;
> +	default:
> +		ath12k_rate = rate;
> +		break;
> +	}
> +
> +	return ath12k_rate;
> +}
> +
>  static void
>  ath12k_wifi7_dp_mon_parse_l_sig_b(const struct hal_rx_lsig_b_info *lsigb,
>  				  struct hal_rx_mon_ppdu_info *ppdu_info)
> @@ -415,25 +451,32 @@ ath12k_wifi7_dp_mon_parse_l_sig_b(const struct hal_rx_lsig_b_info *lsigb,
>  	rate = u32_get_bits(info0, HAL_RX_LSIG_B_INFO_INFO0_RATE);
>  	switch (rate) {
>  	case 1:
> -		rate = HAL_RX_LEGACY_RATE_1_MBPS;
> +		rate = HAL_RX_LEGACY_RATE_LP_1_MBPS;
>  		break;
>  	case 2:
> -	case 5:
> -		rate = HAL_RX_LEGACY_RATE_2_MBPS;
> +		rate = HAL_RX_LEGACY_RATE_LP_2_MBPS;
>  		break;
>  	case 3:
> -	case 6:
> -		rate = HAL_RX_LEGACY_RATE_5_5_MBPS;
> +		rate = HAL_RX_LEGACY_RATE_LP_5_5_MBPS;
>  		break;
>  	case 4:
> +		rate = HAL_RX_LEGACY_RATE_LP_11_MBPS;
> +		break;
> +	case 5:
> +		rate = HAL_RX_LEGACY_RATE_SP_2_MBPS;
> +		break;
> +	case 6:
> +		rate = HAL_RX_LEGACY_RATE_SP_5_5_MBPS;
> +		break;
>  	case 7:
> -		rate = HAL_RX_LEGACY_RATE_11_MBPS;
> +		rate = HAL_RX_LEGACY_RATE_SP_11_MBPS;
>  		break;
>  	default:
>  		rate = HAL_RX_LEGACY_RATE_INVALID;
> +		break;
>  	}
>  
> -	ppdu_info->rate = rate;
> +	ppdu_info->rate = ath12k_wifi7_hal_mon_map_legacy_rate_to_hw_rate(rate);
>  	ppdu_info->cck_flag = 1;
>  }
>  
> @@ -447,31 +490,32 @@ ath12k_wifi7_dp_mon_parse_l_sig_a(const struct hal_rx_lsig_a_info *lsiga,
>  	rate = u32_get_bits(info0, HAL_RX_LSIG_A_INFO_INFO0_RATE);
>  	switch (rate) {
>  	case 8:
> -		rate = HAL_RX_LEGACY_RATE_48_MBPS;
> +		rate = HAL_RX_LEGACY_RATE_OFDM_48_MBPS;
>  		break;
>  	case 9:
> -		rate = HAL_RX_LEGACY_RATE_24_MBPS;
> +		rate = HAL_RX_LEGACY_RATE_OFDM_24_MBPS;
>  		break;
>  	case 10:
> -		rate = HAL_RX_LEGACY_RATE_12_MBPS;
> +		rate = HAL_RX_LEGACY_RATE_OFDM_12_MBPS;
>  		break;
>  	case 11:
> -		rate = HAL_RX_LEGACY_RATE_6_MBPS;
> +		rate = HAL_RX_LEGACY_RATE_OFDM_6_MBPS;
>  		break;
>  	case 12:
> -		rate = HAL_RX_LEGACY_RATE_54_MBPS;
> +		rate = HAL_RX_LEGACY_RATE_OFDM_54_MBPS;
>  		break;
>  	case 13:
> -		rate = HAL_RX_LEGACY_RATE_36_MBPS;
> +		rate = HAL_RX_LEGACY_RATE_OFDM_36_MBPS;
>  		break;
>  	case 14:
> -		rate = HAL_RX_LEGACY_RATE_18_MBPS;
> +		rate = HAL_RX_LEGACY_RATE_OFDM_18_MBPS;
>  		break;
>  	case 15:
> -		rate = HAL_RX_LEGACY_RATE_9_MBPS;
> +		rate = HAL_RX_LEGACY_RATE_OFDM_9_MBPS;
>  		break;
>  	default:
> -		rate = HAL_RX_LEGACY_RATE_INVALID;
> +		rate = HAL_RX_LEGACY_RATE_OFDM_INVALID;
> +		break;
>  	}
>  
>  	ppdu_info->rate = rate;
> 
> base-commit: 2c1ba9c2adf0fda96eaaebd8799268a7506a8fc9

Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>


^ permalink raw reply

* Re: [patch] wifi: mt76: mt7925: fix incorrect TLV length in CLC command
From: Sean Wang @ 2026-02-25 23:05 UTC (permalink / raw)
  To: Quan Zhou
  Cc: Felix Fietkau, Lorenzo Bianconi, Sean Wang, Deren Wu, Ryder Lee,
	Shayne Chen, Leon Yen, Ming Yen Hsieh, Allan Wang, Sarick Jiang,
	Posh Sun, Shengxi Xu, Eric-SY Chang, Michael Lo, CH Yeh,
	Robin Chiu, linux-wireless, linux-mediatek, stable
In-Reply-To: <f56ae0e705774dfa8aab3b99e5bbdc92cd93523e.1772011204.git.quan.zhou@mediatek.com>

On Wed, Feb 25, 2026 at 3:48 AM Quan Zhou <quan.zhou@mediatek.com> wrote:
>
> The previous implementation of __mt7925_mcu_set_clc() set the TLV length
> field (.len) incorrectly during CLC command construction. The length was
> initialized as sizeof(req) - 4, regardless of the actual segment length.
> This could cause the WiFi firmware to misinterpret the command payload,
> resulting in command execution errors.
>
> This patch moves the TLV length assignment to after the segment is
> selected, and sets .len to sizeof(req) + seg->len - 4, matching the
> actual command content. This ensures the firmware receives the
> correct TLV length and parses the command properly.
>
> Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
> Cc: stable@vger.kernel.org
> Signed-off-by: Quan Zhou <quan.zhou@mediatek.com>
> ---
>  drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
> index 1379bf6a26b5..abcdd0e0b3b5 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
> @@ -3380,7 +3380,6 @@ __mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
>                 u8 rsvd[64];
>         } __packed req = {
>                 .tag = cpu_to_le16(0x3),
> -               .len = cpu_to_le16(sizeof(req) - 4),
>
>                 .idx = idx,
>                 .env = env_cap,
> @@ -3409,6 +3408,7 @@ __mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
>                 memcpy(req.type, rule->type, 2);
>
>                 req.size = cpu_to_le16(seg->len);
> +               req.len = cpu_to_le16(sizeof(req) + seg->len - 4);
>                 dev->phy.clc_chan_conf = clc->ver == 1 ? 0xff : rule->flag;
>                 skb = __mt76_mcu_msg_alloc(&dev->mt76, &req,
>                                            le16_to_cpu(req.size) + sizeof(req),

This looks good. It can help improve stability and avoid firmware
misparsing and MCU timeouts.
Acked-by: Sean Wang <sean.wang@mediatek.com>

> --
> 2.45.2
>
>

^ permalink raw reply

* Re: [PATCH ath-next v2 0/4] wifi: ath12k: harden stats/rate handling for WCN785x stability
From: Jeff Johnson @ 2026-02-25 22:24 UTC (permalink / raw)
  To: m.limarencko, jjohnson; +Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <20260212121746.329619-1-m.limarencko@yandex.ru>

On 2/12/2026 4:17 AM, m.limarencko@yandex.ru wrote:
> From: Mikhail Limarenko <m.limarencko@yandex.ru>
> 
> Hi Jeff, all,
> 
> On QCNFA765/WCN785x (PCI, kernel 6.18.5) we observed three recurring
> issues:
> 
> - chan info events with frequency not present in local survey range,
>   producing invalid idx warnings;
> - frequent VDEV_STAT polling can block for 3 seconds on fw_stats_done
>   timeouts and cause visible hitches;
> - occasional invalid MCS metadata (for example HE MCS=12) propagates
>   into mac80211 status handling and correlates with ieee80211_rx_list
>   warnings.
> 
> This series addresses those cases by:
> 1. returning an explicit error from freq_to_idx() when no channel
>    matches, and rejecting negative indexes in callers;
> 2. reducing the wait on VDEV_STAT fw_stats completion and skipping
>    unnecessary waits for stats types that do not require it;
> 3. sanitizing invalid MCS metadata in both dp_rx and dp_mon paths by
>    falling back to legacy metadata with ratelimited diagnostics.
> 
> Tested on:
> - hardware: QCNFA765 (WCN785x)
> - kernel: 6.18.5+deb13-amd64
> - AP mode: 5 GHz (802.11ac)
> 
> Observed after applying this series:
> - station dump polling no longer shows multi-second stalls in test runs;
> - no fresh ieee80211_rx_list WARN was observed in the same windows.
> 
> v2:
> - patch 1/4 commit message no longer claims OOB in chan-info paths
> - patch 1/4 keeps matched-frequency index progression unchanged
> - patch 1/4 returns -ENOENT on no-match and callers reject negative idx
> 
> Thanks,
> Mikhail Limarenko
> 
> Mikhail Limarenko (4):
>   wifi: ath12k: return error when survey frequency is not found
>   wifi: ath12k: avoid long fw_stats waits on vdev stats hot path
>   wifi: ath12k: sanitize invalid MCS metadata in rx path
>   wifi: ath12k: sanitize invalid MCS metadata in monitor rx path
> 
>  drivers/net/wireless/ath/ath12k/dp_mon.c | 38 ++++++++++++++---------
>  drivers/net/wireless/ath/ath12k/dp_rx.c  | 39 ++++++++++++++----------
>  drivers/net/wireless/ath/ath12k/mac.c    | 22 +++++++++++--
>  drivers/net/wireless/ath/ath12k/wmi.c    |  9 +++------
>  4 files changed, 70 insertions(+), 38 deletions(-)
> 

This series does not apply cleanly to ath/main (or ath/ath-next).

Please make sure the issues you saw have not already been fixed since there
were substantial changes from 6.18 => 6.19.



^ permalink raw reply

* Re: [PATCH] wifi: move action code from per-type frame structs
From: Johannes Berg @ 2026-02-25 22:00 UTC (permalink / raw)
  To: Jeff Johnson, linux-wireless
In-Reply-To: <a9caee5b-1698-49ae-bf07-77b417e6ff4d@oss.qualcomm.com>

On Wed, 2026-02-25 at 13:18 -0800, Jeff Johnson wrote:
> On 2/25/2026 9:08 AM, Johannes Berg wrote:
> > 
> > And a couple of other notes:
> > 
> > >  				struct{
> > > -					u8 action_code;
> > > +					u8 no_fixed_fields[0];
> > >  					u8 variable[];
> > >  				} __packed chan_switch;
> > 
> > This thing in a couple of places isn't ideal, but I think it doesn't
> > outweigh the benefits of this structural approach.
> 
> My fear is that "helpful" members of the community will refer to the
> following, believing this is an old style variable array definition:
> 
> https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays

Yeah ... We'll have helpful AIs to tell the "helpful" people off, right?
Right? ;-)

> So I personally feel that a /* no fixed fields */ comment would provide the
> same benefit without bringing unwanted noise (unless the code just doesn't
> build without the member being present).

Ah, but that's exactly the thing, it isn't valid to have structs
completely without members (there's one case without "u8 variable[];"),
nor structs with only a variable member. So indeed it doesn't build
without it.

So ... yeah, not ideal, but I think the structural benefit outweighs the
disadvantage here.

Unless folks disagree with that and think that the action_code really
_should_ be part of the per-action-frame sub-struct? Personally, I think
the code looks better this way, and it has always slightly bothered me,
but I could be convinced otherwise :)

johannes

^ permalink raw reply

* Re: [PATCH] wifi: move action code from per-type frame structs
From: Jeff Johnson @ 2026-02-25 21:18 UTC (permalink / raw)
  To: Johannes Berg, linux-wireless
In-Reply-To: <4957d35e090d54f098d27f937da70770bc001397.camel@sipsolutions.net>

On 2/25/2026 9:08 AM, Johannes Berg wrote:
> 
> And a couple of other notes:
> 
>>  				struct{
>> -					u8 action_code;
>> +					u8 no_fixed_fields[0];
>>  					u8 variable[];
>>  				} __packed chan_switch;
> 
> This thing in a couple of places isn't ideal, but I think it doesn't
> outweigh the benefits of this structural approach.

My fear is that "helpful" members of the community will refer to the
following, believing this is an old style variable array definition:

https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays

So I personally feel that a /* no fixed fields */ comment would provide the
same benefit without bringing unwanted noise (unless the code just doesn't
build without the member being present).

But you're the boss :)

/jeff


^ permalink raw reply

* Re: [PATCH] wifi: wlcore: ensure skb headroom before skb_push
From: Guenter Roeck @ 2026-02-25 20:52 UTC (permalink / raw)
  To: Peter Åstrand; +Cc: linux-wireless
In-Reply-To: <097bd417-e1d7-acd4-be05-47b199075013@lysator.liu.se>

Hi,

On Wed, Dec 03, 2025 at 08:57:08AM +0100, Peter Åstrand wrote:
> 
> This avoids occasional skb_under_panic Oops from wl1271_tx_work. In this case, headroom is
> less than needed (typically 110 - 94 = 16 bytes).
> 
> Signed-off-by: Peter Astrand <astrand@lysator.liu.se>
> ---
>  drivers/net/wireless/ti/wlcore/tx.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
> index f76087be2f75..6241866d39df 100644
> --- a/drivers/net/wireless/ti/wlcore/tx.c
> +++ b/drivers/net/wireless/ti/wlcore/tx.c
> @@ -207,6 +207,11 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
>  	total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks);
>  
>  	if (total_blocks <= wl->tx_blocks_available) {
> +		if (skb_headroom(skb) < (total_len - skb->len) &&
> +		    pskb_expand_head(skb, (total_len - skb->len), 0, GFP_ATOMIC)) {
> +			wl1271_free_tx_id(wl, id);
> +			return -EAGAIN;
> +		}

An experimental AI code review agent provided the following feedback:

 If pskb_expand_head() fails, the code returns -EAGAIN. However, in
 wlcore_tx_work_locked(), a return value of -EAGAIN from
 wl1271_prepare_tx_frame() is interpreted as the aggregation buffer being full.
 This causes the code to flush the buffer, put the skb back at the head of the
 queue, and immediately retry the same skb in a tight while loop.

 Because wlcore_tx_work_locked() holds wl->mutex, and the retry happens
 immediately with GFP_ATOMIC, will this result in an infinite loop and a CPU
 soft lockup? Should this return -ENOMEM instead, so the packet is dropped and
 the loop terminates?

I don't understand the code well enough to understand if the AI agent has a
point or not. Please take a look and let me know if this is a real problem.

Thanks,
Guenter

^ permalink raw reply

* Re: [PATCH ath-next] wifi: ath12k: Fix legacy rate mapping for monitor mode capture
From: Vasanthakumar Thiagarajan @ 2026-02-25 17:16 UTC (permalink / raw)
  To: Thiraviyam Mariyappan, ath12k; +Cc: linux-wireless, P Praneesh
In-Reply-To: <20260209054924.2713072-1-thiraviyam.mariyappan@oss.qualcomm.com>



On 2/9/2026 11:19 AM, Thiraviyam Mariyappan wrote:
> From: P Praneesh <praneesh.p@oss.qualcomm.com>
> 
> The current implementation incorrectly reports legacy CCK and OFDM rates
> in monitor mode radiotap headers. The rate field displays wrong values,
> for example showing 11 Mbps when the actual rate is 1 Mbps. This occurs
> because the HAL layer uses a unified enum for both CCK and OFDM rates
> without distinguishing between long/short preamble variants and proper
> rate mapping to hardware rate indices.
> 
> The root cause is threefold:
> 
> 1. The hal_rx_legacy_rate enum conflates CCK and OFDM rates into a
>     single enumeration, making it impossible to differentiate between
>     802.11b CCK rates (with long/short preamble variants) and 802.11a/g
>     OFDM rates.
> 
> 2. The L-SIG-B parsing function maps hardware rate values to the wrong
>     enum values. For CCK rates, it incorrectly combines long and short
>     preamble cases (e.g., cases 2 and 5 both map to 2 Mbps), losing
>     preamble information critical for proper rate identification.
> 
> 3. The mac layer's rate-to-index conversion function does not properly
>     handle the precedence between long preamble, short preamble, and
>     OFDM rates when matching hardware rate values.
> 
> Split the hal_rx_legacy_rate enum into two separate enumerations:
> hal_rx_legacy_rate for CCK rates with explicit long preamble (LP) and
> short preamble (SP) variants, and hal_rx_legacy_rates_ofdm for OFDM
> rates. This separation allows proper identification of rate types and
> preamble modes.
> 
> Introduce a new mapping ath12k_wifi7_hal_mon_map_legacy_rate_to_hw_rate()
> that converts HAL CCK rate enums to hardware rate indices defined in
> ath12k_hw_rate_cck. This ensures the rate field in ppdu_info contains
> the correct hardware rate index that matches the mac layer's expectations.
> 
> Update the L-SIG-B parsing to map each hardware rate value (1-7) to its
> corresponding CCK rate enum with proper preamble designation:
> - Cases 1-4: Long preamble (1, 2, 5.5, 11 Mbps)
> - Cases 5-7: Short preamble (2, 5.5, 11 Mbps)
> 
> Update the L-SIG-A parsing to use the new OFDM-specific enum values,
> maintaining the existing rate mapping for 802.11a/g OFDM rates.
> 
> Refactor the mac layer's ath12k_mac_hw_rate_to_idx() function to
> implement proper matching precedence:
> 1. First match OFDM rates using the IEEE80211_RATE_MANDATORY_A flag
> 2. Then match CCK short preamble rates
> 3. Finally match CCK long preamble rates as fallback
> 
> Add helper macros ATH12K_MAC_RATE_A_M and ATH12K_MAC_RATE_B to improve
> readability of the rate table initialization and ensure the mandatory
> flag is set for OFDM rates.
> 
> This fix ensures monitor mode captures display accurate rate information
> in the radiotap header, correctly distinguishing between 1 Mbps and
> 11 Mbps, and properly identifying preamble types for CCK rates.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01181-QCAHKSWPL_SILICONZ-1
> 
> Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices")
> Signed-off-by: P Praneesh <praneesh.p@oss.qualcomm.com>
> Signed-off-by: Thiraviyam Mariyappan <thiraviyam.mariyappan@oss.qualcomm.com>

Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>

^ permalink raw reply

* Re: [PATCH] wifi: move action code from per-type frame structs
From: Johannes Berg @ 2026-02-25 17:08 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <20260225175252.03c5c338a7b2.I9a24328e3ffcaae179466a935f1c3345029f9961@changeid>


And a couple of other notes:

>  				struct{
> -					u8 action_code;
> +					u8 no_fixed_fields[0];
>  					u8 variable[];
>  				} __packed chan_switch;

This thing in a couple of places isn't ideal, but I think it doesn't
outweigh the benefits of this structural approach.

> @@ -2665,16 +2645,15 @@ static inline bool ieee80211_is_timing_measurement(struct sk_buff *skb)
>  {
>  	struct ieee80211_mgmt *mgmt = (void *)skb->data;
>  
> -	if (skb->len < IEEE80211_MIN_ACTION_SIZE)
> +	if (skb->len < IEEE80211_MIN_ACTION_SIZE(wnm_timing_msr))
>  		return false;
>  
>  	if (!ieee80211_is_action(mgmt->frame_control))
>  		return false;
>  
>  	if (mgmt->u.action.category == WLAN_CATEGORY_WNM_UNPROTECTED &&
> -	    mgmt->u.action.u.wnm_timing_msr.action_code ==
> -		WLAN_UNPROTECTED_WNM_ACTION_TIMING_MEASUREMENT_RESPONSE &&
> -	    skb->len >= offsetofend(typeof(*mgmt), u.action.u.wnm_timing_msr))
> +	    mgmt->u.action.action_code ==
> +			WLAN_UNPROTECTED_WNM_ACTION_TIMING_MEASUREMENT_RESPONSE)
>  		return true;

This is, unfortunately, a bugfix, as is:

> @@ -2689,15 +2668,13 @@ static inline bool ieee80211_is_ftm(struct sk_buff *skb)
>  {
>  	struct ieee80211_mgmt *mgmt = (void *)skb->data;
>  
> +	if (skb->len < IEEE80211_MIN_ACTION_SIZE(ftm))
> +		return false;
> +
>  	if (!ieee80211_is_public_action((void *)mgmt, skb->len))
>  		return false;
>  
> -	if (mgmt->u.action.u.ftm.action_code ==
> -		WLAN_PUB_ACTION_FTM_RESPONSE &&
> -	    skb->len >= offsetofend(typeof(*mgmt), u.action.u.ftm))
> -		return true;
> 

because the original MIN_ACTION_SIZE didn't include the action_code
field, and thus these were accessing without checking that it exists.

I don't think it's a huge problem that we need to fix separately though
given tailroom and skb shared data etc. will always be there.

johannes

^ permalink raw reply

* Re: [PATCH v3] wifi: ath11k: fix memory leaks in beacon template setup
From: Vasanthakumar Thiagarajan @ 2026-02-25 17:08 UTC (permalink / raw)
  To: Zilin Guan, jeff.johnson
  Cc: ath11k, baochen.qiang, jianhao.xu, jjohnson, linux-kernel,
	linux-wireless
In-Reply-To: <20260130084451.110768-1-zilin@seu.edu.cn>



On 1/30/2026 2:14 PM, Zilin Guan wrote:
> The functions ath11k_mac_setup_bcn_tmpl_ema() and
> ath11k_mac_setup_bcn_tmpl_mbssid() allocate memory for beacon templates
> but fail to free it when parameter setup returns an error.
> 
> Since beacon templates must be released during normal execution, they
> must also be released in the error handling paths to prevent memory
> leaks.
> 
> Fix this by using unified exit paths with proper cleanup in the respective
> error paths.
> 
> Compile tested only. Issue found using a prototype static analysis tool
> and code review.
> 
> Fixes: 3a415daa3e8b ("wifi: ath11k: add P2P IE in beacon template")
> Fixes: 335a92765d30 ("wifi: ath11k: MBSSID beacon support")
> Suggested-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
> Signed-off-by: Zilin Guan <zilin@seu.edu.cn>

Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox