Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH wireless-next 1/2] wifi: mac80211: ibss: read deauth reason_code after frame length check
From: Miri Korenblit @ 2026-07-15 18:27 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Shahar Tzarfati

From: Shahar Tzarfati <shahar.tzarfati@intel.com>

The function was reading reason_code from the frame before validating
that the frame is at least IEEE80211_DEAUTH_FRAME_LEN bytes long.

Move the reason_code read to after the length check so the field is
guaranteed to be present before it is accessed.

Signed-off-by: Shahar Tzarfati <shahar.tzarfati@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 net/mac80211/ibss.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index d0fd6054f182..9915dd5c36df 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -881,11 +881,13 @@ static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata,
 					  struct ieee80211_mgmt *mgmt,
 					  size_t len)
 {
-	u16 reason = le16_to_cpu(mgmt->u.deauth.reason_code);
+	u16 reason;
 
 	if (len < IEEE80211_DEAUTH_FRAME_LEN)
 		return;
 
+	reason = le16_to_cpu(mgmt->u.deauth.reason_code);
+
 	ibss_dbg(sdata, "RX DeAuth SA=%pM DA=%pM\n", mgmt->sa, mgmt->da);
 	ibss_dbg(sdata, "\tBSSID=%pM (reason: %d)\n", mgmt->bssid, reason);
 	sta_info_destroy_addr(sdata, mgmt->sa);
-- 
2.34.1


^ permalink raw reply related

* [PATCH wireless-next 2/2] wifi: mac80211: mlme: read deauth reason_code after frame length check
From: Miri Korenblit @ 2026-07-15 18:27 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Shahar Tzarfati
In-Reply-To: <20260715212706.db26604650bd.I2caa73c396b8c9d357224b9334d5df3cafac498e@changeid>

From: Shahar Tzarfati <shahar.tzarfati@intel.com>

The function was reading reason_code from the frame before validating
that the frame is at least IEEE80211_DEAUTH_FRAME_LEN bytes long.

Move the reason_code read to after the length check so the field is
guaranteed to be present before it is accessed. Also replace the
open-coded 24 + 2 with the named constant IEEE80211_DEAUTH_FRAME_LEN
for clarity.

Signed-off-by: Shahar Tzarfati <shahar.tzarfati@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 net/mac80211/mlme.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9e92337bb6f9..f180fcd477d0 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -5641,13 +5641,15 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
 				     struct ieee80211_mgmt *mgmt, size_t len)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
+	u16 reason_code;
 
 	lockdep_assert_wiphy(sdata->local->hw.wiphy);
 
-	if (len < 24 + 2)
+	if (len < IEEE80211_DEAUTH_FRAME_LEN)
 		return;
 
+	reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
+
 	if (!ether_addr_equal(mgmt->bssid, mgmt->sa)) {
 		ieee80211_tdls_handle_disconnect(sdata, mgmt->sa, reason_code);
 		return;
-- 
2.34.1


^ permalink raw reply related

* [PATCH wireless-next] wifi: cfg80211: clarify and tighten key checks
From: Miri Korenblit @ 2026-07-15 18:24 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

Currently, we accept per-STA GTK for any interface type
if the IBSS_RSN flag is set, which doesn't make sense,
and also accept various key indices that aren't really
(meant to be) supported, such as IGTK/BIGTK on IBSS or
AP_VLAN etc.

For MESH and NAN_DATA interface types, per-STA GTKs are
required, so their support shouldn't depend on IBSS_RSN.

Conversely a driver setting IBSS_RSN doesn't really say
it also accepts per-STA GTK for other interface types.

Move more checks into cfg80211_valid_key_idx() and make
them more precise:
 - allow IGTK and, if supported, BIGTK for NAN
 - allow per-STA (RX) GTK only for
   - NAN_DATA
   - IBSS if IBSS_RSN is supported
   - MESH
 - allow B/I/GTK for station/P2P-client without mac_addr
   for RX with the current AP (historic API quirk),
   subject to support
 - allow TX GTK for AP/P2P-GO/AP_VLAN
 - allow TX IGTK/BIGTK for AP/P2P-GO subject to support

Other settings are rejected, clearing up corner cases
and disallowing unexpected settings.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 net/wireless/core.h        |   5 +-
 net/wireless/nl80211.c     |  11 ++--
 net/wireless/util.c        | 105 +++++++++++++++++++++++++++----------
 net/wireless/wext-compat.c |   3 +-
 4 files changed, 86 insertions(+), 38 deletions(-)

diff --git a/net/wireless/core.h b/net/wireless/core.h
index df47ed6208a5..399037514943 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -443,8 +443,9 @@ void cfg80211_sme_abandon_assoc(struct wireless_dev *wdev);
 
 /* internal helpers */
 bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher);
-bool cfg80211_valid_key_idx(struct cfg80211_registered_device *rdev,
-			    int key_idx, bool pairwise);
+bool cfg80211_valid_key_idx(struct wireless_dev *wdev,
+			    int key_idx, bool pairwise,
+			    const u8 *mac_addr);
 int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
 				   struct wireless_dev *wdev,
 				   struct key_params *params, int key_idx,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 242071ad10d6..99a1c0174bdb 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5409,7 +5409,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
 	if (!rdev->ops->get_key)
 		return -EOPNOTSUPP;
 
-	if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
+	if (!cfg80211_valid_key_idx(wdev, key_idx, pairwise, mac_addr))
 		return -ENOENT;
 
 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
@@ -5663,8 +5663,9 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
 	    key.type != NL80211_KEYTYPE_GROUP)
 		return -EINVAL;
 
-	if (!cfg80211_valid_key_idx(rdev, key.idx,
-				    key.type == NL80211_KEYTYPE_PAIRWISE))
+	if (!cfg80211_valid_key_idx(wdev, key.idx,
+				    key.type == NL80211_KEYTYPE_PAIRWISE,
+				    mac_addr))
 		return -EINVAL;
 
 	if (!rdev->ops->del_key)
@@ -5672,10 +5673,6 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
 
 	err = nl80211_key_allowed(wdev);
 
-	if (key.type == NL80211_KEYTYPE_GROUP && mac_addr &&
-	    !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
-		err = -ENOENT;
-
 	if (!err)
 		err = nl80211_validate_key_link_id(info, wdev, link_id,
 				key.type == NL80211_KEYTYPE_PAIRWISE);
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 24527bf321b2..3e584d0ca3e2 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -241,10 +241,8 @@ bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher)
 	return false;
 }
 
-static bool
-cfg80211_igtk_cipher_supported(struct cfg80211_registered_device *rdev)
+static bool cfg80211_igtk_cipher_supported(struct wiphy *wiphy)
 {
-	struct wiphy *wiphy = &rdev->wiphy;
 	int i;
 
 	for (i = 0; i < wiphy->n_cipher_suites; i++) {
@@ -260,27 +258,86 @@ cfg80211_igtk_cipher_supported(struct cfg80211_registered_device *rdev)
 	return false;
 }
 
-bool cfg80211_valid_key_idx(struct cfg80211_registered_device *rdev,
-			    int key_idx, bool pairwise)
+bool cfg80211_valid_key_idx(struct wireless_dev *wdev,
+			    int key_idx, bool pairwise,
+			    const u8 *mac_addr)
 {
-	int max_key_idx;
-
-	if (pairwise)
-		max_key_idx = 3;
-	else if (wiphy_ext_feature_isset(&rdev->wiphy,
-					 NL80211_EXT_FEATURE_BEACON_PROTECTION) ||
-		 wiphy_ext_feature_isset(&rdev->wiphy,
-					 NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))
-		max_key_idx = 7;
-	else if (cfg80211_igtk_cipher_supported(rdev))
-		max_key_idx = 5;
-	else
-		max_key_idx = 3;
+	if (WARN_ON(!wdev))
+		return false;
 
-	if (key_idx < 0 || key_idx > max_key_idx)
+	if (key_idx < 0)
 		return false;
 
-	return true;
+	/*
+	 * Can't differentiate ciphers here so allow 0..3.
+	 * Pairwise keys must be for a station (MAC address given).
+	 */
+	if (pairwise) {
+		if (!mac_addr)
+			return false;
+
+		return key_idx < 4;
+	}
+
+	/*
+	 * For group keys, mac_addr==NULL means setting a group key
+	 * for TX, which is only supported on some interface types,
+	 * except for STATION/P2P_CLIENT, where it's setting the RX
+	 * key with the current AP (for legacy reasons.)
+	 *
+	 * Apart from that exception, a non-NULL mac_addr means RX
+	 * key being set.
+	 */
+
+	switch (wdev->iftype) {
+	case NL80211_IFTYPE_ADHOC:
+		if (!(wdev->wiphy->flags & WIPHY_FLAG_IBSS_RSN))
+			return false;
+		fallthrough;
+	case NL80211_IFTYPE_MESH_POINT:
+		/* no support for IGTK/BIGTK (yet?) */
+		return key_idx < 4;
+	case NL80211_IFTYPE_NAN_DATA:
+		/* these always need to support per-STA GTK */
+		return key_idx < 4;
+	case NL80211_IFTYPE_NAN:
+		/* no data */
+		if (key_idx < 4)
+			return false;
+		/* NAN reused this flag */
+		if (wiphy_ext_feature_isset(wdev->wiphy,
+					    NL80211_EXT_FEATURE_BEACON_PROTECTION))
+			return key_idx <= 7;
+		return key_idx <= 5;
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_P2P_CLIENT:
+		/* see note about exception above */
+		if (mac_addr)
+			return false;
+		/* BIGTK support implies IGTK support */
+		if (wiphy_ext_feature_isset(wdev->wiphy,
+					    NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))
+			return key_idx <= 7;
+		fallthrough;
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_P2P_GO:
+		/* no RX with [B]IGTK */
+		if (mac_addr)
+			return false;
+		if (wiphy_ext_feature_isset(wdev->wiphy,
+					    NL80211_EXT_FEATURE_BEACON_PROTECTION))
+			return key_idx <= 7;
+		fallthrough;
+	case NL80211_IFTYPE_AP_VLAN:
+		/* no RX with GTK */
+		if (mac_addr)
+			return false;
+		if (cfg80211_igtk_cipher_supported(wdev->wiphy))
+			return key_idx <= 5;
+		return key_idx <= 3;
+	default:
+		return false;
+	}
 }
 
 int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
@@ -288,13 +345,7 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
 				   struct key_params *params, int key_idx,
 				   bool pairwise, const u8 *mac_addr)
 {
-	if (!cfg80211_valid_key_idx(rdev, key_idx, pairwise))
-		return -EINVAL;
-
-	if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
-		return -EINVAL;
-
-	if (pairwise && !mac_addr)
+	if (!cfg80211_valid_key_idx(wdev, key_idx, pairwise, mac_addr))
 		return -EINVAL;
 
 	switch (params->cipher) {
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 5dbf3ef4b257..d45bc08c0de4 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -454,8 +454,7 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
 				rejoin = true;
 			}
 
-			if (!pairwise && addr &&
-			    !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
+			if (!cfg80211_valid_key_idx(wdev, idx, pairwise, addr))
 				err = -ENOENT;
 			else
 				err = rdev_del_key(rdev, wdev, -1, idx, pairwise,
-- 
2.34.1


^ permalink raw reply related

* [PATCH wireless-next] wifi: cfg80211: improve multi-BSSID profile continuation parser
From: Miri Korenblit @ 2026-07-15 18:11 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

The previous change from John Walker fixed the loop iteration,
but the code is written in a bad way. Pass the pointers needed
for the iteration to the function instead.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 net/wireless/scan.c | 49 +++++++++++++++++++++------------------------
 1 file changed, 23 insertions(+), 26 deletions(-)

diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 05b7dc6b766c..e62b7dd2b7c2 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -2403,12 +2403,11 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
 	return NULL;
 }
 
-static const struct element
-*cfg80211_get_profile_continuation(const u8 *ie, size_t ielen,
-				   const struct element *mbssid_elem,
-				   const struct element *sub_elem)
+static bool cfg80211_iter_profile_continuation(const u8 *ie, size_t ielen,
+					       const struct element **mbssid,
+					       const struct element **sub_elem)
 {
-	const u8 *mbssid_end = mbssid_elem->data + mbssid_elem->datalen;
+	const u8 *mbssid_end = (*mbssid)->data + (*mbssid)->datalen;
 	const struct element *next_mbssid;
 	const struct element *next_sub;
 
@@ -2420,30 +2419,34 @@ static const struct element
 	 * If it is not the last subelement in current MBSSID IE or there isn't
 	 * a next MBSSID IE - profile is complete.
 	*/
-	if ((sub_elem->data + sub_elem->datalen < mbssid_end - 1) ||
+	if (((*sub_elem)->data + (*sub_elem)->datalen < mbssid_end - 1) ||
 	    !next_mbssid)
-		return NULL;
+		return false;
 
-	/* For any length error, just return NULL */
+	/* For any length error, just return false to stop iteration */
 
 	if (next_mbssid->datalen < 4)
-		return NULL;
+		return false;
 
 	next_sub = (void *)&next_mbssid->data[1];
 
 	if (next_mbssid->data + next_mbssid->datalen <
 	    next_sub->data + next_sub->datalen)
-		return NULL;
+		return false;
 
 	if (next_sub->id != 0 || next_sub->datalen < 2)
-		return NULL;
+		return false;
 
 	/*
 	 * Check if the first element in the next sub element is a start
 	 * of a new profile
 	 */
-	return next_sub->data[0] == WLAN_EID_NON_TX_BSSID_CAP ?
-	       NULL : next_mbssid;
+	if (next_sub->data[0] == WLAN_EID_NON_TX_BSSID_CAP)
+		return false;
+
+	*mbssid = next_mbssid;
+	*sub_elem = next_sub;
+	return true;
 }
 
 size_t cfg80211_merge_profile(const u8 *ie, size_t ielen,
@@ -2452,26 +2455,20 @@ size_t cfg80211_merge_profile(const u8 *ie, size_t ielen,
 			      u8 *merged_ie, size_t max_copy_len)
 {
 	size_t copied_len = sub_elem->datalen;
-	const struct element *next_mbssid;
 
 	if (sub_elem->datalen > max_copy_len)
 		return 0;
 
 	memcpy(merged_ie, sub_elem->data, sub_elem->datalen);
 
-	while ((next_mbssid = cfg80211_get_profile_continuation(ie, ielen,
-								mbssid_elem,
-								sub_elem))) {
-		const struct element *next_sub = (void *)&next_mbssid->data[1];
-
-		if (copied_len + next_sub->datalen > max_copy_len)
+	while (cfg80211_iter_profile_continuation(ie, ielen,
+						  &mbssid_elem,
+						  &sub_elem)) {
+		if (copied_len + sub_elem->datalen > max_copy_len)
 			break;
-		memcpy(merged_ie + copied_len, next_sub->data,
-		       next_sub->datalen);
-		copied_len += next_sub->datalen;
-
-		mbssid_elem = next_mbssid;
-		sub_elem = next_sub;
+		memcpy(merged_ie + copied_len, sub_elem->data,
+		       sub_elem->datalen);
+		copied_len += sub_elem->datalen;
 	}
 
 	return copied_len;
-- 
2.34.1


^ permalink raw reply related

* [PATCH wireless-next] wifi: use UHR operation field presence bits
From: Miri Korenblit @ 2026-07-15 18:08 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

The spec originally had the idea that the fact that it's
a beacon frame determines the (non-)presence of the values,
but added presence bits in D1.4. Use those presence bits in
addition to the enable bits.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 include/linux/ieee80211-uhr.h | 44 +++++++++++++++++------------------
 net/mac80211/mlme.c           |  3 +--
 net/mac80211/parse.c          |  4 +---
 net/wireless/nl80211.c        |  2 +-
 4 files changed, 25 insertions(+), 28 deletions(-)

diff --git a/include/linux/ieee80211-uhr.h b/include/linux/ieee80211-uhr.h
index 597c9e559261..665d4b3a5b41 100644
--- a/include/linux/ieee80211-uhr.h
+++ b/include/linux/ieee80211-uhr.h
@@ -17,6 +17,11 @@
 #define IEEE80211_UHR_OPER_PARAMS_PEDCA_ENA		0x0004
 #define IEEE80211_UHR_OPER_PARAMS_DBE_ENA		0x0008
 #define IEEE80211_UHR_OPER_PARAMS_DBE_BW		0x0070
+#define IEEE80211_UHR_OPER_PARAMS_DUO_PRES		0x0080
+#define IEEE80211_UHR_OPER_PARAMS_DPS_PRES		0x0100
+#define IEEE80211_UHR_OPER_PARAMS_NPCA_PRES		0x0200
+#define IEEE80211_UHR_OPER_PARAMS_PEDCA_PRES		0x0400
+#define IEEE80211_UHR_OPER_PARAMS_DBE_PRES		0x0800
 
 struct ieee80211_uhr_operation {
 	__le16 params;
@@ -265,8 +270,7 @@ struct ieee80211_uhr_p_edca_info {
 	__le16 params;
 } __packed;
 
-static inline bool ieee80211_uhr_oper_size_ok(const u8 *data, u8 len,
-					      bool beacon)
+static inline bool ieee80211_uhr_oper_size_ok(const u8 *data, u8 len)
 {
 	const struct ieee80211_uhr_operation *oper = (const void *)data;
 	u8 needed = sizeof(*oper);
@@ -274,19 +278,15 @@ static inline bool ieee80211_uhr_oper_size_ok(const u8 *data, u8 len,
 	if (len < needed)
 		return false;
 
-	/* nothing else present in beacons */
-	if (beacon)
-		return true;
-
 	/* DPS Operation Parameters (fixed 4 bytes) */
-	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DPS_ENA)) {
+	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DPS_PRES)) {
 		needed += sizeof(struct ieee80211_uhr_dps_info);
 		if (len < needed)
 			return false;
 	}
 
 	/* NPCA Operation Parameters (fixed 4 bytes + optional 2 bytes) */
-	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_NPCA_ENA)) {
+	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_NPCA_PRES)) {
 		const struct ieee80211_uhr_npca_info *npca =
 			(const void *)(data + needed);
 
@@ -303,14 +303,14 @@ static inline bool ieee80211_uhr_oper_size_ok(const u8 *data, u8 len,
 	}
 
 	/* P-EDCA Operation Parameters (fixed 3 bytes) */
-	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_PEDCA_ENA)) {
+	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_PEDCA_PRES)) {
 		needed += sizeof(struct ieee80211_uhr_p_edca_info);
 		if (len < needed)
 			return false;
 	}
 
 	/* DBE Operation Parameters (fixed 1 byte + optional 2 bytes) */
-	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DBE_ENA)) {
+	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DBE_PRES)) {
 		const struct ieee80211_uhr_dbe_info *dbe =
 			(const void *)(data + needed);
 
@@ -329,19 +329,19 @@ static inline bool ieee80211_uhr_oper_size_ok(const u8 *data, u8 len,
 	return len >= needed;
 }
 
-/*
- * Note: cannot call this on the element coming from a beacon,
- * must ensure ieee80211_uhr_oper_size_ok(..., false) first
- */
+/* Note: must ensure ieee80211_uhr_oper_size_ok(...) first */
 static inline const struct ieee80211_uhr_npca_info *
 ieee80211_uhr_npca_info(const struct ieee80211_uhr_operation *oper)
 {
 	const u8 *pos = oper->variable;
 
+	if (!(oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_NPCA_PRES)))
+		return NULL;
+
 	if (!(oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_NPCA_ENA)))
 		return NULL;
 
-	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DPS_ENA))
+	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DPS_PRES))
 		pos += sizeof(struct ieee80211_uhr_dps_info);
 
 	return (const void *)pos;
@@ -360,22 +360,22 @@ ieee80211_uhr_npca_dis_subch_bitmap(const struct ieee80211_uhr_operation *oper)
 	return npca->dis_subch_bmap;
 }
 
-/*
- * Note: cannot call this on the element coming from a beacon,
- * must ensure ieee80211_uhr_oper_size_ok(..., false) first
- */
+/* Note: must ensure ieee80211_uhr_oper_size_ok(...) first */
 static inline const struct ieee80211_uhr_dbe_info *
 ieee80211_uhr_oper_dbe_info(const struct ieee80211_uhr_operation *oper)
 {
 	const u8 *pos = oper->variable;
 
+	if (!(oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DBE_PRES)))
+		return NULL;
+
 	if (!(oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DBE_ENA)))
 		return NULL;
 
-	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DPS_ENA))
+	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DPS_PRES))
 		pos += sizeof(struct ieee80211_uhr_dps_info);
 
-	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_NPCA_ENA)) {
+	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_NPCA_PRES)) {
 		const struct ieee80211_uhr_npca_info *npca = (const void *)pos;
 
 		pos += sizeof(*npca);
@@ -383,7 +383,7 @@ ieee80211_uhr_oper_dbe_info(const struct ieee80211_uhr_operation *oper)
 			pos += sizeof(npca->dis_subch_bmap[0]);
 	}
 
-	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_PEDCA_ENA))
+	if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_PEDCA_PRES))
 		pos += sizeof(struct ieee80211_uhr_p_edca_info);
 
 	return (const void *)pos;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9e92337bb6f9..4ad5e9497323 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1701,8 +1701,7 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link,
 	if (stype != IEEE80211_STYPE_BEACON &&
 	    chanreq.oper.npca_chan && elems->uhr_operation &&
 	    ieee80211_uhr_oper_size_ok((const void *)elems->uhr_operation,
-				       elems->uhr_operation_len,
-				       false)) {
+				       elems->uhr_operation_len)) {
 		const struct ieee80211_uhr_npca_info *npca;
 		struct ieee80211_bss_npca_params params = {};
 
diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c
index c2f2f78f2b4f..cb2be167cde7 100644
--- a/net/mac80211/parse.c
+++ b/net/mac80211/parse.c
@@ -209,9 +209,7 @@ ieee80211_parse_extension_element(u32 *crc,
 		if (params->mode < IEEE80211_CONN_MODE_UHR)
 			break;
 		calc_crc = true;
-		if (ieee80211_uhr_oper_size_ok(data, len,
-					       params->type == (IEEE80211_FTYPE_MGMT |
-								IEEE80211_STYPE_BEACON))) {
+		if (ieee80211_uhr_oper_size_ok(data, len)) {
 			elems->uhr_operation = data;
 			elems->uhr_operation_len = len;
 		}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 242071ad10d6..5fa70974d57c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -441,7 +441,7 @@ static int validate_uhr_operation(const struct nlattr *attr,
 	const u8 *data = nla_data(attr);
 	unsigned int len = nla_len(attr);
 
-	if (!ieee80211_uhr_oper_size_ok(data, len, false))
+	if (!ieee80211_uhr_oper_size_ok(data, len))
 		return -EINVAL;
 	return 0;
 }
-- 
2.34.1


^ permalink raw reply related

* [PATCH wireless-next] wifi: mac80211: always send regulatory connectivity element
From: Miri Korenblit @ 2026-07-15 18:03 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

The spec says to include it if the STA is "capable of operating
as STA 6G", which is a bit unclear because this is defined at a
STA level and not at the MLD level or so, but WFA requires this
to be included. Either way, the element is completely advisory
and intended mostly for debugging (and perhaps a bit steering),
so just include it in association request all the time if 6 GHz
is supported.

To determine what exactly to include, check all the channels
that aren't disabled. That way, it ends up being a lowest
common denominator, which is most useful for steering etc.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 net/mac80211/ieee80211_i.h |  4 ++--
 net/mac80211/mlme.c        | 13 ++++++-------
 net/mac80211/util.c        | 24 +++++++++++++++++++++---
 3 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index d585820245dd..11f449e8ff00 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2771,8 +2771,8 @@ int ieee80211_put_eht_cap(struct sk_buff *skb,
 int ieee80211_put_uhr_cap(struct sk_buff *skb,
 			  struct ieee80211_sub_if_data *sdata,
 			  const struct ieee80211_supported_band *sband);
-int ieee80211_put_reg_conn(struct sk_buff *skb,
-			   enum ieee80211_channel_flags flags);
+void ieee80211_put_reg_conn(struct ieee80211_sub_if_data *sdata,
+			    struct sk_buff *skb);
 
 /* channel management */
 bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9e92337bb6f9..1afdb610dff2 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2307,13 +2307,14 @@ ieee80211_add_link_elems(struct ieee80211_sub_if_data *sdata,
 	offset = ieee80211_add_before_reg_conn(skb, extra_elems,
 					       extra_elems_len, offset);
 
-	if (sband->band == NL80211_BAND_6GHZ) {
+	/* only add this on the assoc link, not in per-STA profiles */
+	if (link) {
 		/*
 		 * as per Section E.2.7 of IEEE 802.11 REVme D7.0, non-AP STA
 		 * capable of operating on the 6 GHz band shall transmit
 		 * regulatory connectivity element.
 		 */
-		ieee80211_put_reg_conn(skb, chan->flags);
+		ieee80211_put_reg_conn(sdata, skb);
 	}
 
 	/*
@@ -2564,11 +2565,8 @@ ieee80211_link_common_elems_size(struct ieee80211_sub_if_data *sdata,
 		sizeof(struct ieee80211_he_mcs_nss_supp) +
 		IEEE80211_HE_PPE_THRES_MAX_LEN;
 
-	if (sband->band == NL80211_BAND_6GHZ) {
+	if (sband->band == NL80211_BAND_6GHZ)
 		size += 2 + 1 + sizeof(struct ieee80211_he_6ghz_capa);
-		/* reg connection */
-		size += 4;
-	}
 
 	size += 2 + 1 + sizeof(struct ieee80211_eht_cap_elem) +
 		sizeof(struct ieee80211_eht_mcs_nss_supp) +
@@ -2615,7 +2613,8 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 	       2 + assoc_data->ssid_len + /* SSID */
 	       assoc_data->ie_len + /* extra IEs */
 	       (assoc_data->fils_kek_len ? 16 /* AES-SIV */ : 0) +
-	       9; /* WMM */
+	       9 /* WMM */ +
+	       4 /* regulatory connectivity, if 6 GHz is supported */;
 
 	for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
 		struct cfg80211_bss *cbss = assoc_data->link[link_id].bss;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index f6d4ae4127c8..34f500deb2c8 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2703,12 +2703,31 @@ int ieee80211_put_he_cap(struct sk_buff *skb,
 	return 0;
 }
 
-int ieee80211_put_reg_conn(struct sk_buff *skb,
-			   enum ieee80211_channel_flags flags)
+void ieee80211_put_reg_conn(struct ieee80211_sub_if_data *sdata,
+			    struct sk_buff *skb)
 {
+	struct ieee80211_local *local = sdata->local;
 	u8 reg_conn = IEEE80211_REG_CONN_LPI_VALID |
 		      IEEE80211_REG_CONN_LPI_VALUE |
 		      IEEE80211_REG_CONN_SP_VALID;
+	struct ieee80211_supported_band *sband;
+	bool available_channels = false;
+	u32 flags = 0;
+	int i;
+
+	sband = local->hw.wiphy->bands[NL80211_BAND_6GHZ];
+	if (!sband)
+		return;
+
+	for (i = 0; i < sband->n_channels; i++) {
+		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
+			continue;
+		flags |= sband->channels[i].flags;
+		available_channels = true;
+	}
+
+	if (!available_channels)
+		return;
 
 	if (!(flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT))
 		reg_conn |= IEEE80211_REG_CONN_SP_VALUE;
@@ -2717,7 +2736,6 @@ int ieee80211_put_reg_conn(struct sk_buff *skb,
 	skb_put_u8(skb, 1 + sizeof(reg_conn));
 	skb_put_u8(skb, WLAN_EID_EXT_NON_AP_STA_REG_CON);
 	skb_put_u8(skb, reg_conn);
-	return 0;
 }
 
 int ieee80211_put_he_6ghz_cap(struct sk_buff *skb,
-- 
2.34.1


^ permalink raw reply related

* RE: kernel BUG at mm/slub.c:634 (kfree) when unbinding device from iwlwifi
From: Korenblit, Miriam Rachel @ 2026-07-15 17:22 UTC (permalink / raw)
  To: Marek Marczykowski-Górecki
  Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <aleaCWlvrmiUcLhT@mail-itl>

[-- Attachment #1: Type: text/plain, Size: 8523 bytes --]



> -----Original Message-----
> From: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
> Sent: Wednesday, July 15, 2026 5:33 PM
> To: Korenblit, Miriam Rachel <miriam.rachel.korenblit@intel.com>
> Cc: linux-wireless@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: kernel BUG at mm/slub.c:634 (kfree) when unbinding device from iwlwifi
> 
> Hello,
> 
> I get a kernel panic when unbinding device (8086:0085) from the iwlwifi driver
> (via writing to the "unbind" file in sysfs), while the wifi connection is active. I can
> reproduce it on Thinkpad X230, but other devices might be affected too. The
> specific crash is:
> 
>     [  286.908182] kernel BUG at mm/slub.c:634!
>     [  286.908201] Oops: invalid opcode: 0000 [#1] SMP PTI
>     [  286.908221] CPU: 1 UID: 0 PID: 1959 Comm: prepare-suspend Not tainted
> 6.18.15-1.qubes.fc41.x86_64 #1 PREEMPT(full)
>     [  286.908255] Hardware name: Xen HVM domU, BIOS 4.19.4 03/17/2026
>     [  286.908275] RIP: 0010:kfree+0x3a8/0x470
>     [  286.908292] Code: 5d 41 5e 41 5f 5d e9 67 bb ff ff 4d 89 f1 41 b8 01 00 00 00
> 48 89 d9 48 89 da 4c 89 ee 4c 89 e7 e8 ad 2c 00 00 e9 bd fd ff ff <0f> 0b 89 c8 4c
> 8d 04 03 40 f6 c6 80 0f 84 41 ff ff ff 83 e6 08 0f
>     [  286.908347] RSP: 0018:ffffcfce8280bb50 EFLAGS: 00010246
>     [  286.908365] RAX: ffff8b2dcef2c800 RBX: ffff8b2dcef2c800 RCX:
> ffff8b2dcef2c830
>     [  286.908389] RDX: 00000000000be001 RSI: 0000000000000000 RDI:
> ffff8b2dcef2c880
>     [  286.908414] RBP: ffffcfce8280bba0 R08: ffff8b2dcef2c860 R09:
> 0000000000000000
>     [  286.908438] R10: ffff8b2dcef2c860 R11: 0000000000000000 R12:
> ffff8b2dd2841600
>     [  286.908462] R13: fffff077003bcb00 R14: ffffffffc093c480 R15:
> 0000000000000060
>     [  286.908487] FS:  00007b10286cd740(0000) GS:ffff8b2e19c6c000(0000)
> knlGS:0000000000000000
>     [  286.908511] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>     [  286.908532] CR2: 00007fb93027bc70 CR3: 00000000034f0005 CR4:
> 00000000001706f0
>     [  286.908559] Call Trace:
>     [  286.908570]  <TASK>
>     [  286.908581]  ? _raw_spin_unlock_bh+0xe/0x20
>     [  286.908599]  iwl_pcie_txq_free+0x130/0x170 [iwlwifi]
>     [  286.908644]  iwl_pcie_tx_free+0x66/0xe0 [iwlwifi]
>     [  286.908681]  iwl_trans_pcie_free+0x1df/0x250 [iwlwifi]
>     [  286.908719]  pci_device_remove+0x42/0xb0
>     [  286.908736]  device_release_driver_internal+0x19c/0x200
>     [  286.908755]  unbind_store+0xa1/0xb0
>     [  286.908771]  kernfs_fop_write_iter+0x150/0x200
>     [  286.908790]  vfs_write+0x25d/0x450
>     [  286.908806]  ksys_write+0x6b/0xe0
>     [  286.908825]  do_syscall_64+0x84/0x800
>     [  286.908842]  ? syscall_exit_work+0x108/0x140
>     [  286.908861]  ? do_syscall_64+0xbb/0x800
>     [  286.908876]  ? ksys_dup3+0x63/0xf0
>     [  286.908892]  ? syscall_exit_work+0x108/0x140
>     [  286.911388]  ? do_syscall_64+0xbb/0x800
>     [  286.911408]  ? do_sys_openat2+0xa4/0xe0
>     [  286.911423]  ? syscall_exit_work+0x108/0x140
>     [  286.911443]  ? do_syscall_64+0xbb/0x800
>     [  286.911458]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
>     [  286.911477] RIP: 0033:0x7b102873ec5e
>     [  286.911493] Code: 4d 89 d8 e8 34 bd 00 00 4c 8b 5d f8 41 8b 93 08 03 00 00
> 59 5e 48 83 f8 fc 74 11 c9 c3 0f 1f 80 00 00 00 00 48 8b 45 10 0f 05 <c9> c3 83 e2
> 39 83 fa 08 75 e7 e8 13 ff ff ff 0f 1f 00 f3 0f 1e fa
>     [  286.911549] RSP: 002b:00007ffd94bc3100 EFLAGS: 00000202 ORIG_RAX:
> 0000000000000001
>     [  286.911575] RAX: ffffffffffffffda RBX: 00007b10288ba5c0 RCX:
> 00007b102873ec5e
>     [  286.911600] RDX: 000000000000000d RSI: 00006385db4f8020 RDI:
> 0000000000000001
>     [  286.911625] RBP: 00007ffd94bc3110 R08: 0000000000000000 R09:
> 0000000000000000
>     [  286.911650] R10: 0000000000000000 R11: 0000000000000202 R12:
> 000000000000000d
>     [  286.911674] R13: 000000000000000d R14: 00006385db4f8020 R15:
> 00006385db4f5b30
>     [  286.911701]  </TASK>
>     [  286.911711] Modules linked in: iwldvm iwlwifi mac80211 ehci_pci ehci_hcd
> nft_nat nft_flow_offload nf_flow_table_inet nf_flow_table qrtr
> nf_conntrack_netlink nft_reject_ipv6 nf_reject_ipv6 nft_reject_ipv4
> nf_reject_ipv4 nft_reject nft_ct nft_masq nft_chain_nat nf_nat nf_conntrack
> nf_defrag_ipv6 nf_defrag_ipv4 nf_tables joydev libarc4 intel_rapl_msr
> intel_rapl_common polyval_clmulni ghash_clmulni_intel cfg80211 e1000e
> ata_generic rfkill i2c_piix4 pata_acpi i2c_smbus pcspkr floppy vfat fat serio_raw
> xen_scsiback target_core_mod xen_netback xen_privcmd xen_gntdev
> xen_gntalloc xen_blkback xen_evtchn i2c_dev fuse loop nfnetlink overlay
> xen_blkfront [last unloaded: iwlwifi]
>     [  286.911967] ---[ end trace 0000000000000000 ]---
> 
> This is running in a VM (HVM) under Xen, with relevant PCI device attached, but I
> don't think it's relevant for this bug.
> 
> I've got reports about the issue in Linux 6.18.15 initially (after updating from
> 6.12), but later tests identified it's a regression somewhere between 6.15.11 and
> 6.16.8.

Hi, could you please test the attached patch? 
It is based on 6.18

> 
> The crash still happen on 7.0.14, although it looks different there:
> 
>     [  106.379541] ------------[ cut here ]------------
>     [  106.379572] kernel BUG at mm/slub.c:542!
>     [  106.379596] Oops: invalid opcode: 0000 [#1] SMP PTI
>     [  106.379618] CPU: 1 UID: 0 PID: 240 Comm: kworker/1:2 Not tainted 7.0.14-
> 1.qubes.fc41.x86_64 #1 PREEMPT(full)
>     [  106.379656] Hardware name: Xen HVM domU, BIOS 4.19.4 06/09/2026
>     [  106.379680] Workqueue: slub_flushwq flush_cpu_sheaves
>     [  106.379711] RIP: 0010:build_detached_freelist+0x1d0/0x210
>     [  106.379733] Code: 41 5c 41 5d c3 cc cc cc cc 31 d2 4d 85 c0 0f 85 b2 fe ff ff
> 48 89 04 24 e8 7d fd ff ff 48 c7 03 00 00 00 00 48 8b 04 24 eb d0 <0f> 0b 48 85 d2
> 74 e3 48 89 13 4c 8b 42 08 e9 8c fe ff ff 0f 0b 31
>     [  106.379795] RSP: 0000:ffffcebd804c3c88 EFLAGS: 00010246
>     [  106.379815] RAX: 000000000000001d RBX: ffffcebd804c3cb8 RCX:
> ffff8e6240fcf000
>     [  106.379843] RDX: ffff8e6240fcf000 RSI: 000000000000001d RDI:
> 0000000000000003
>     [  106.379870] RBP: ffffffff80000000 R08: 0000000080000000 R09:
> ffff8e6240fcf030
>     [  106.379898] R10: ffffcebd804c3d10 R11: 0000000000000000 R12:
> ffff8e6242a68b00
>     [  106.379925] R13: ffff8e6242a68aff R14: 000000000000001c R15:
> 0000000000000000
>     [  106.379953] FS:  0000000000000000(0000) GS:ffff8e62a837a000(0000)
> knlGS:0000000000000000
>     [  106.379981] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>     [  106.380004] CR2: 0000767e599f2fd0 CR3: 000000000c1d2001 CR4:
> 00000000001706f0
>     [  106.380035] Call Trace:
>     [  106.380047]  <TASK>
>     [  106.380060]  __kmem_cache_free_bulk.part.0+0x60/0xe0
>     [  106.380085]  __sheaf_flush_main_batch+0xa1/0xe0
>     [  106.380110]  flush_cpu_sheaves+0xc3/0xe0
>     [  106.380129]  process_one_work+0x198/0x390
>     [  106.380149]  worker_thread+0x1af/0x320
>     [  106.380168]  ? __pfx_worker_thread+0x10/0x10
>     [  106.380190]  kthread+0xe3/0x120
>     [  106.380207]  ? __pfx_kthread+0x10/0x10
>     [  106.380223]  ret_from_fork+0x19e/0x260
>     [  106.380241]  ? __pfx_kthread+0x10/0x10
>     [  106.380257]  ret_from_fork_asm+0x1a/0x30
>     [  106.380276]  </TASK>
>     [  106.380287] Modules linked in: nft_nat nft_flow_offload nf_flow_table_inet
> nf_flow_table nf_conntrack_netlink nft_reject_ipv6 nf_reject_ipv6 qrtr
> nft_reject_ipv4 nf_reject_ipv4 nft_reject nft_ct nft_masq nft_chain_nat nf_nat
> nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables vfat fat intel_rapl_msr
> iwldvm intel_rapl_common ghash_clmulni_intel mac80211 libarc4 iwlwifi joydev
> cfg80211 ehci_pci pcspkr e1000e ehci_hcd rfkill floppy ata_generic i2c_piix4
> pata_acpi i2c_smbus serio_raw xen_scsiback target_core_mod xen_netback
> xen_privcmd xen_gntdev xen_gntalloc xen_blkback xen_evtchn i2c_dev loop fuse
> nfnetlink zram lz4hc_compress lz4_compress overlay xen_blkfront
>     [  106.381851] ---[ end trace 0000000000000000 ]---
> 
> This one doesn't have obvious relation to iwlwifi, but I suspect it's at least related.
> 
> There are some more call traces at
> https://github.com/QubesOS/qubes-issues/issues/10845 but they look pretty
> similar.
> 
> --
> Best Regards,
> Marek Marczykowski-Górecki
> Invisible Things Lab

[-- Attachment #2: 0001-wifi-iwlwifi-trans-don-t-memset-trans-conf-when-it-i.patch --]
[-- Type: application/octet-stream, Size: 2148 bytes --]

From 519b527a9b83fd072e74611176b08170709e4001 Mon Sep 17 00:00:00 2001
From: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Date: Wed, 15 Jul 2026 20:19:33 +0300
Subject: [PATCH] wifi: iwlwifi: trans: don't memset trans::conf when it is
 still needed
Organization: Intel Israel (74) Limited

Currently, trans::conf is cleared in opmode_leave(), which means that
in the rest of the remove() it will be zeroed.

But some of the freeing code still needs some data from it, for example
the cmd_queue id.

For older devices that their cmd_queue id is not 0, it can cause us to
free queue 0 as it was a command queue.

A command queue is different from a regular queue, the first has its cmd as
regular kmalloc'ed memory while a regular queue has it from a
kmem_cache, so the two should be freed differently.

To avoid that, clear the trans::conf before we call the opmode
instead.

Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/iwl-drv.c   | 2 ++
 drivers/net/wireless/intel/iwlwifi/iwl-trans.c | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index 607fcea6f4ef..41fc45daa726 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -1549,6 +1549,8 @@ _iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op)
 		dbgfs_dir = drv->dbgfs_op_mode;
 #endif
 
+		memset(&drv->trans->conf, 0, sizeof(drv->trans->conf));
+
 		op_mode = ops->start(drv->trans, drv->trans->cfg,
 				     &drv->fw, dbgfs_dir);
 
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
index 5232f66c2d52..b25d54cfcfb7 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
@@ -423,7 +423,6 @@ void iwl_trans_op_mode_leave(struct iwl_trans *trans)
 	cancel_delayed_work_sync(&trans->restart.wk);
 
 	trans->op_mode = NULL;
-	memset(&trans->conf, 0, sizeof(trans->conf));
 
 	trans->state = IWL_TRANS_NO_FW;
 }
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH] wifi: mwifiex: replace one-element arrays with flexible array members
From: Kees Cook @ 2026-07-15 16:35 UTC (permalink / raw)
  To: Georgi Valkov
  Cc: briannorris, francesco, johannes.berg, bhelgaas, error27,
	s.kerkmann, linux-wireless, linux-kernel
In-Reply-To: <20260712222334.7134-1-gvalkov@gmail.com>

On Mon, Jul 13, 2026 at 01:23:34AM +0300, Georgi Valkov wrote:
> Replace deprecated one-element arrays with flexible array members.
> CONFIG_FORTIFY_SOURCE reports the following warning when
> one-element arrays are used as variable-length buffers:
> 
> sta_cmd.c:1033 mwifiex_sta_prepare_cmd
> memcpy: detected field-spanning write (size 84) of single field
> "domain->triplet" at .../marvell/mwifiex/sta_cmd.c:1033 (size 3)
> 
> Convert affected structs to use flexible array members.
> - Preserve existing wire layouts.
> - Replace affected uses of sizeof(member) with sizeof(type).
> - Replace unions containing one-element arrays with
>   u8 flexible arrays, and document the stored parameter-set type.
> 
> Tested-on: WRT3200ACM, OpenWrt
> Signed-off-by: Georgi Valkov <gvalkov@gmail.com>
> ---
>  drivers/net/wireless/marvell/mwifiex/fw.h     | 20 +++++++------------
>  drivers/net/wireless/marvell/mwifiex/join.c   |  8 ++++----
>  .../net/wireless/marvell/mwifiex/sta_cmd.c    |  2 +-
>  3 files changed, 12 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h
> index e9e896606912..ec3e3f806134 100644
> --- a/drivers/net/wireless/marvell/mwifiex/fw.h
> +++ b/drivers/net/wireless/marvell/mwifiex/fw.h
> @@ -823,7 +823,7 @@ struct chan_band_param_set {
>  
>  struct mwifiex_ie_types_chan_band_list_param_set {
>  	struct mwifiex_ie_types_header header;
> -	struct chan_band_param_set chan_band_param[1];
> +	struct chan_band_param_set chan_band_param[];
>  } __packed;
>  
>  struct mwifiex_ie_types_rates_param_set {
> @@ -886,7 +886,7 @@ struct mwifiex_ie_types_wildcard_ssid_params {
>  #define TSF_DATA_SIZE            8
>  struct mwifiex_ie_types_tsf_timestamp {
>  	struct mwifiex_ie_types_header header;
> -	u8 tsf_data[1];
> +	u8 tsf_data[];
>  } __packed;
>  
>  struct mwifiex_cf_param_set {
> @@ -902,10 +902,7 @@ struct mwifiex_ibss_param_set {
>  
>  struct mwifiex_ie_types_ss_param_set {
>  	struct mwifiex_ie_types_header header;
> -	union {
> -		struct mwifiex_cf_param_set cf_param_set[1];
> -		struct mwifiex_ibss_param_set ibss_param_set[1];
> -	} cf_ibss;
> +	u8 cf_ibss[];	/* CF and IBSS param sets are stored here */
>  } __packed;
>  
>  struct mwifiex_fh_param_set {
> @@ -921,10 +918,7 @@ struct mwifiex_ds_param_set {
>  
>  struct mwifiex_ie_types_phy_param_set {
>  	struct mwifiex_ie_types_header header;
> -	union {
> -		struct mwifiex_fh_param_set fh_param_set[1];
> -		struct mwifiex_ds_param_set ds_param_set[1];
> -	} fh_ds;
> +	u8 fh_ds[];	/* FH and DS param sets are stored here */
>  } __packed;

This (and below) can still be a union so you don't lose the type
information:

	union {
		DECLARE_FLEX_ARRAY(struct mwifiex_fh_param_set, fh_param_set);
		DECLARE_FLEX_ARRAY(struct mwifiex_ds_param_set, ds_param_set);
	} fh_ds;

>  
>  struct mwifiex_ie_types_auth_type {
> @@ -1383,7 +1377,7 @@ struct host_cmd_ds_802_11_snmp_mib {
>  	__le16 query_type;
>  	__le16 oid;
>  	__le16 buf_size;
> -	u8 value[1];
> +	u8 value[];
>  } __packed;
>  
>  struct mwifiex_rate_scope {
> @@ -1551,7 +1545,7 @@ struct mwifiex_scan_cmd_config {
>  	 *  TLV_TYPE_CHANLIST, mwifiex_ie_types_chan_list_param_set
>  	 *  WLAN_EID_SSID, mwifiex_ie_types_ssid_param_set
>  	 */
> -	u8 tlv_buf[1];	/* SSID TLV(s) and ChanList TLVs are stored
> +	u8 tlv_buf[];	/* SSID TLV(s) and ChanList TLVs are stored
>  				   here */
>  } __packed;
>  
> @@ -1683,7 +1677,7 @@ struct host_cmd_ds_802_11_bg_scan_query_rsp {
>  struct mwifiex_ietypes_domain_param_set {
>  	struct mwifiex_ie_types_header header;
>  	u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
> -	struct ieee80211_country_ie_triplet triplet[1];
> +	struct ieee80211_country_ie_triplet triplet[];
>  } __packed;
>  
>  struct host_cmd_ds_802_11d_domain_info {
> diff --git a/drivers/net/wireless/marvell/mwifiex/join.c b/drivers/net/wireless/marvell/mwifiex/join.c
> index 5a1a0287c1d5..a2c427e6af3f 100644
> --- a/drivers/net/wireless/marvell/mwifiex/join.c
> +++ b/drivers/net/wireless/marvell/mwifiex/join.c
> @@ -421,15 +421,15 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
>  
>  	phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos;
>  	phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS);
> -	phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set));
> -	memcpy(&phy_tlv->fh_ds.ds_param_set,
> +	phy_tlv->header.len = cpu_to_le16(sizeof(struct mwifiex_ds_param_set));

And this would become (the "*" added to get the member size):

	phy_tlv->header.len = cpu_to_le16(sizeof(*phy_tlv->fh_ds.ds_param_set));

etc.

> +	memcpy(phy_tlv->fh_ds,
>  	       &bss_desc->phy_param_set.ds_param_set.current_chan,
> -	       sizeof(phy_tlv->fh_ds.ds_param_set));
> +	       sizeof(struct mwifiex_ds_param_set));
>  	pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len);
>  
>  	ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos;
>  	ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS);
> -	ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set));
> +	ss_tlv->header.len = cpu_to_le16(sizeof(struct mwifiex_cf_param_set));
>  	pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len);
>  
>  	/* Get the common rates supported between the driver and the BSS Desc */
> diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
> index 623ddde8c8e5..071f7cb305e1 100644
> --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
> +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
> @@ -108,7 +108,7 @@ static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv,
>  		    "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
>  	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
>  	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib)
> -				- 1 + S_DS_GEN);
> +				+ S_DS_GEN);
>  
>  	snmp_mib->oid = cpu_to_le16((u16)cmd_oid);
>  	if (cmd_action == HostCmd_ACT_GEN_GET) {
> -- 
> 2.55.0
> 

-- 
Kees Cook

^ permalink raw reply

* Re: [PATCH] wifi: mwifiex: validate HT/VHT capability and operation IE lengths
From: Francesco Dolcini @ 2026-07-15 16:34 UTC (permalink / raw)
  To: Doruk Tan Ozturk
  Cc: Francesco Dolcini, Brian Norris, Kees Cook, linux-wireless,
	linux-kernel, stable
In-Reply-To: <20260715162800.1922-1-doruk@0sec.ai>

On Wed, Jul 15, 2026 at 06:28:00PM +0200, Doruk Tan Ozturk wrote:
> > why break and not return -EINVAL? (this in general, not only on this
> > specific one).
> 
> To skip the one malformed optional element and keep parsing the rest of the
> beacon, like the FH/DS/CF/IBSS cases just above in the same loop. Happy to
> switch to -EINVAL if you'd rather reject the whole BSS.

maybe I am missing something, but I see return -EINVAL; when the packet
is malformed. see for example

		case WLAN_EID_VENDOR_SPECIFIC:
			vendor_ie = (struct ieee_types_vendor_specific *)
					current_ptr;

			/* 802.11 requires at least 3-byte OUI. */
			if (element_len < sizeof(vendor_ie->vend_hdr.oui.oui))
				return -EINVAL;


My advise would be to do the same we are already doing, and unless I am
wrong, it means that we skip the whole frame if a corruption is
detected.

Francesco



^ permalink raw reply

* Re: [PATCH v2] wifi: mwifiex: bound uAP association event IEs to the event buffer
From: Francesco Dolcini @ 2026-07-15 16:28 UTC (permalink / raw)
  To: HE WEI (ギカク)
  Cc: Brian Norris, Francesco Dolcini, Miri Korenblit, Johannes Berg,
	Kees Cook, Kalle Valo, linux-wireless, linux-kernel
In-Reply-To: <20260715135711.34688-1-skyexpoc@gmail.com>

On Wed, Jul 15, 2026 at 10:57:11PM +0900, HE WEI (ギカク) wrote:
> mwifiex_process_uap_event() handles EVENT_UAP_STA_ASSOC by exposing the
> (re)association request IEs that the firmware copies into the event:
> 
> 	sinfo->assoc_req_ies = &event->data[len];
> 	len = (u8 *)sinfo->assoc_req_ies - (u8 *)&event->frame_control;
> 	sinfo->assoc_req_ies_len = le16_to_cpu(event->len) - (u16)len;
> 
> event->len is supplied by the device firmware and is never validated,
> and the subtraction is unchecked.  assoc_req_ies points into
...

> 
> Fixes: e568634ae7ac ("mwifiex: add AP event handling framework")
> Signed-off-by: HE WEI (ギカク) <skyexpoc@gmail.com>

Where you able to test this? It looks ok, but you never know ...

Reviewed-by: Francesco Dolcini <francesco.dolcini@toradex.com>


^ permalink raw reply

* Re: [PATCH] wifi: mwifiex: validate HT/VHT capability and operation IE lengths
From: Doruk Tan Ozturk @ 2026-07-15 16:28 UTC (permalink / raw)
  To: Francesco Dolcini
  Cc: Brian Norris, Kees Cook, linux-wireless, linux-kernel, stable
In-Reply-To: <20260715144021.GE56330@francesco-nb>

> Were you able to test that this is not breaking the driver functionality?

Unfortunately I don't own one of these cards, and mwifiex is fullmac so
there's no hwsim either, so it was source and compile only. The added checks
only skip elements too short for what the driver later reads, so they
shouldn't affect a well-formed beacon.

> why break and not return -EINVAL? (this in general, not only on this
> specific one).

To skip the one malformed optional element and keep parsing the rest of the
beacon, like the FH/DS/CF/IBSS cases just above in the same loop. Happy to
switch to -EINVAL if you'd rather reject the whole BSS.

-Doruk

^ permalink raw reply

* Re: [PATCH] wifi: mwifiex: bound the pairwise-cipher OUI walk to the IE length
From: Doruk Tan Ozturk @ 2026-07-15 16:27 UTC (permalink / raw)
  To: Francesco Dolcini; +Cc: Brian Norris, linux-wireless, linux-kernel, stable
In-Reply-To: <20260715144752.GF56330@francesco-nb>

> maybe define an intermediate variable to store `offsetof(struct ie_body, ptk_body)`
> so that it is clear what this is, and you also can re-use it later?

Good idea, will do in v2. Thanks.

-Doruk

^ permalink raw reply

* Re: [PATCH] wifi: mwifiex: replace one-element arrays with flexible array members
From: Francesco Dolcini @ 2026-07-15 16:14 UTC (permalink / raw)
  To: Georgi Valkov
  Cc: briannorris, francesco, johannes.berg, bhelgaas, error27,
	s.kerkmann, kees, linux-wireless, linux-kernel
In-Reply-To: <20260712222334.7134-1-gvalkov@gmail.com>

On Mon, Jul 13, 2026 at 01:23:34AM +0300, Georgi Valkov wrote:
> Replace deprecated one-element arrays with flexible array members.
> CONFIG_FORTIFY_SOURCE reports the following warning when
> one-element arrays are used as variable-length buffers:
> 
> sta_cmd.c:1033 mwifiex_sta_prepare_cmd
> memcpy: detected field-spanning write (size 84) of single field
> "domain->triplet" at .../marvell/mwifiex/sta_cmd.c:1033 (size 3)
> 
> Convert affected structs to use flexible array members.
> - Preserve existing wire layouts.
> - Replace affected uses of sizeof(member) with sizeof(type).
> - Replace unions containing one-element arrays with
>   u8 flexible arrays, and document the stored parameter-set type.
> 
> Tested-on: WRT3200ACM, OpenWrt
> Signed-off-by: Georgi Valkov <gvalkov@gmail.com>

Reviewed-by: Francesco Dolcini <francesco.dolcini@toradex.com>


^ permalink raw reply

* [PATCH mt76 v2 2/2] wifi: mt76: mt7915: fix net_fill_forward_path for non-DBDC mt7986
From: Zhi-Jun You @ 2026-07-15 15:21 UTC (permalink / raw)
  To: nbd, lorenzo, ryder.lee
  Cc: shayne.chen, sean.wang, linux-wireless, linux-mediatek,
	Zhi-Jun You, Benjamin Larsson
In-Reply-To: <20260715152113.553-1-hujy652@gmail.com>

Current implementation assumes that the hardware supports DBDC or single
band and binds to band0.

This causes net_fill_forward_path to select the wrong queue for non-DBDC
mt7986 because it binds to band1 and getting the following in dmesg:

ieee80211 phy2: WA: --> drop by reaseon:1, msdu id = 0xc002 but failed!
mtk_wed1: error status=00000002
ieee80211 phy2: WA: txblk
10324e00
len = 128
DW0 : 10 00 00 00
DW1 : 00 00 00 00
DW2 : 00 00 00 00
DW3 : 72 0f 94 68
DW4 : 00 00 00 00
DW5 : ff 03 00 00
DW6 : 00 00 3c 40
DW7 : 00 17 dd 14
DW8 : 79 6f 00 00
DW9 : 02 c0 00 00
DW10 : 58 c5 34 10
DW11 : 00 00 00 00
DW12 : 00 06 3e 00
DW13 : 00 00 00 80
DW14 : 10 8c 00 00
DW15 : 00 00 00 00
DW16 : 00 00 00 00
DW17 : 00 00 00 00
DW18 : 00 00 00 00
DW19 : 00 00 00 00
DW20 : 00 00 00 00
DW21 : 00 00 00 00
DW22 : 00 00 00 00
DW23 : 00 00 00 00
DW24 : 00 00 00 00
DW25 : 00 00 00 00
DW26 : 00 00 00 00
DW27 : 00 00 00 00
DW28 : 00 00 00 00
DW29 : 00 00 00 00
DW30 : 00 00 00 00
DW31 : 00 00 00 00

Fix it by using phy->mt76->band_idx for queue which works for both
non-DBDC and DBDC devices.

Fixes: f68d67623dec ("mt76: mt7915: add Wireless Ethernet Dispatch support")
Suggested-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
Signed-off-by: Zhi-Jun You <hujy652@gmail.com>
---
Changes in v2
- Use band_idx for all cases.
- Link to v1: https://lore.kernel.org/linux-wireless/20260630150649.1629-2-hujy652@gmail.com
---
 drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index 51643a48ed15..044b592efe28 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -1743,7 +1743,7 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw,
 	path->mtk_wdma.wdma_idx = wed->wdma_idx;
 	path->mtk_wdma.bss = mvif->mt76.idx;
 	path->mtk_wdma.wcid = is_mt7915(&dev->mt76) ? msta->wcid.idx : 0x3ff;
-	path->mtk_wdma.queue = phy != &dev->phy;
+	path->mtk_wdma.queue = phy->mt76->band_idx;
 
 	ctx->dev = NULL;
 
-- 
2.47.3


^ permalink raw reply related

* [PATCH mt76 v2 1/2] wifi: mt76: wed: fix kernel panic on non-DBDC MT7986
From: Zhi-Jun You @ 2026-07-15 15:21 UTC (permalink / raw)
  To: nbd, lorenzo, ryder.lee
  Cc: shayne.chen, sean.wang, linux-wireless, linux-mediatek,
	Zhi-Jun You

In mt76_wed_init_rx_buf, it's hardcoded to use MT_RXQ_MAIN.
But for non-DBDC MT7986 MT_RXQ_BAND1 is used for RX data queue which
leads to kernel panic when attaching WED.

Use the correct RX queue by checking WED version and band_idx.

v2 and band 1 -> MT_RXQ_BAND1
Others -> MT_RXQ_MAIN

Kernel panic:

Unable to handle kernel access to user memory outside uaccess routines at virtual address 0000000000000000
Mem abort info:
  ESR = 0x0000000096000005
  EC = 0x25: DABT (current EL), IL = 32 bits
  SET = 0, FnV = 0
  EA = 0, S1PTW = 0
  FSC = 0x05: level 1 translation fault
Data abort info:
  ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000
  CM = 0, WnR = 0, TnD = 0, TagAccess = 0
  GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
Internal error: Oops: 0000000096000005 [#1]  SMP
CPU: 1 UID: 0 PID: 925 Comm: kmodloader Tainted: G           O        6.18.26 #0 NONE
Tainted: [O]=OOT_MODULE
Hardware name: Acer Connect Vero W6m (DT)
pstate: 40400005 (nZcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
pc : page_pool_alloc_frag_netmem+0x1c/0x1bc
lr : page_pool_alloc_frag+0xc/0x34
sp : ffffffc081dab660
x29: ffffffc081dab660 x28: ffffffc081dabc60 x27: ffffff80091af040
x26: 0000008000000000 x25: ffffff80091a8898 x24: ffffff80091a5440
x23: 0000000000001000 x22: 0000000140000000 x21: ffffff80091a2040
x20: ffffff8003f1d780 x19: 0000000000000000 x18: 0000000000000020
x17: ffffffbfbf0ac000 x16: ffffffc080ee0000 x15: ffffff80049d47ca
x14: 000000000000037b x13: 000000000000037b x12: 0000000000000001
x11: 0000000000000000 x10: 0000000000000000 x9 : 0000000000000000
x8 : ffffff8003f1d7c0 x7 : 0000000000000000 x6 : ffffff8003f1d780
x5 : 0000000000000680 x4 : 0000000000000000 x3 : 0000000000002824
x2 : 0000000000000000 x1 : ffffffc081dab71c x0 : 0000000000000000
Call trace:
 page_pool_alloc_frag_netmem+0x1c/0x1bc (P)
 page_pool_alloc_frag+0xc/0x34
 mt76_wed_init_rx_buf+0xf8/0x2ac [mt76]
 mtk_wed_start+0x79c/0x12ac
 mt7915_dma_start+0x274/0x63c [mt7915e]
 mt7915_dma_start+0x5b4/0x63c [mt7915e]
 mt7915_dma_init+0x49c/0x81c [mt7915e]
 mt7915_register_device+0x24c/0x530 [mt7915e]
 mt7915_mmio_probe+0x91c/0x1980 [mt7915e]
 platform_probe+0x58/0xa0
 really_probe+0xb8/0x2a8
 __driver_probe_device+0x74/0x118
 driver_probe_device+0x3c/0xe0
 __driver_attach+0x88/0x154
 bus_for_each_dev+0x60/0xb0
 driver_attach+0x20/0x28
 bus_add_driver+0xdc/0x200
 driver_register+0x64/0x118
 __platform_driver_register+0x20/0x30
 init_module+0x74/0x1000 [mt7915e]
 do_one_initcall+0x4c/0x1f8
 do_init_module+0x50/0x210
 load_module+0x15f8/0x1b10
 __do_sys_init_module+0x1a8/0x260
 __arm64_sys_init_module+0x18/0x20
 invoke_syscall.constprop.0+0x4c/0xd0
 do_el0_svc+0x3c/0xd0
 el0_svc+0x18/0x60
 el0t_64_sync_handler+0x98/0xdc
 el0t_64_sync+0x158/0x15c
Code: aa0003f3 a9025bf5 a90363f7 d2820017 (b9400000)

Signed-off-by: Zhi-Jun You <hujy652@gmail.com>
---
Changes since RFC
- Replace single band with non-DBDC
---
 drivers/net/wireless/mediatek/mt76/wed.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/wed.c b/drivers/net/wireless/mediatek/mt76/wed.c
index ed657d952de2..f210a0c57d81 100644
--- a/drivers/net/wireless/mediatek/mt76/wed.c
+++ b/drivers/net/wireless/mediatek/mt76/wed.c
@@ -33,10 +33,15 @@ u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
 {
 	struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc;
 	struct mt76_dev *dev = mt76_wed_to_dev(wed);
-	struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
 	struct mt76_txwi_cache *t = NULL;
+	struct mt76_queue *q;
 	int i;
 
+	if (wed->version == 2 && dev->phy.band_idx)
+		q = &dev->q_rx[MT_RXQ_BAND1];
+	else
+		q = &dev->q_rx[MT_RXQ_MAIN];
+
 	for (i = 0; i < size; i++) {
 		dma_addr_t addr;
 		u32 offset;
-- 
2.47.3


^ permalink raw reply related

* Re: [PATCH] wifi: mwifiex: fix freeze for 60 seconds caused by request_firmware
From: Francesco Dolcini @ 2026-07-15 14:52 UTC (permalink / raw)
  To: Georgi Valkov
  Cc: briannorris, francesco, s.kerkmann, johannes.berg, kees,
	linux-wireless, linux-kernel
In-Reply-To: <20260712221709.7099-1-gvalkov@gmail.com>

On Mon, Jul 13, 2026 at 01:17:09AM +0300, Georgi Valkov wrote:
> Fix regression in rgpower table loading, caused by using
> request_firmware(): when the requested firmware does not exist, e.g.
> nxp/rgpower_WW.bin does not exist on OpenWRT builds for WRT3200ACM,
> request_firmware() falls back to firmware_fallback_sysfs(), which expects
> the firmware to be provided by user space using SYSFS. No such utility is
> provided in this configuration, so the entire system locks up for 60
> seconds, until the request times out. During this time, no other log
> messages are observed, and the device does not respond to commands over
> UART.
> 
> The request_firmware() call is performed in the following context:
> current->comm kworker/1:2  in_task 1  irqs_disabled 0  in_atomic 0
> 
> Fixed by using request_firmware_direct(). This prevents fallback to SYSFS,
> and avoids delay. The rgpower table is optional. The driver falls back
> to the device tree power table if the firmware is not present.
> 
> The error code is printed for debugging and returned to the caller,
> which only cares for success or failure, so there are no side effects.
> 
> Fixes: 7b6f16a25806 ("wifi: mwifiex: add rgpower table loading support")
> Signed-off-by: Georgi Valkov <gvalkov@gmail.com>

Reviewed-by: Francesco Dolcini <francesco.dolcini@toradex.com>


^ permalink raw reply

* Re: [PATCH] wifi: mwifiex: bound the pairwise-cipher OUI walk to the IE length
From: Francesco Dolcini @ 2026-07-15 14:47 UTC (permalink / raw)
  To: Doruk Tan Ozturk
  Cc: Brian Norris, Francesco Dolcini, linux-wireless, linux-kernel,
	stable
In-Reply-To: <20260711071334.58307-1-doruk@0sec.ai>

On Sat, Jul 11, 2026 at 09:13:34AM +0200, Doruk Tan Ozturk wrote:
> mwifiex_search_oui_in_ie() reads the pairwise-cipher (PTK) count from a
> beacon/probe-response RSN or WPA information element:
> 
> 	count = iebody->ptk_cnt[0];
> 
> and then walks "count" 4-byte OUIs from the element, comparing each with
> memcmp(). The count byte comes straight from the (attacker-supplied) IE
> and is never checked against the element's own length. The callers admit
> the element on element_id alone (has_ieee_hdr() / has_vendor_hdr(), no
> length check), so a crafted RSN/WPA IE with a large pairwise count makes
> the walk read up to 255 * 4 bytes past the element -- an out-of-bounds
> read of the kmemdup()'d beacon buffer, reachable from any AP whose
> beacon/probe response is processed during scan result parsing.
> 
> Pass the number of available IE bytes to the walk and reject a count
> whose OUI list would not fit, keeping the loop within the element.
> 
> Found by 0sec (https://0sec.ai) using automated source analysis; the
> unbounded count-driven walk is evident from source. Compile-tested.
> 
> Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver")
> Cc: stable@vger.kernel.org
> Assisted-by: 0sec:claude-opus-4-8
> Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
> ---
>  drivers/net/wireless/marvell/mwifiex/scan.c | 22 ++++++++++++++++++---
>  1 file changed, 19 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c
> index 97c0ec3b822e..3a55fc6f1b54 100644
> --- a/drivers/net/wireless/marvell/mwifiex/scan.c
> +++ b/drivers/net/wireless/marvell/mwifiex/scan.c
> @@ -104,12 +104,21 @@ has_vendor_hdr(struct ieee_types_vendor_specific *ie, u8 key)
>   * a given oui in PTK.
>   */
>  static u8
> -mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui)
> +mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui, int ie_len)
>  {
>  	u8 count;
>  
> +	/* Need grp_key_oui[4] + ptk_cnt[2] before reading the OUI count. */
> +	if (ie_len < (int)offsetof(struct ie_body, ptk_body))

maybe define an intermediate variable to store `offsetof(struct ie_body, ptk_body)`
so that it is clear what this is, and you also can re-use it later?

Francesco


^ permalink raw reply

* Re: [PATCH] wifi: mwifiex: validate HT/VHT capability and operation IE lengths
From: Francesco Dolcini @ 2026-07-15 14:40 UTC (permalink / raw)
  To: Doruk Tan Ozturk
  Cc: Brian Norris, Francesco Dolcini, Kees Cook, linux-wireless,
	linux-kernel, stable
In-Reply-To: <20260709100800.7026-1-doruk@0sec.ai>

On Thu, Jul 09, 2026 at 12:08:00PM +0200, Doruk Tan Ozturk wrote:
> mwifiex_update_bss_desc_with_ie() records raw pointers to the HT
> Capabilities, HT Operation, VHT Capabilities, VHT Operation, 20/40 BSS
> Coexistence and Operating Mode Notification elements taken straight out
> of a beacon/probe-response buffer, without checking that each element is
> long enough for the fixed-size structure that later consumers read. The
> buffer is a tight kmemdup() of the on-air IEs (beacon_buf_size ==
> ies->len), so a truncated element placed last leaves the stored pointer
> one past the end of the allocation.
> 
> At association time these pointers are dereferenced at fixed offsets
> regardless of the on-air length: mwifiex_cmd_append_11n_tlv() memcpy()s
> sizeof(struct ieee80211_ht_cap) (26 bytes) from bcn_ht_cap and reads
> bcn_ht_oper->ht_param, and mwifiex_cmd_append_11ac_tlv() memcpy()s
> sizeof(struct ieee80211_vht_cap) (12 bytes) from bcn_vht_cap and reads
> bcn_vht_oper->chan_width. A nearby AP (rogue / evil-twin; an open SSID
> needs no credentials) advertising a BSS with a truncated HT/VHT cap
> element therefore triggers a slab out-of-bounds read on the victim's
> association attempt. This out-of-bounds read is the primary issue.
> 
> For the HT-Cap copy the over-read bytes are additionally placed into the
> outgoing association request, so a limited amount of adjacent heap memory
> can leak over the air. In station mode this is small (single-digit
> bytes), because mwifiex_fill_cap_info() rewrites most of the copied
> HT-Cap before transmission; the leak is a secondary effect.
> 
> mwifiex_set_sta_ht_cap() has the same missing-length pattern: in uAP mode
> it reads two bytes of ieee80211_ht_cap.cap_info from a
> cfg80211_find_ie(WLAN_EID_HT_CAPABILITY) result in a client association
> request without checking the element length, a 1-2 byte out-of-bounds
> read (used only to select an A-MSDU size, not leaked).
> 
> Reject (skip) any of these elements whose payload is shorter than the
> structure the driver later reads, matching the length validation the
> FH/DS/CF/IBSS parameter-set cases in the same beacon parser already
> perform.
> 
> No dynamic reproducer: mwifiex is a fullmac driver for Marvell hardware
> with no mac80211_hwsim equivalent, so this was confirmed by source and
> structure-offset analysis only.

Were you able to test that this is not breaking the driver functionality?

> 
> Found by 0sec automated security-research tooling (https://0sec.ai).
> 
> Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver")
> Cc: stable@vger.kernel.org
> Assisted-by: 0sec:claude-opus-4-8
> Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
> ---
>  drivers/net/wireless/marvell/mwifiex/scan.c | 12 ++++++++++++
>  drivers/net/wireless/marvell/mwifiex/util.c |  2 +-
>  2 files changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c
> index 97c0ec3b822e..997e7e19525b 100644
> --- a/drivers/net/wireless/marvell/mwifiex/scan.c
> +++ b/drivers/net/wireless/marvell/mwifiex/scan.c
> @@ -1384,6 +1384,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
>  							bss_entry->beacon_buf);
>  			break;
>  		case WLAN_EID_HT_CAPABILITY:
> +			if (element_len < sizeof(struct ieee80211_ht_cap))
> +				break;

why break and not return -EINVAL? (this in general, not only on this
specific one).



^ permalink raw reply

* kernel BUG at mm/slub.c:634 (kfree) when unbinding device from iwlwifi
From: Marek Marczykowski-Górecki @ 2026-07-15 14:32 UTC (permalink / raw)
  To: Miri Korenblit; +Cc: linux-wireless, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 7730 bytes --]

Hello,

I get a kernel panic when unbinding device (8086:0085) from the iwlwifi
driver (via writing to the "unbind" file in sysfs), while the wifi
connection is active. I can reproduce it on Thinkpad X230, but other
devices might be affected too. The specific crash is:

    [  286.908182] kernel BUG at mm/slub.c:634!
    [  286.908201] Oops: invalid opcode: 0000 [#1] SMP PTI
    [  286.908221] CPU: 1 UID: 0 PID: 1959 Comm: prepare-suspend Not tainted 6.18.15-1.qubes.fc41.x86_64 #1 PREEMPT(full) 
    [  286.908255] Hardware name: Xen HVM domU, BIOS 4.19.4 03/17/2026
    [  286.908275] RIP: 0010:kfree+0x3a8/0x470
    [  286.908292] Code: 5d 41 5e 41 5f 5d e9 67 bb ff ff 4d 89 f1 41 b8 01 00 00 00 48 89 d9 48 89 da 4c 89 ee 4c 89 e7 e8 ad 2c 00 00 e9 bd fd ff ff <0f> 0b 89 c8 4c 8d 04 03 40 f6 c6 80 0f 84 41 ff ff ff 83 e6 08 0f
    [  286.908347] RSP: 0018:ffffcfce8280bb50 EFLAGS: 00010246
    [  286.908365] RAX: ffff8b2dcef2c800 RBX: ffff8b2dcef2c800 RCX: ffff8b2dcef2c830
    [  286.908389] RDX: 00000000000be001 RSI: 0000000000000000 RDI: ffff8b2dcef2c880
    [  286.908414] RBP: ffffcfce8280bba0 R08: ffff8b2dcef2c860 R09: 0000000000000000
    [  286.908438] R10: ffff8b2dcef2c860 R11: 0000000000000000 R12: ffff8b2dd2841600
    [  286.908462] R13: fffff077003bcb00 R14: ffffffffc093c480 R15: 0000000000000060
    [  286.908487] FS:  00007b10286cd740(0000) GS:ffff8b2e19c6c000(0000) knlGS:0000000000000000
    [  286.908511] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
    [  286.908532] CR2: 00007fb93027bc70 CR3: 00000000034f0005 CR4: 00000000001706f0
    [  286.908559] Call Trace:
    [  286.908570]  <TASK>
    [  286.908581]  ? _raw_spin_unlock_bh+0xe/0x20
    [  286.908599]  iwl_pcie_txq_free+0x130/0x170 [iwlwifi]
    [  286.908644]  iwl_pcie_tx_free+0x66/0xe0 [iwlwifi]
    [  286.908681]  iwl_trans_pcie_free+0x1df/0x250 [iwlwifi]
    [  286.908719]  pci_device_remove+0x42/0xb0
    [  286.908736]  device_release_driver_internal+0x19c/0x200
    [  286.908755]  unbind_store+0xa1/0xb0
    [  286.908771]  kernfs_fop_write_iter+0x150/0x200
    [  286.908790]  vfs_write+0x25d/0x450
    [  286.908806]  ksys_write+0x6b/0xe0
    [  286.908825]  do_syscall_64+0x84/0x800
    [  286.908842]  ? syscall_exit_work+0x108/0x140
    [  286.908861]  ? do_syscall_64+0xbb/0x800
    [  286.908876]  ? ksys_dup3+0x63/0xf0
    [  286.908892]  ? syscall_exit_work+0x108/0x140
    [  286.911388]  ? do_syscall_64+0xbb/0x800
    [  286.911408]  ? do_sys_openat2+0xa4/0xe0
    [  286.911423]  ? syscall_exit_work+0x108/0x140
    [  286.911443]  ? do_syscall_64+0xbb/0x800
    [  286.911458]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
    [  286.911477] RIP: 0033:0x7b102873ec5e
    [  286.911493] Code: 4d 89 d8 e8 34 bd 00 00 4c 8b 5d f8 41 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 11 c9 c3 0f 1f 80 00 00 00 00 48 8b 45 10 0f 05 <c9> c3 83 e2 39 83 fa 08 75 e7 e8 13 ff ff ff 0f 1f 00 f3 0f 1e fa
    [  286.911549] RSP: 002b:00007ffd94bc3100 EFLAGS: 00000202 ORIG_RAX: 0000000000000001
    [  286.911575] RAX: ffffffffffffffda RBX: 00007b10288ba5c0 RCX: 00007b102873ec5e
    [  286.911600] RDX: 000000000000000d RSI: 00006385db4f8020 RDI: 0000000000000001
    [  286.911625] RBP: 00007ffd94bc3110 R08: 0000000000000000 R09: 0000000000000000
    [  286.911650] R10: 0000000000000000 R11: 0000000000000202 R12: 000000000000000d
    [  286.911674] R13: 000000000000000d R14: 00006385db4f8020 R15: 00006385db4f5b30
    [  286.911701]  </TASK>
    [  286.911711] Modules linked in: iwldvm iwlwifi mac80211 ehci_pci ehci_hcd nft_nat nft_flow_offload nf_flow_table_inet nf_flow_table qrtr nf_conntrack_netlink nft_reject_ipv6 nf_reject_ipv6 nft_reject_ipv4 nf_reject_ipv4 nft_reject nft_ct nft_masq nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables joydev libarc4 intel_rapl_msr intel_rapl_common polyval_clmulni ghash_clmulni_intel cfg80211 e1000e ata_generic rfkill i2c_piix4 pata_acpi i2c_smbus pcspkr floppy vfat fat serio_raw xen_scsiback target_core_mod xen_netback xen_privcmd xen_gntdev xen_gntalloc xen_blkback xen_evtchn i2c_dev fuse loop nfnetlink overlay xen_blkfront [last unloaded: iwlwifi]
    [  286.911967] ---[ end trace 0000000000000000 ]---

This is running in a VM (HVM) under Xen, with relevant PCI device
attached, but I don't think it's relevant for this bug.

I've got reports about the issue in Linux 6.18.15 initially (after
updating from 6.12), but later tests identified it's a regression
somewhere between 6.15.11 and 6.16.8.

The crash still happen on 7.0.14, although it looks different there:

    [  106.379541] ------------[ cut here ]------------
    [  106.379572] kernel BUG at mm/slub.c:542!
    [  106.379596] Oops: invalid opcode: 0000 [#1] SMP PTI
    [  106.379618] CPU: 1 UID: 0 PID: 240 Comm: kworker/1:2 Not tainted 7.0.14-1.qubes.fc41.x86_64 #1 PREEMPT(full) 
    [  106.379656] Hardware name: Xen HVM domU, BIOS 4.19.4 06/09/2026
    [  106.379680] Workqueue: slub_flushwq flush_cpu_sheaves
    [  106.379711] RIP: 0010:build_detached_freelist+0x1d0/0x210
    [  106.379733] Code: 41 5c 41 5d c3 cc cc cc cc 31 d2 4d 85 c0 0f 85 b2 fe ff ff 48 89 04 24 e8 7d fd ff ff 48 c7 03 00 00 00 00 48 8b 04 24 eb d0 <0f> 0b 48 85 d2 74 e3 48 89 13 4c 8b 42 08 e9 8c fe ff ff 0f 0b 31
    [  106.379795] RSP: 0000:ffffcebd804c3c88 EFLAGS: 00010246
    [  106.379815] RAX: 000000000000001d RBX: ffffcebd804c3cb8 RCX: ffff8e6240fcf000
    [  106.379843] RDX: ffff8e6240fcf000 RSI: 000000000000001d RDI: 0000000000000003
    [  106.379870] RBP: ffffffff80000000 R08: 0000000080000000 R09: ffff8e6240fcf030
    [  106.379898] R10: ffffcebd804c3d10 R11: 0000000000000000 R12: ffff8e6242a68b00
    [  106.379925] R13: ffff8e6242a68aff R14: 000000000000001c R15: 0000000000000000
    [  106.379953] FS:  0000000000000000(0000) GS:ffff8e62a837a000(0000) knlGS:0000000000000000
    [  106.379981] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
    [  106.380004] CR2: 0000767e599f2fd0 CR3: 000000000c1d2001 CR4: 00000000001706f0
    [  106.380035] Call Trace:
    [  106.380047]  <TASK>
    [  106.380060]  __kmem_cache_free_bulk.part.0+0x60/0xe0
    [  106.380085]  __sheaf_flush_main_batch+0xa1/0xe0
    [  106.380110]  flush_cpu_sheaves+0xc3/0xe0
    [  106.380129]  process_one_work+0x198/0x390
    [  106.380149]  worker_thread+0x1af/0x320
    [  106.380168]  ? __pfx_worker_thread+0x10/0x10
    [  106.380190]  kthread+0xe3/0x120
    [  106.380207]  ? __pfx_kthread+0x10/0x10
    [  106.380223]  ret_from_fork+0x19e/0x260
    [  106.380241]  ? __pfx_kthread+0x10/0x10
    [  106.380257]  ret_from_fork_asm+0x1a/0x30
    [  106.380276]  </TASK>
    [  106.380287] Modules linked in: nft_nat nft_flow_offload nf_flow_table_inet nf_flow_table nf_conntrack_netlink nft_reject_ipv6 nf_reject_ipv6 qrtr nft_reject_ipv4 nf_reject_ipv4 nft_reject nft_ct nft_masq nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables vfat fat intel_rapl_msr iwldvm intel_rapl_common ghash_clmulni_intel mac80211 libarc4 iwlwifi joydev cfg80211 ehci_pci pcspkr e1000e ehci_hcd rfkill floppy ata_generic i2c_piix4 pata_acpi i2c_smbus serio_raw xen_scsiback target_core_mod xen_netback xen_privcmd xen_gntdev xen_gntalloc xen_blkback xen_evtchn i2c_dev loop fuse nfnetlink zram lz4hc_compress lz4_compress overlay xen_blkfront
    [  106.381851] ---[ end trace 0000000000000000 ]---

This one doesn't have obvious relation to iwlwifi, but I suspect it's at
least related.

There are some more call traces at
https://github.com/QubesOS/qubes-issues/issues/10845 but they look
pretty similar.

-- 
Best Regards,
Marek Marczykowski-Górecki
Invisible Things Lab

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [PATCH] wifi: mwifiex: validate scan TLV result arrays
From: Francesco Dolcini @ 2026-07-15 14:17 UTC (permalink / raw)
  To: Pengpeng Hou
  Cc: Brian Norris, Francesco Dolcini, Kees Cook, linux-wireless,
	linux-kernel
In-Reply-To: <20260706092654.79403-1-pengpeng@iscas.ac.cn>

On Mon, Jul 06, 2026 at 05:26:54PM +0800, Pengpeng Hou wrote:
> mwifiex_ret_802_11_scan() indexes TSF and channel-band TLV
> arrays by the reported number of BSS result sets.
> 
> Ignore TSF or channel-band TLVs whose payload length cannot provide one
> entry per reported BSS set.
> 
> Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>

Was this tested?

> ---
>  drivers/net/wireless/marvell/mwifiex/scan.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c
> index 97c0ec3b822e..7416756ada3b 100644
> --- a/drivers/net/wireless/marvell/mwifiex/scan.c
> +++ b/drivers/net/wireless/marvell/mwifiex/scan.c
> @@ -2165,6 +2165,15 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
>  					     (struct mwifiex_ie_types_data **)
>  					     &chan_band_tlv);
>  
> +	if (tsf_tlv &&
> +	    le16_to_cpu(tsf_tlv->header.len) / TSF_DATA_SIZE <
> +	    scan_rsp->number_of_sets)
> +		tsf_tlv = NULL;
> +	if (chan_band_tlv &&
> +	    le16_to_cpu(chan_band_tlv->header.len) /
> +	    sizeof(*chan_band_tlv->chan_band_param) < scan_rsp->number_of_sets)
> +		chan_band_tlv = NULL;
> +

If something like that happen we should return an error, and return from
the function

a few lines before we do

	if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) {
		mwifiex_dbg(adapter, ERROR,
			    "SCAN_RESP: too many AP returned (%d)\n",
			    scan_rsp->number_of_sets);
		ret = -1;
		goto check_next_scan;
	}

why not doing something similar when this buffer from the fw is
corrupted?

Francesco


^ permalink raw reply

* [PATCH v2] wifi: iwlwifi: validate UEFI reduced-power SKU TLV length
From: Pengpeng Hou @ 2026-07-15 13:57 UTC (permalink / raw)
  To: Miri Korenblit; +Cc: linux-wireless, linux-kernel, Pengpeng Hou

iwl_uefi_reduce_power_parse() reads an iwl_sku_id from an
IWL_UCODE_TLV_PNVM_SKU payload after only checking that the generic TLV
payload is present.

A short type-specific payload can therefore make the three data[] reads
extend beyond the TLV. Reject SKU TLVs shorter than the structure before
accessing it.

Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
Changes since v1: https://lore.kernel.org/all/2026063008051412.5-ccfa108-0020-wifi-iwlwifi-validate-UEFI--pengpeng@iscas.ac.cn/
- use sizeof(*tlv_sku_id) as requested by Miri Korenblit
---
 drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
index 2ef0a7a..4cd36b4 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -248,6 +248,12 @@ int iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
 			IWL_DEBUG_FW(trans,
 				     "Got IWL_UCODE_TLV_PNVM_SKU len %d\n",
 				     tlv_len);
+			if (tlv_len < sizeof(*tlv_sku_id)) {
+				IWL_ERR(trans, "invalid PNVM SKU TLV len: %u\n",
+					tlv_len);
+				return -EINVAL;
+			}
+
 			IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n",
 				     le32_to_cpu(tlv_sku_id->data[0]),
 				     le32_to_cpu(tlv_sku_id->data[1]),
-- 
2.50.1 (Apple Git-155)



^ permalink raw reply related

* [PATCH v2] wifi: iwlwifi: validate PNVM SKU TLV length
From: Pengpeng Hou @ 2026-07-15 13:57 UTC (permalink / raw)
  To: Miri Korenblit; +Cc: linux-wireless, linux-kernel, Pengpeng Hou

iwl_pnvm_parse() reads an iwl_sku_id from an
IWL_UCODE_TLV_PNVM_SKU payload after only checking that the generic TLV
payload is present.

A short type-specific payload can therefore make the three data[] reads
extend beyond the TLV. Reject SKU TLVs shorter than the structure before
accessing it.

Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
Changes since v1: https://lore.kernel.org/all/2026063008044943.4-ccfa108-0019-wifi-iwlwifi-validate-PNVM--pengpeng@iscas.ac.cn/
- use sizeof(*tlv_sku_id) as requested by Miri Korenblit
---
 drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
index afff8d5..6daa5cc 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
@@ -198,6 +198,12 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data,
 			IWL_DEBUG_FW(trans,
 				     "Got IWL_UCODE_TLV_PNVM_SKU len %d\n",
 				     tlv_len);
+			if (tlv_len < sizeof(*tlv_sku_id)) {
+				IWL_ERR(trans, "invalid PNVM SKU TLV len: %u\n",
+					tlv_len);
+				return -EINVAL;
+			}
+
 			IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n",
 				     le32_to_cpu(tlv_sku_id->data[0]),
 				     le32_to_cpu(tlv_sku_id->data[1]),
-- 
2.50.1 (Apple Git-155)



^ permalink raw reply related

* [PATCH wireless] wifi: at76c50x-usb: avoid length underflow in at76_guess_freq()
From: Huihui Huang @ 2026-07-15 14:08 UTC (permalink / raw)
  To: linux-wireless; +Cc: Huihui Huang, Johannes Berg, Johan Hovold

at76_guess_freq() checks only that the received frame is at least a bare
802.11 header (24 bytes) before subtracting the fixed management-body
offset:

	len -= el_off;

For both beacon and probe response frames, el_off is 36. If the frame is
shorter than el_off, subtracting it causes the calculated IE length to
wrap. The length is eventually passed to cfg80211_find_elem_match() as a
very large unsigned value, so the element walk runs beyond the RX skb.

This path is reached from at76_rx_tasklet() while scanning. If the device
delivers a truncated beacon or probe response, the oversized IE length
causes an out-of-bounds read during scanning.

Skip the IE lookup if the frame does not reach the variable elements,
before subtracting el_off.

Fixes: 1264b951463a ("at76c50x-usb: add driver")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Huihui Huang <hhhuang@smu.edu.sg>
---

Tested on wireless.git commit a0d82fb85053 with KASAN and a temporary
KUnit test calling at76_guess_freq() with a 30-byte beacon skb while
scanning.

Before:
  BUG: KASAN: slab-out-of-bounds in cfg80211_find_elem_match

After:
  ok 1 at76_guess_freq_short_frame_test
  No KASAN reports.

 drivers/net/wireless/atmel/at76c50x-usb.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c
index 32e3e09e7680..d9c2809be4ba 100644
--- a/drivers/net/wireless/atmel/at76c50x-usb.c
+++ b/drivers/net/wireless/atmel/at76c50x-usb.c
@@ -1521,13 +1521,16 @@ static inline int at76_guess_freq(struct at76_priv *priv)

 	if (ieee80211_is_probe_resp(hdr->frame_control)) {
 		el_off = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
-		el = ((struct ieee80211_mgmt *)hdr)->u.probe_resp.variable;
 	} else if (ieee80211_is_beacon(hdr->frame_control)) {
 		el_off = offsetof(struct ieee80211_mgmt, u.beacon.variable);
-		el = ((struct ieee80211_mgmt *)hdr)->u.beacon.variable;
 	} else {
 		goto exit;
 	}
+
+	if (len < el_off)
+		goto exit;
+
+	el = priv->rx_skb->data + el_off;
 	len -= el_off;

 	el = cfg80211_find_ie(WLAN_EID_DS_PARAMS, el, len);

base-commit: a0d82fb8505326cbc53dc9a0c08f97d11197bb30
--
2.50.1

^ permalink raw reply related

* Re: [PATCH] wifi: mwifiex: validate rate scope TLV length
From: Francesco Dolcini @ 2026-07-15 14:01 UTC (permalink / raw)
  To: Pengpeng Hou
  Cc: Brian Norris, Francesco Dolcini, Kees Cook, linux-wireless,
	linux-kernel
In-Reply-To: <20260706091346.76985-1-pengpeng@iscas.ac.cn>

On Mon, Jul 06, 2026 at 05:13:46PM +0800, Pengpeng Hou wrote:
> From: Pengpeng <pengpeng@iscas.ac.cn>
> 
> mwifiex_ret_tx_rate_cfg() verifies that a TLV stays within the command
> response, then parses RATE_SCOPE as struct mwifiex_rate_scope. The
> type-specific parser also needs to prove that the declared TLV payload
> covers the bitmap fields that it reads.
> 
> Check the RATE_SCOPE payload length before copying the legacy bitmaps,
> and require the VHT bitmap area only for firmware API version 15 where
> it is consumed.
> 
> Signed-off-by: Pengpeng <pengpeng@iscas.ac.cn>

Is this change tested? On which device? How?

Francesco


^ permalink raw reply

* [PATCH v2] wifi: mwifiex: bound uAP association event IEs to the event buffer
From: HE WEI (ギカク) @ 2026-07-15 13:57 UTC (permalink / raw)
  To: Brian Norris
  Cc: Francesco Dolcini, Miri Korenblit, Johannes Berg, Kees Cook,
	Kalle Valo, linux-wireless, linux-kernel,
	HE WEI (ギカク)

mwifiex_process_uap_event() handles EVENT_UAP_STA_ASSOC by exposing the
(re)association request IEs that the firmware copies into the event:

	sinfo->assoc_req_ies = &event->data[len];
	len = (u8 *)sinfo->assoc_req_ies - (u8 *)&event->frame_control;
	sinfo->assoc_req_ies_len = le16_to_cpu(event->len) - (u16)len;

event->len is supplied by the device firmware and is never validated,
and the subtraction is unchecked.  assoc_req_ies points into
adapter->event_body[MAX_EVENT_SIZE], a fixed-size array embedded in the
kmalloc()'d struct mwifiex_adapter.

On the ap_11n_enabled path mwifiex_set_sta_ht_cap() walks these IEs with
cfg80211_find_ie(), whose for_each_element() loop dereferences each
element header.  A firmware-reported event->len larger than the bytes
actually received makes assoc_req_ies_len describe IEs that extend past
event_body, so the walk reads out of the adapter slab object, a
slab-out-of-bounds read (KASAN: slab-out-of-bounds in cfg80211_find_ie).
An event->len smaller than the header instead makes the int subtraction
negative, which wraps to a huge size_t when stored in assoc_req_ies_len.
The same length is handed to cfg80211_new_sta(), so a more modest
over-claim can also copy stale event_body bytes into the
NL80211_CMD_NEW_STATION notification.

A malicious or malfunctioning mwifiex device (USB/SDIO/PCIe) can deliver
such an event while the interface is in AP/uAP mode.

Validate event->len before use: reject a length that underflows the
header or that would place the IEs outside the event_body[] buffer the
event was copied into.  event->len here is struct mwifiex_assoc_event.len,
a payload field internal to this event, not the transport frame length,
so it is validated in this handler rather than at the generic
MWIFIEX_TYPE_EVENT receive path, which only sees the event cause and the
transport frame length.  The bound is against event_body[MAX_EVENT_SIZE]
rather than the actually-received length because the transports store the
event differently (USB and SDIO leave the 4-byte event header in
event_skb, PCIe strips it via skb_pull), whereas event_body is the single
fixed buffer all of them copy the event into.  This is the event-path
analogue of the receive-path bounds checks added in commit 119585281617
("wifi: mwifiex: Fix OOB and integer underflow when rx packets").

Fixes: e568634ae7ac ("mwifiex: add AP event handling framework")
Signed-off-by: HE WEI (ギカク) <skyexpoc@gmail.com>
---
v2: fold le16_to_cpu(event->len) into a local evt_len as requested, which
    also shortens the bounds check.  No functional change.

 .../net/wireless/marvell/mwifiex/uap_event.c  | 24 +++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/uap_event.c b/drivers/net/wireless/marvell/mwifiex/uap_event.c
index 679fdae0f001..ba1bdbbff687 100644
--- a/drivers/net/wireless/marvell/mwifiex/uap_event.c
+++ b/drivers/net/wireless/marvell/mwifiex/uap_event.c
@@ -123,11 +123,31 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
 				len = ETH_ALEN;
 
 			if (len != -1) {
+				u16 evt_len = le16_to_cpu(event->len);
+
 				sinfo->assoc_req_ies = &event->data[len];
 				len = (u8 *)sinfo->assoc_req_ies -
 				      (u8 *)&event->frame_control;
-				sinfo->assoc_req_ies_len =
-					le16_to_cpu(event->len) - (u16)len;
+
+				/*
+				 * event->len is reported by the device firmware
+				 * and is not otherwise validated.  Reject a
+				 * length that underflows the header, or that
+				 * would place the association request IEs
+				 * outside the fixed-size event_body[] buffer the
+				 * event was copied into; otherwise the IE walk
+				 * in mwifiex_set_sta_ht_cap() reads past
+				 * event_body and out of the adapter slab object.
+				 */
+				if (evt_len < len ||
+				    (u8 *)&event->frame_control + evt_len >
+				    adapter->event_body + MAX_EVENT_SIZE) {
+					mwifiex_dbg(adapter, ERROR,
+						    "invalid STA assoc event length\n");
+					kfree(sinfo);
+					return -1;
+				}
+				sinfo->assoc_req_ies_len = evt_len - (u16)len;
 			}
 		}
 		cfg80211_new_sta(priv->netdev->ieee80211_ptr, event->sta_addr,
-- 
2.54.0


^ permalink raw reply related


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