Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH v2 iwlwifi-next 12/15] wifi: iwlwifi: api: clean up/fix some kernel-doc references
From: Miri Korenblit @ 2026-05-15 12:09 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260515120948.1157329-1-miriam.rachel.korenblit@intel.com>

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

Some of these structs just don't exist (any more), or other
versions should be referenced, clean that up.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/fw/api/commands.h | 7 +++----
 drivers/net/wireless/intel/iwlwifi/fw/api/location.h | 7 ++++---
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
index 24bac3f00310..abd259350589 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
@@ -57,8 +57,7 @@ enum iwl_legacy_cmds {
 	/**
 	 * @UCODE_ALIVE_NTFY:
 	 * Alive data from the firmware, as described in
-	 * &struct iwl_alive_ntf_v3 or &struct iwl_alive_ntf_v4 or
-	 * &struct iwl_alive_ntf_v5 or &struct iwl_alive_ntf_v7.
+	 * &struct iwl_alive_ntf_v3 or &struct iwl_alive_ntf_v7.
 	 */
 	UCODE_ALIVE_NTFY = 0x1,
 
@@ -384,7 +383,7 @@ enum iwl_legacy_cmds {
 	 * @STATISTICS_NOTIFICATION:
 	 * one of &struct iwl_notif_statistics_v10,
 	 * &struct iwl_notif_statistics_v11,
-	 * &struct iwl_notif_statistic,
+	 * &struct iwl_notif_statistics,
 	 * &struct iwl_statistics_operational_ntfy_ver_14
 	 * &struct iwl_statistics_operational_ntfy
 	 */
@@ -558,7 +557,7 @@ enum iwl_legacy_cmds {
 	WOWLAN_CONFIGURATION = 0xe1,
 
 	/**
-	 * @WOWLAN_TSC_RSC_PARAM: &struct iwl_wowlan_rsc_tsc_params_cmd_v4,
+	 * @WOWLAN_TSC_RSC_PARAM: &struct iwl_wowlan_rsc_tsc_params_cmd_ver_2,
 	 *	&struct iwl_wowlan_rsc_tsc_params_cmd
 	 */
 	WOWLAN_TSC_RSC_PARAM = 0xe2,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h
index 2ee3a48aa5df..d3f774ffacde 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h
@@ -2,7 +2,7 @@
 /*
  * Copyright (C) 2015-2017 Intel Deutschland GmbH
  * Copyright (C) 2018-2022 Intel Corporation
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
  */
 #ifndef __iwl_fw_api_location_h__
 #define __iwl_fw_api_location_h__
@@ -81,8 +81,9 @@ enum iwl_location_subcmd_ids {
 	 * @TOF_RANGE_RESPONSE_NOTIF: ranging response, using one of
 	 *	&struct iwl_tof_range_rsp_ntfy_v5,
 	 *	&struct iwl_tof_range_rsp_ntfy_v6,
-	 *	&struct iwl_tof_range_rsp_ntfy_v7 or
-	 *	&struct iwl_tof_range_rsp_ntfy_v8
+	 *	&struct iwl_tof_range_rsp_ntfy_v7,
+	 *	&struct iwl_tof_range_rsp_ntfy_v9 or
+	 *	&struct iwl_tof_range_rsp_ntfy
 	 */
 	TOF_RANGE_RESPONSE_NOTIF = 0xFF,
 };
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 iwlwifi-next 13/15] wifi: iwlwifi: pcie: add two LNL PCI IDs
From: Miri Korenblit @ 2026-05-15 12:09 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260515120948.1157329-1-miriam.rachel.korenblit@intel.com>

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

Add two PCI IDs for two WiFi-7 BE1735x Killer devices (these
are CRFs) so they work when put into the LNL platform.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index fdafbad506a7..b0c59181907e 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -537,6 +537,8 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct pci_device_id iwl_hw_card_ids[] = {
 	{IWL_PCI_DEVICE(0xA840, 0x4314, iwl_bz_mac_cfg)},
 	{IWL_PCI_DEVICE(0xA840, 0x1775, iwl_bz_mac_cfg)},
 	{IWL_PCI_DEVICE(0xA840, 0x1776, iwl_bz_mac_cfg)},
+	{IWL_PCI_DEVICE(0xA840, 0x1735, iwl_bz_mac_cfg)},
+	{IWL_PCI_DEVICE(0xA840, 0x1736, iwl_bz_mac_cfg)},
 	{IWL_PCI_DEVICE(0x7740, PCI_ANY_ID, iwl_bz_mac_cfg)},
 	{IWL_PCI_DEVICE(0x4D40, PCI_ANY_ID, iwl_bz_mac_cfg)},
 
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 iwlwifi-next 14/15] wifi: iwlwifi: mld: expose beacon avg signal
From: Miri Korenblit @ 2026-05-15 12:09 UTC (permalink / raw)
  To: linux-wireless; +Cc: Shahar Tzarfati
In-Reply-To: <20260515120948.1157329-1-miriam.rachel.korenblit@intel.com>

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

Store beacon_average_energy from per-link FW statistics and expose it
via station_info as rx_beacon_signal_avg in sta statistics.

This fixes missing beacon average signal reporting to upper layers.

Signed-off-by: Shahar Tzarfati <shahar.tzarfati@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/link.h |  3 ++
 .../net/wireless/intel/iwlwifi/mld/stats.c    | 47 ++++++++++++++++++-
 2 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.h b/drivers/net/wireless/intel/iwlwifi/mld/link.h
index 4527f054ce92..0b3974d86531 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/link.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/link.h
@@ -36,6 +36,8 @@ struct iwl_probe_resp_data {
  * @rcu_head: RCU head for freeing this data.
  * @fw_id: the fw id of the link.
  * @active: if the link is active or not.
+ * @avg_signal: The current average signal of beacons [dBm] retrieved from
+ *	firmware per-link periodic stats (STATISTICS_OPER_NOTIF).
  * @queue_params: QoS data from mac80211. This is updated with a call to
  *	drv_conf_tx per each AC, and then notified once with BSS_CHANGED_QOS.
  *	So we store it here and then send one link cmd for all the ACs.
@@ -68,6 +70,7 @@ struct iwl_mld_link {
 	struct_group(zeroed_on_hw_restart,
 		u8 fw_id;
 		bool active;
+		s8 avg_signal;
 		struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
 		struct ieee80211_chanctx_conf __rcu *chan_ctx;
 		bool he_ru_2mhz_block;
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/stats.c b/drivers/net/wireless/intel/iwlwifi/mld/stats.c
index b93e0f8ab5fb..e7b283cbe199 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/stats.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/stats.c
@@ -311,6 +311,40 @@ static void iwl_mld_sta_stats_fill_txrate(struct iwl_mld_sta *mld_sta,
 	}
 }
 
+static void iwl_mld_sta_stats_fill_beacon_signal_avg(struct ieee80211_vif *vif,
+						     struct station_info *sinfo)
+{
+	struct ieee80211_bss_conf *link_conf;
+	struct iwl_mld_link *link;
+	u8 link_id;
+
+	if (iwl_mld_emlsr_active(vif))
+		return;
+
+	/* TODO: support statistics for NAN */
+	if (vif->type == NL80211_IFTYPE_NAN ||
+	    vif->type == NL80211_IFTYPE_NAN_DATA)
+		return;
+
+	link_id = iwl_mld_get_primary_link(vif);
+	link_conf = link_conf_dereference_protected(vif, link_id);
+
+	if (WARN_ONCE(!link_conf,
+		      "link_conf is NULL for link_id=%u\n", link_id))
+		return;
+
+	link = iwl_mld_link_from_mac80211(link_conf);
+	if (WARN_ONCE(!link,
+		      "iwl_mld_link is NULL for link_id=%u\n", link_id))
+		return;
+
+	if (!link->avg_signal)
+		return;
+
+	sinfo->rx_beacon_signal_avg = link->avg_signal;
+	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG);
+}
+
 void iwl_mld_mac80211_sta_statistics(struct ieee80211_hw *hw,
 				     struct ieee80211_vif *vif,
 				     struct ieee80211_sta *sta,
@@ -329,9 +363,9 @@ void iwl_mld_mac80211_sta_statistics(struct ieee80211_hw *hw,
 
 	iwl_mld_sta_stats_fill_txrate(mld_sta, sinfo);
 
-	/* TODO: NL80211_STA_INFO_BEACON_RX */
+	iwl_mld_sta_stats_fill_beacon_signal_avg(vif, sinfo);
 
-	/* TODO: NL80211_STA_INFO_BEACON_SIGNAL_AVG */
+	/* TODO: NL80211_STA_INFO_BEACON_RX */
 }
 
 #define IWL_MLD_TRAFFIC_LOAD_MEDIUM_THRESH	10 /* percentage */
@@ -443,6 +477,8 @@ iwl_mld_process_per_link_stats(struct iwl_mld *mld,
 	     fw_id++) {
 		const struct iwl_stats_ntfy_per_link *link_stats;
 		struct ieee80211_bss_conf *bss_conf;
+		struct iwl_mld_link *link;
+		u32 avg_raw;
 		int sig;
 
 		bss_conf = iwl_mld_fw_id_to_link_conf(mld, fw_id);
@@ -456,6 +492,13 @@ iwl_mld_process_per_link_stats(struct iwl_mld *mld,
 		sig = -le32_to_cpu(link_stats->beacon_filter_average_energy);
 		iwl_mld_update_link_sig(bss_conf->vif, sig, bss_conf);
 
+		link = iwl_mld_link_from_mac80211(bss_conf);
+		if (WARN_ON_ONCE(!link))
+			continue;
+
+		avg_raw = le32_to_cpu(link_stats->beacon_average_energy);
+		link->avg_signal = clamp_t(int, -(int)avg_raw, S8_MIN, 0);
+
 		/* TODO: parse more fields here (task=statistics)*/
 	}
 
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 iwlwifi-next 15/15] wifi: iwlwifi: mld: disallow puncturing in US/CA for WH
From: Miri Korenblit @ 2026-05-15 12:09 UTC (permalink / raw)
  To: linux-wireless; +Cc: Pagadala Yesu Anjaneyulu, Emmanuel Grumbach
In-Reply-To: <20260515120948.1157329-1-miriam.rachel.korenblit@intel.com>

From: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>

FM continues to follow the BIOS/MCC policy, while WH sets
DISALLOW_PUNCTURING for US/CA and clears it for other MCC values.
Update the MCC handling accordingly.

Signed-off-by: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/mcc.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mcc.c b/drivers/net/wireless/intel/iwlwifi/mld/mcc.c
index 16bb1b4904f9..8502129abe49 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mcc.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mcc.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
  */
 
 #include <net/cfg80211.h>
@@ -129,7 +129,7 @@ iwl_mld_get_regdomain(struct iwl_mld *mld,
 
 	mld->mcc_src = resp->source_id;
 
-	/* FM is the earliest supported and later always do puncturing */
+	/* FM follows BIOS/MCC policy, WH disallows puncturing only in US/CA. */
 	if (CSR_HW_RFID_TYPE(mld->trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_FM) {
 		if (!iwl_puncturing_is_allowed_in_bios(mld->bios_enable_puncturing,
 						       le16_to_cpu(resp->mcc)))
@@ -137,6 +137,15 @@ iwl_mld_get_regdomain(struct iwl_mld *mld,
 		else
 			__clear_bit(IEEE80211_HW_DISALLOW_PUNCTURING,
 				    mld->hw->flags);
+	} else if (CSR_HW_RFID_TYPE(mld->trans->info.hw_rf_id) ==
+			IWL_CFG_RF_TYPE_WH) {
+		u16 mcc = le16_to_cpu(resp->mcc);
+
+		if (mcc == IWL_MCC_US || mcc == IWL_MCC_CANADA)
+			ieee80211_hw_set(mld->hw, DISALLOW_PUNCTURING);
+		else
+			__clear_bit(IEEE80211_HW_DISALLOW_PUNCTURING,
+				    mld->hw->flags);
 	}
 
 out:
-- 
2.34.1


^ permalink raw reply related

* [PATCH 0/4] wifi: iwlwifi: harden netdetect resume-path parsing against firmware-controlled inputs (mvm + mld)
From: Michael Bommarito @ 2026-05-15 12:10 UTC (permalink / raw)
  To: Miri Korenblit
  Cc: Johannes Berg, Emmanuel Grumbach, linux-wireless, linux-kernel,
	stable

Four defensive bound-check additions on the WoWLAN net-detect
resume path in iwlwifi, validating firmware-controlled response
lengths and bitmap-bit positions at the host/firmware trust
boundary. Two patches each in the mvm and mld op-modes; both
op-modes are live in current kernels (mvm drives 7000-series
through pre-BE200 hardware; mld drives Wi-Fi 7 / BE200+ when
CONFIG_IWLMLD is enabled).

The series is in the same shape as the recently fixed sibling
commit 744fabc338e8 ("wifi: iwlwifi: mvm: fix potential
out-of-bounds read in iwl_mvm_nd_match_info_handler()"), which
landed in stable on 2026-04-11. Well-behaved firmware should not
trigger any of these, but the host parser should not depend on
that.

Patches 1 + 3: length-tail guard on the firmware response.
iwl_mvm_netdetect_query_results() and
iwl_mld_netdetect_match_info_handler() validate only the fixed
header size of the response/notification, then memcpy the flex-
array tail unconditionally. A response of exactly query_len /
sizeof(*notif) bytes passes the guard and the memcpy reads
matches_len / NETDETECT_QUERY_BUF_LEN bytes of adjacent slab
content. KASAN reports the slab-out-of-bounds READ "0 bytes to
the right of the allocated 24-byte region" in the kmalloc-32
cache. Same fix shape as the sibling.

Patches 2 + 4: clamp the channel-iteration upper bound against
the netdetect channels-table length. iwl_mvm_query_set_freqs()
and iwl_mld_set_netdetect_info() iterate the per-match
matching_channels[] bitmap and index a channels[] pointer table
by bit position, without bounding the bit positions against
the table length. The pre-existing caller-side guards compare
popcount to table length, not bit position to table length. The
mvm path iterates over the full 0..55 bit range; the mld path
is accidentally bounded to 0..6 by a bits-vs-bytes confusion
(for_each_set_bit() takes bits, but the call passes sizeof(...)
which is 7 bytes). Both can index past the channels[] allocation
when the user's net-detect configuration has fewer channels than
the relevant bound. The wild-pointer dereference of
channels[j]->center_freq inside the resume work-queue then page-
faults the kernel; a KUnit harness exercising the mvm shape
panics with

  Kernel panic - not syncing: Segfault with no mm

and the mld shape panics identically when n_channels < 7. The
mld fix folds the bits-vs-bytes correction together with the
clamp because applying only the bits-correction without the
clamp would widen the OOB exposure from j < 7 to j < 56.

All four bugs require the firmware to produce inputs outside the
implied driver contract: a short response (patches 1, 3), or
matching_channels[] bits set at positions outside the channels-
table bound (patches 2, 4). Well-behaved firmware should not do
either. The patches add defensive validation at a trust boundary;
they are not a claim that current Intel firmware misbehaves.

Reproducer: self-contained KUnit suite that lifts all four buggy
code paths into standalone harnesses (no firmware or hardware
dependency, ~10s on UML). Patched-shape subtests pass cleanly
under the proposed fixes (test_patched_rejects_short,
test_patched_accepts_full, test_set_freqs_patched_clamps,
test_mld_match_info_patched_rejects_short,
test_mld_set_freqs_patched_clamps).

All four patches build clean under x86_64 allmodconfig with no
new warnings; checkpatch --strict reports 0/0/0 on each.

Michael Bommarito (4):
  wifi: iwlwifi: mvm: include matches_len in scan-offload-query length
    check
  wifi: iwlwifi: mvm: clamp set_freqs iteration to n_nd_channels
  wifi: iwlwifi: mld: include matches tail in match-info length check
  wifi: iwlwifi: mld: clamp netdetect channel iteration to n_channels

 drivers/net/wireless/intel/iwlwifi/mld/d3.c | 20 +++++++++++++++-----
 drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 10 +++++++---
 2 files changed, 22 insertions(+), 8 deletions(-)

--
2.53.0


^ permalink raw reply

* [PATCH 1/4] wifi: iwlwifi: mvm: include matches_len in scan-offload-query length check
From: Michael Bommarito @ 2026-05-15 12:10 UTC (permalink / raw)
  To: Miri Korenblit
  Cc: Johannes Berg, Emmanuel Grumbach, linux-wireless, linux-kernel,
	stable
In-Reply-To: <20260515121100.649334-1-michael.bommarito@gmail.com>

iwl_mvm_netdetect_query_results() validates the firmware response
length against query_len (the fixed-header size of struct
iwl_scan_offload_match_info or iwl_scan_offload_profiles_query_v1)
but immediately follows with:

	memcpy(results->matches, query->matches, matches_len);

where matches_len is

	sizeof(struct iwl_scan_offload_profile_match[_v1]) *
		iwl_umac_scan_get_max_profiles(mvm->fw)

and is not included in the guard. A firmware response of exactly
query_len bytes therefore satisfies the guard yet the memcpy
reads matches_len bytes past the end of the slab-allocated
firmware-response buffer. The worst-case extent depends on the
firmware path:

  - v2 layout, SCAN_OFFLOAD_UPDATE_PROFILES_CMD version unknown
    or < 3: matches_len = 18 * IWL_SCAN_MAX_PROFILES = 198 bytes.
  - v2 layout, command version >= 3:
    matches_len = 18 * IWL_SCAN_MAX_PROFILES_V2 = 144 bytes.
  - v1 layout: matches_len = 16 * IWL_SCAN_MAX_PROFILES = 176 bytes.

Reproduced under UML+KASAN via a KUnit harness that lifts the
length-validation + memcpy logic into a self-contained test.
With the response sized at the v2 query_len (24 bytes of
match-info header) and the older-firmware max_profiles path,
KASAN reports a slab-out-of-bounds READ of 198 bytes at 0 bytes
to the right of a 24-byte allocation in the kmalloc-32 cache.
Building drivers/net/wireless/intel/iwlwifi/mvm/d3.o under
x86_64 allmodconfig with the fix applied yields no new warnings.

The sibling fix iwl_mvm_nd_match_info_handler() was corrected
by commit 744fabc338e8 ("wifi: iwlwifi: mvm: fix potential
out-of-bounds read in iwl_mvm_nd_match_info_handler()"). The
present function was missed during that audit; apply the same
correction shape.

Cc: stable@vger.kernel.org
Fixes: e4fe5d4b10cd ("iwlwifi: mvm: Support new format of SCAN_OFFLOAD_PROFILES_QUERY_RSP")
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
---
 drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 9a74f60c9185..c17ac62feec3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -2458,7 +2458,7 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm,
 	}
 
 	len = iwl_rx_packet_payload_len(cmd.resp_pkt);
-	if (len < query_len) {
+	if (len < query_len + matches_len) {
 		IWL_ERR(mvm, "Invalid scan offload profiles query response!\n");
 		ret = -EIO;
 		goto out_free_resp;
-- 
2.53.0


^ permalink raw reply related

* [PATCH 2/4] wifi: iwlwifi: mvm: clamp set_freqs iteration to n_nd_channels
From: Michael Bommarito @ 2026-05-15 12:10 UTC (permalink / raw)
  To: Miri Korenblit
  Cc: Johannes Berg, Emmanuel Grumbach, linux-wireless, linux-kernel,
	stable
In-Reply-To: <20260515121100.649334-1-michael.bommarito@gmail.com>

iwl_mvm_query_set_freqs() iterates over bit positions
0 .. SCAN_OFFLOAD_MATCHING_CHANNELS_LEN * 8 - 1 (= 0..55 on the v2
path, 0..39 on the v1 path) and, for each set bit, performs:

	match->channels[n_channels++] =
		mvm->nd_channels[i]->center_freq;

without constraining i against mvm->n_nd_channels. The pointer
table mvm->nd_channels is kmemdup()ed at suspend time with
exactly mvm->n_nd_channels entries (whatever the userspace
NL80211_CMD_SET_WOWLAN request supplied as
nd_config->n_channels; typical real-world values are 5..50).
If the firmware response contains any matching_channels[] bit
set at a position >= mvm->n_nd_channels, the indexed load reads
a u8* slot past the end of the pointer-table allocation, then
the immediate ->center_freq dereferences that wild pointer.

The pre-existing caller guard

	if (mvm->n_nd_channels < n_channels)
		continue;

compares the bitmap's popcount to the table length, not the bit
positions to the table length. A bitmap with three set bits at
positions {50, 51, 52} has popcount 3 and passes the guard
unconditionally, then walks 50+ entries off the end of
mvm->nd_channels.

Reproduced under UML+KASAN via a KUnit harness that lifts the
iteration logic. With nd_channels allocated as 5 entries and
matching_channels bits set at positions 7 (immediate redzone)
and 50 (far OOB), the kernel panics on the wild deref:

  Kernel panic - not syncing: Segfault with no mm
  RIP: 0033:set_freqs_buggy.constprop.0+0xc1/0x15e

(The selector 0x0033 in the RIP line is UML's user-mode segment;
under UML, in-kernel code runs in ring 3 on the host. The trap
is a kernel-context page fault on the wild-pointer deref.)

Building drivers/net/wireless/intel/iwlwifi/mvm/d3.o under
x86_64 allmodconfig with the fix applied yields no new warnings.

Clamp the iteration upper bound to min(matching-bits-width,
mvm->n_nd_channels) so high-position bits, however the firmware
emitted them, cannot index past the pointer table. Mirror the
fix for the v1 fallback arm.

Cc: stable@vger.kernel.org
Fixes: 8ed4e659f34c ("iwlwifi: mvm: add channel information to the netdetect notifications")
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
---
 drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index c17ac62feec3..b04d8dd26cd0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -2514,16 +2514,20 @@ static void iwl_mvm_query_set_freqs(struct iwl_mvm *mvm,
 		       IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) {
 		struct iwl_scan_offload_profile_match *matches =
 			 (void *)results->matches;
+		int max = min_t(int, SCAN_OFFLOAD_MATCHING_CHANNELS_LEN * 8,
+				mvm->n_nd_channels);
 
-		for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN * 8; i++)
+		for (i = 0; i < max; i++)
 			if (matches[idx].matching_channels[i / 8] & (BIT(i % 8)))
 				match->channels[n_channels++] =
 					mvm->nd_channels[i]->center_freq;
 	} else {
 		struct iwl_scan_offload_profile_match_v1 *matches =
 			 (void *)results->matches;
+		int max = min_t(int, SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V1 * 8,
+				mvm->n_nd_channels);
 
-		for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V1 * 8; i++)
+		for (i = 0; i < max; i++)
 			if (matches[idx].matching_channels[i / 8] & (BIT(i % 8)))
 				match->channels[n_channels++] =
 					mvm->nd_channels[i]->center_freq;
-- 
2.53.0


^ permalink raw reply related

* [PATCH 3/4] wifi: iwlwifi: mld: include matches tail in match-info length check
From: Michael Bommarito @ 2026-05-15 12:10 UTC (permalink / raw)
  To: Miri Korenblit
  Cc: Johannes Berg, Emmanuel Grumbach, linux-wireless, linux-kernel,
	stable
In-Reply-To: <20260515121100.649334-1-michael.bommarito@gmail.com>

iwl_mld_netdetect_match_info_handler() validates the firmware
notification length against sizeof(*notif) (the fixed-header
size of struct iwl_scan_offload_match_info, 24 bytes) but then
immediately memcpys NETDETECT_QUERY_BUF_LEN bytes from
notif->matches:

	if (IWL_FW_CHECK(mld, len < sizeof(*notif),
			 "Invalid scan offload match notif of length: %d\n",
			 len))
		return true;
	...
	if (results->matched_profiles)
		memcpy(results->matches, notif->matches,
		       NETDETECT_QUERY_BUF_LEN);

NETDETECT_QUERY_BUF_LEN is

	(sizeof(struct iwl_scan_offload_profile_match) *
	 IWL_SCAN_MAX_PROFILES_V2)
	= 18 * 8 = 144 bytes

so a firmware-emitted notif sized at exactly sizeof(*notif)
(24 bytes) satisfies the guard yet the memcpy reads 144 bytes
past the slab-allocated notification buffer.

Reproduced under UML+KASAN via a KUnit harness that lifts the
length-validation + memcpy logic into a self-contained test.
KASAN reports

  BUG: KASAN: slab-out-of-bounds in mld_match_info_buggy.constprop.0
  Read of size 144 at addr ...

Building drivers/net/wireless/intel/iwlwifi/mld/d3.o under
x86_64 allmodconfig with the fix applied yields no new warnings.

This is the same bug shape as the previously fixed sibling
commit 744fabc338e8 ("wifi: iwlwifi: mvm: fix potential
out-of-bounds read in iwl_mvm_nd_match_info_handler()") applied
to the mvm peer function. The mld driver was added in February
2025 and inherited the same length-check miss; apply the same
correction shape.

Cc: stable@vger.kernel.org
Fixes: d1e879ec600f ("wifi: iwlwifi: add iwlmld sub-driver")
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
---
 drivers/net/wireless/intel/iwlwifi/mld/d3.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
index ef98efc8fb1b..e89ec531cb06 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
@@ -1128,7 +1128,7 @@ iwl_mld_netdetect_match_info_handler(struct iwl_mld *mld,
 			 mld->netdetect))
 		return true;
 
-	if (IWL_FW_CHECK(mld, len < sizeof(*notif),
+	if (IWL_FW_CHECK(mld, len < sizeof(*notif) + NETDETECT_QUERY_BUF_LEN,
 			 "Invalid scan offload match notif of length: %d\n",
 			 len))
 		return true;
-- 
2.53.0


^ permalink raw reply related

* [PATCH 4/4] wifi: iwlwifi: mld: clamp netdetect channel iteration to n_channels
From: Michael Bommarito @ 2026-05-15 12:11 UTC (permalink / raw)
  To: Miri Korenblit
  Cc: Johannes Berg, Emmanuel Grumbach, linux-wireless, linux-kernel,
	stable
In-Reply-To: <20260515121100.649334-1-michael.bommarito@gmail.com>

iwl_mld_set_netdetect_info() walks the per-match matching_channels[]
bitmap and emits one center_freq per set bit by indexing
netdetect_cfg->channels[]:

	for_each_set_bit(j,
			 (unsigned long *)&matches[i].matching_channels[0],
			 sizeof(matches[i].matching_channels)) {
		match->channels[match->n_channels] =
			netdetect_cfg->channels[j]->center_freq;
		match->n_channels++;
	}

Two problems here.

First, the third argument to for_each_set_bit(bit, addr, size) is
the number of BITS to walk, not bytes.
sizeof(matches[i].matching_channels) is
SCAN_OFFLOAD_MATCHING_CHANNELS_LEN = 7 BYTES, so the macro only
visits j = 0..6 and silently misses bits 7..55 of the 56-bit
bitmap. This is a functional defect (per-match channel reporting
is truncated to the first 7 entries of the bitmap).

Second, the loop body indexes netdetect_cfg->channels[j] without
bounding j against netdetect_cfg->n_channels. netdetect_cfg
->channels is a kmemdup()'ed array of pointers sized at exactly
n_channels entries (the user's WoWLAN net-detect channel list).
If n_channels < 7 (a 2.4 GHz only configuration, or a small saved-
SSID channel allowlist) and the firmware sets a match bit at any
position in [n_channels, 6], the indexed load reads past the end
of the allocation, and ->center_freq then dereferences whatever
that wild pointer fetched.

Reproduced under UML+KASAN via a KUnit harness that lifts the
iteration logic. With netdetect_cfg->channels sized at 5 entries
and matching_channels bit 5 set, the kernel panics on the wild
deref:

  Kernel panic - not syncing: Segfault with no mm
  RIP: 0033:mld_set_freqs_buggy.constprop.0+0x116/0x1c2

(The selector 0x0033 is UML's user-mode segment; under UML,
in-kernel code runs in ring 3 on the host. The trap is a
kernel-context page fault on the wild-pointer deref.)

Building drivers/net/wireless/intel/iwlwifi/mld/d3.o under
x86_64 allmodconfig with the fix applied yields no new warnings.

Rewrite the iteration as an explicit indexed loop with an upper
bound of min(bitmap-width-in-bits, n_channels). This addresses
both issues in one step: bits-correct iteration over the bitmap,
and a hard clamp against the channels-table length. Address the
two together because applying only the bits-correct iteration
without the clamp would widen the OOB exposure from j < 7 to
j < 56.

A short comment is added because the clamp's purpose (avoiding an
OOB pointer fetch from netdetect_cfg->channels) is not obvious
from the expression alone, and a future reader could otherwise
"simplify" the bound back to the underlying constant.

Cc: stable@vger.kernel.org
Fixes: d1e879ec600f ("wifi: iwlwifi: add iwlmld sub-driver")
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
---
 drivers/net/wireless/intel/iwlwifi/mld/d3.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
index e89ec531cb06..51abf414bb1e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
@@ -1165,7 +1165,7 @@ iwl_mld_set_netdetect_info(struct iwl_mld *mld,
 
 	for_each_set_bit(i, &matched_profiles, netdetect_cfg->n_match_sets) {
 		struct cfg80211_wowlan_nd_match *match;
-		int idx, j, n_channels = 0;
+		int idx, j, max, n_channels = 0;
 		struct iwl_scan_offload_profile_match *matches =
 			(void *)netdetect_res->matches;
 
@@ -1192,9 +1192,19 @@ iwl_mld_set_netdetect_info(struct iwl_mld *mld,
 		if (netdetect_cfg->n_channels < n_channels)
 			continue;
 
-		for_each_set_bit(j,
-				 (unsigned long *)&matches[i].matching_channels[0],
-				 sizeof(matches[i].matching_channels)) {
+		/* Clamp bit-index iteration to the channels table length:
+		 * a firmware-set bit past n_channels would otherwise index
+		 * past the kmemdup'd netdetect_cfg->channels[] allocation.
+		 */
+		max = min_t(int, BITS_PER_BYTE *
+			    sizeof(matches[i].matching_channels),
+			    netdetect_cfg->n_channels);
+
+		for (j = 0; j < max; j++) {
+			if (!(matches[i].matching_channels[j / BITS_PER_BYTE] &
+			      BIT(j % BITS_PER_BYTE)))
+				continue;
+
 			match->channels[match->n_channels] =
 				netdetect_cfg->channels[j]->center_freq;
 			match->n_channels++;
-- 
2.53.0


^ permalink raw reply related

* [PATCH iwlwifi-fixes 0/5] wifi: iwlwifi: fixes - 2026-05-15
From: Miri Korenblit @ 2026-05-15 12:14 UTC (permalink / raw)
  To: linux-wireless

Hi,
A couple of fixes from our internal tree.

Miri
---

Emmanuel Grumbach (1):
  wifi: iwlwifi: mld: disconnect only after 6 beacons without Rx

Johannes Berg (2):
  wifi: iwlwifi: mvm: fix driver-set TX rates on old devices
  wifi: iwlwifi: mld: don't WARN on WoWLAN suspend w/o BSS vif

Miri Korenblit (1):
  wifi: iwlwifi: mld: don't dereference a pointer before NULL checking
    it

Moriya Itzchaki (1):
  wifi: iwlwifi: use correct function to read STEP_URM register

 .../wireless/intel/iwlwifi/mld/constants.h    |  4 +--
 drivers/net/wireless/intel/iwlwifi/mld/d3.c   |  6 ++---
 drivers/net/wireless/intel/iwlwifi/mld/link.c | 13 +++++----
 .../net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 27 ++++++++++++-------
 .../net/wireless/intel/iwlwifi/mvm/utils.c    | 14 +++-------
 .../intel/iwlwifi/pcie/gen1_2/trans-gen2.c    |  6 ++---
 6 files changed, 36 insertions(+), 34 deletions(-)

-- 
2.34.1


^ permalink raw reply

* [PATCH iwlwifi-fixes 1/5] wifi: iwlwifi: mld: don't dereference a pointer before NULL checking it
From: Miri Korenblit @ 2026-05-15 12:14 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260515121500.1170852-1-miriam.rachel.korenblit@intel.com>

In iwl_mld_remove_link, the link->fw_id is saved at the beginning of the
function so we have it after we freed the link.

But the link pointer can be NULL, and is not checked when the fw_id is
stored.

Fix it by simply freeing the link at the end of the function.

fFixes: 0e66a39f4f0e ("wifi: iwlwifi: fix potential use after free in iwl_mld_remove_link()")
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/link.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c
index b66e84d2365f..be2cdf43c72e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/link.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
  */
 
 #include "constants.h"
@@ -504,7 +504,6 @@ void iwl_mld_remove_link(struct iwl_mld *mld,
 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(bss_conf->vif);
 	struct iwl_mld_link *link = iwl_mld_link_from_mac80211(bss_conf);
 	bool is_deflink = link == &mld_vif->deflink;
-	u8 fw_id = link->fw_id;
 
 	if (WARN_ON(!link || link->active))
 		return;
@@ -512,15 +511,15 @@ void iwl_mld_remove_link(struct iwl_mld *mld,
 	iwl_mld_rm_link_from_fw(mld, bss_conf);
 	/* Continue cleanup on failure */
 
-	if (!is_deflink)
-		kfree_rcu(link, rcu_head);
-
 	RCU_INIT_POINTER(mld_vif->link[bss_conf->link_id], NULL);
 
-	if (WARN_ON(fw_id >= mld->fw->ucode_capa.num_links))
+	if (WARN_ON(link->fw_id >= mld->fw->ucode_capa.num_links))
 		return;
 
-	RCU_INIT_POINTER(mld->fw_id_to_bss_conf[fw_id], NULL);
+	RCU_INIT_POINTER(mld->fw_id_to_bss_conf[link->fw_id], NULL);
+
+	if (!is_deflink)
+		kfree_rcu(link, rcu_head);
 }
 
 void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld,
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-fixes 2/5] wifi: iwlwifi: mvm: fix driver-set TX rates on old devices
From: Miri Korenblit @ 2026-05-15 12:14 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, stable
In-Reply-To: <20260515121500.1170852-1-miriam.rachel.korenblit@intel.com>

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

On old devices such as 7265D, rates are still encoded in version 1
format, which doesn't use the CCK/OFDM rate index (0-3/0-7) but
rather their PLCP value (e.g. 10 for 1 Mbps CCK rate.)

While introducing v3 rates, I changed the driver from internally
handling v1 rates and converting to v2, to internally handling v3
and converting to v1 or v2 according to the firmware. I accordingly
changed the code in iwl_mvm_mac80211_idx_to_hwrate() to no longer
have different values for different APIs. This was correct.

However, I later reverted this part of the change, because it was
reported that I had broken beacon rates, causing a FW assert/crash.
This caused TX_CMD rates to be set incorrectly, potentially causing
a warning when reported back from the device as having been used.

Fix this (hopefully correctly now) by handling beacon rates in the
TX_CMD that's embedded in the beacon template command separately.
Restore iwl_mvm_mac80211_idx_to_hwrate() to return only the rate
index, not PLCP value, fixing the real TX_CMD.

Fixes: 3592c0083fb2 ("wifi: iwlwifi: mvm: fix beacon template/fixed rate")
Cc: stable@vger.kernel.org
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 .../net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 27 ++++++++++++-------
 .../net/wireless/intel/iwlwifi/mvm/utils.c    | 14 +++-------
 2 files changed, 22 insertions(+), 19 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
index c523c5e82d4a..8ffa72aca3cf 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2012-2014, 2018-2025 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2026 Intel Corporation
  * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
  * Copyright (C) 2015-2017 Intel Deutschland GmbH
  */
@@ -927,13 +927,18 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm,
 
 u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw, u8 rate_idx)
 {
-	u16 flags = iwl_mvm_mac80211_idx_to_hwrate(fw, rate_idx);
 	bool is_new_rate = iwl_fw_lookup_cmd_ver(fw, BEACON_TEMPLATE_CMD, 0) > 10;
+	u16 flags = 0;
 
 	if (rate_idx <= IWL_LAST_CCK_RATE)
 		flags |= is_new_rate ? IWL_MAC_BEACON_CCK
 			  : IWL_MAC_BEACON_CCK_V1;
 
+	if (iwl_fw_lookup_cmd_ver(fw, TX_CMD, 0) > 8)
+		flags |= iwl_mvm_mac80211_idx_to_hwrate(fw, rate_idx);
+	else
+		flags |= iwl_fw_rate_idx_to_plcp(rate_idx);
+
 	return flags;
 }
 
@@ -962,6 +967,7 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,
 {
 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 	struct ieee80211_tx_info *info;
+	u32 rate_n_flags = 0;
 	u8 rate;
 	u32 tx_flags;
 
@@ -981,18 +987,21 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,
 			 IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION)) {
 		iwl_mvm_toggle_tx_ant(mvm, &mvm->mgmt_last_antenna_idx);
 
-		tx_params->rate_n_flags =
-			cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) <<
-				    RATE_MCS_ANT_POS);
+		rate_n_flags |= BIT(mvm->mgmt_last_antenna_idx) <<
+					RATE_MCS_ANT_POS;
 	}
 
 	rate = iwl_mvm_mac_ctxt_get_beacon_rate(mvm, info, vif);
 
-	tx_params->rate_n_flags |=
-		cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate));
-	if (rate == IWL_FIRST_CCK_RATE)
-		tx_params->rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK_V1);
+	if (rate < IWL_FIRST_OFDM_RATE)
+		rate_n_flags |= RATE_MCS_MOD_TYPE_CCK;
+	else
+		rate_n_flags |= RATE_MCS_MOD_TYPE_LEGACY_OFDM;
+
+	rate_n_flags |= iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate);
 
+	tx_params->rate_n_flags = iwl_mvm_v3_rate_to_fw(rate_n_flags,
+							mvm->fw_rates_ver);
 }
 
 int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index 4a33a032c2a7..f052537e9567 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2012-2014, 2018-2025 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2026 Intel Corporation
  * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
  * Copyright (C) 2015-2017 Intel Deutschland GmbH
  */
@@ -159,15 +159,9 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
 
 u8 iwl_mvm_mac80211_idx_to_hwrate(const struct iwl_fw *fw, int rate_idx)
 {
-	if (iwl_fw_lookup_cmd_ver(fw, TX_CMD, 0) > 8)
-		/* In the new rate legacy rates are indexed:
-		 * 0 - 3 for CCK and 0 - 7 for OFDM.
-		 */
-		return (rate_idx >= IWL_FIRST_OFDM_RATE ?
-			rate_idx - IWL_FIRST_OFDM_RATE :
-			rate_idx);
-
-	return iwl_fw_rate_idx_to_plcp(rate_idx);
+	return rate_idx >= IWL_FIRST_OFDM_RATE ?
+		rate_idx - IWL_FIRST_OFDM_RATE :
+		rate_idx;
 }
 
 u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac)
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-fixes 3/5] wifi: iwlwifi: use correct function to read STEP_URM register
From: Miri Korenblit @ 2026-05-15 12:14 UTC (permalink / raw)
  To: linux-wireless; +Cc: Moriya Itzchaki, Johannes Berg
In-Reply-To: <20260515121500.1170852-1-miriam.rachel.korenblit@intel.com>

From: Moriya Itzchaki <moriya.itzchaki@intel.com>

CNVI_PMU_STEP_FLOW is a PRPH register, not a UMAC PRPH register.
Use iwl_read_prph() instead of iwl_read_umac_prph() to read it
correctly.

Fixes: de0c2cdcb7eb ("wifi: iwlwifi: mvm: limit EHT 320 MHz MCS for STEP URM")
Signed-off-by: Moriya Itzchaki <moriya.itzchaki@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c
index a50e845cea42..64262bcca55d 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c
@@ -398,9 +398,9 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans)
 	mutex_unlock(&trans_pcie->mutex);
 
 	if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
-		trans->step_urm = !!(iwl_read_umac_prph(trans,
-							CNVI_PMU_STEP_FLOW) &
-					CNVI_PMU_STEP_FLOW_FORCE_URM);
+		trans->step_urm = !!(iwl_read_prph(trans,
+						   CNVI_PMU_STEP_FLOW) &
+				     CNVI_PMU_STEP_FLOW_FORCE_URM);
 }
 
 static bool iwl_pcie_set_ltr(struct iwl_trans *trans)
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-fixes 4/5] wifi: iwlwifi: mld: don't WARN on WoWLAN suspend w/o BSS vif
From: Miri Korenblit @ 2026-05-15 12:14 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260515121500.1170852-1-miriam.rachel.korenblit@intel.com>

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

Clearly, from a user perspective, it must be valid to configure
WoWLAN (which can include network detection) and then suspend
while not connected to a network, or even without an interface
at all (WoWLAN config is handled on a per-wiphy basis). Since
mac80211 doesn't distinguish these cases and simply calls the
driver to suspend whenever WoWLAN is configured, the driver has
to cleanly handle the case where it's called for WoWLAN but no
(BSS) interface exists.

Remove the WARN_ON(), move the print so it doesn't get done in
this case, and keep returning 1 to disconnect everything.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/d3.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
index ef98efc8fb1b..3a595a1c2e00 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
@@ -1930,12 +1930,12 @@ int iwl_mld_wowlan_suspend(struct iwl_mld *mld, struct cfg80211_wowlan *wowlan)
 	if (WARN_ON(!wowlan))
 		return 1;
 
-	IWL_DEBUG_WOWLAN(mld, "Starting the wowlan suspend flow\n");
-
 	bss_vif = iwl_mld_get_bss_vif(mld);
-	if (WARN_ON(!bss_vif))
+	if (!bss_vif)
 		return 1;
 
+	IWL_DEBUG_WOWLAN(mld, "Starting the wowlan suspend flow\n");
+
 	if (!bss_vif->cfg.assoc) {
 		int ret;
 		/* If we're not associated, this must be netdetect */
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-fixes 5/5] wifi: iwlwifi: mld: disconnect only after 6 beacons without Rx
From: Miri Korenblit @ 2026-05-15 12:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260515121500.1170852-1-miriam.rachel.korenblit@intel.com>

From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>

After 4 missed beacons since last Rx, the firmware will send an NDP to the
AP. If the NDP is ACK'ed, it'll reset the missed_beacons_since_last_rx
counter.
Disconnecting after 4 beacons doesn't give enough time to the firmware
to send the NDP.

Wait until we get 6 missed beacons since last Rx before disconnecting.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/constants.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/constants.h b/drivers/net/wireless/intel/iwlwifi/mld/constants.h
index e2a5eecc18c3..890abcab3837 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/constants.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/constants.h
@@ -1,11 +1,11 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
  */
 #ifndef __iwl_mld_constants_h__
 #define __iwl_mld_constants_h__
 
-#define IWL_MLD_MISSED_BEACONS_SINCE_RX_THOLD			4
+#define IWL_MLD_MISSED_BEACONS_SINCE_RX_THOLD			6
 #define IWL_MLD_MISSED_BEACONS_THRESHOLD			8
 #define IWL_MLD_MISSED_BEACONS_THRESHOLD_LONG			19
 #define IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS		5
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH] wifi: cfg80211: validate common_info length in ieee80211_mle_size_ok()
From: Alexandru Hossu @ 2026-05-15 12:57 UTC (permalink / raw)
  To: gregkh; +Cc: security, linux-wireless, johannes
In-Reply-To: <2026051527-scrooge-oppressor-1500@gregkh>

On Fri, May 15, 2026 at 01:36:03PM +0200, Greg KH wrote:
> Context matters :)
> Also, this isn't in a mergable format, please take a look at the kernel
> documentation for how to do this properly.

Sorry for both issues. The greeting was wrong, the format was wrong,
and most importantly I didn't check the tree first -- the fix is
already at ieee80211-eht.h:912 in linux-next. I wasted your time.

Withdrawing this.

Alexandru

^ permalink raw reply

* [PATCH wireless 0/2] wifi: mac80211: negotiated TTLM sparse-map cursor
From: Michael Bommarito @ 2026-05-15 15:17 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Ayala Beker, linux-wireless, linux-kernel

ieee80211_parse_neg_ttlm() advances its cursor by map_size for every
TID, even TIDs whose bit is clear in link_map_presence and therefore
contribute no map bytes to the element.  A sparse map then makes a
later present TID read past the validated element.

Patch 1/2 moves the cursor advance inside the if-present branch so
the parser walks the same layout that ieee80211_tid_to_link_map_size_ok()
already validates.

Patch 2/2 adds two KUnit cases under the new mac80211-ttlm suite to
lock the layout: sparse_presence_no_oob_read crafts a buffer sized
exactly to the validated element so a pre-fix run is a KASAN
slab-out-of-bounds report; dense_presence_baseline confirms the fix
does not regress the path that was already correct.

Reach is adjacent (AV:A) from an associated peer MLD; the sender does
not need privileges on the victim kernel.  The OOB bytes are gated by
valid_links before being applied to driver state, so a peer cannot
turn the read into a policy change.  KUnit + KASAN observes a slab-
out-of-bounds read when the element is exactly sized.  Whether the
same read trips KASAN through the production RX frame path depends on
allocator state; this series does not include an over-the-air hwsim
replay.

Michael Bommarito (2):
  wifi: mac80211: consume only present negotiated TTLM maps
  wifi: mac80211: add KUnit coverage for negotiated TTLM parser

 net/mac80211/ieee80211_i.h      |   4 +
 net/mac80211/mlme.c             |   5 +-
 net/mac80211/tests/.kunitconfig |   4 +
 net/mac80211/tests/Makefile     |   2 +-
 net/mac80211/tests/ttlm.c       | 175 ++++++++++++++++++++++++++++++++
 5 files changed, 187 insertions(+), 3 deletions(-)
 create mode 100644 net/mac80211/tests/.kunitconfig
 create mode 100644 net/mac80211/tests/ttlm.c

-- 
2.53.0


^ permalink raw reply

* [PATCH wireless 1/2] wifi: mac80211: consume only present negotiated TTLM maps
From: Michael Bommarito @ 2026-05-15 15:17 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Ayala Beker, linux-wireless, linux-kernel
In-Reply-To: <20260515151719.1317659-1-michael.bommarito@gmail.com>

ieee80211_tid_to_link_map_size_ok() validates negotiated TTLM elements
against the number of link-map entries indicated by link_map_presence.
ieee80211_parse_neg_ttlm() must consume the same layout.

The parser advanced its cursor for every TID, including TIDs whose
presence bit is clear and therefore have no map bytes in the element.
A sparse map can then make a later present TID read past the validated
element.

The bad bytes land in neg_ttlm->{up,down}link[tid] but are gated by
valid_links before being applied to driver state, so a peer cannot
turn the read into a policy change.  Under KUnit + KASAN with an
exact-sized element allocation the OOB read is reported as a
slab-out-of-bounds; whether the same trigger fires under the
production RX path depends on surrounding allocator state.

Advance the cursor only when the current TID has a map present.

Fixes: 8f500fbc6c65 ("wifi: mac80211: process and save negotiated TID to Link mapping request")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
 net/mac80211/mlme.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 160ae65a5c645..c3a2844740a14 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -8155,6 +8155,7 @@ ieee80211_parse_neg_ttlm(struct ieee80211_sub_if_data *sdata,
 					 "No active links for TID %d", tid);
 				return -EINVAL;
 			}
+			pos += map_size;
 		} else {
 			map = 0;
 		}
@@ -8173,7 +8174,6 @@ ieee80211_parse_neg_ttlm(struct ieee80211_sub_if_data *sdata,
 		default:
 			return -EINVAL;
 		}
-		pos += map_size;
 	}
 	return 0;
 }
-- 
2.53.0


^ permalink raw reply related

* [PATCH wireless 2/2] wifi: mac80211: add KUnit coverage for negotiated TTLM parser
From: Michael Bommarito @ 2026-05-15 15:17 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Ayala Beker, linux-wireless, linux-kernel
In-Reply-To: <20260515151719.1317659-1-michael.bommarito@gmail.com>

Add KUnit coverage for ieee80211_parse_neg_ttlm() to lock the sparse
link_map_presence layout against future regressions.

The sparse_presence_no_oob_read case crafts a negotiated TTLM element
with link_map_presence = BIT(0) | BIT(7) and bm_size = 2 in a buffer
sized exactly to the validated element length.  Without the parser
fix this would read 14 bytes past the buffer when processing TID 7;
under KASAN that is a slab-out-of-bounds report.

The dense_presence_baseline case crafts a fully populated
link_map_presence = 0xff element to confirm that the cursor-advance
fix does not regress the path that was already correct.

Export ieee80211_parse_neg_ttlm via VISIBLE_IF_MAC80211_KUNIT so the
test can call it directly.

Assisted-by: Claude:claude-sonnet-4-6
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
 net/mac80211/ieee80211_i.h      |   4 +
 net/mac80211/mlme.c             |   3 +-
 net/mac80211/tests/.kunitconfig |   4 +
 net/mac80211/tests/Makefile     |   2 +-
 net/mac80211/tests/ttlm.c       | 175 ++++++++++++++++++++++++++++++++
 5 files changed, 186 insertions(+), 2 deletions(-)
 create mode 100644 net/mac80211/tests/.kunitconfig
 create mode 100644 net/mac80211/tests/ttlm.c

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 2a693406294bc..aa9c9781db92e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2948,6 +2948,10 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
 			      struct ieee80211_chan_req *chanreq,
 			      struct cfg80211_chan_def *ap_chandef,
 			      unsigned long *userspace_selectors);
+int ieee80211_parse_neg_ttlm(struct ieee80211_sub_if_data *sdata,
+			     const struct ieee80211_ttlm_elem *ttlm,
+			     struct ieee80211_neg_ttlm *neg_ttlm,
+			     u8 *direction);
 #else
 #define EXPORT_SYMBOL_IF_MAC80211_KUNIT(sym)
 #define VISIBLE_IF_MAC80211_KUNIT static
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index c3a2844740a14..9a51870a818da 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -8096,7 +8096,7 @@ ieee80211_send_neg_ttlm_res(struct ieee80211_sub_if_data *sdata,
 	ieee80211_tx_skb(sdata, skb);
 }
 
-static int
+VISIBLE_IF_MAC80211_KUNIT int
 ieee80211_parse_neg_ttlm(struct ieee80211_sub_if_data *sdata,
 			 const struct ieee80211_ttlm_elem *ttlm,
 			 struct ieee80211_neg_ttlm *neg_ttlm,
@@ -8177,6 +8177,7 @@ ieee80211_parse_neg_ttlm(struct ieee80211_sub_if_data *sdata,
 	}
 	return 0;
 }
+EXPORT_SYMBOL_IF_MAC80211_KUNIT(ieee80211_parse_neg_ttlm);
 
 void ieee80211_process_neg_ttlm_req(struct ieee80211_sub_if_data *sdata,
 				    struct ieee80211_mgmt *mgmt, size_t len)
diff --git a/net/mac80211/tests/.kunitconfig b/net/mac80211/tests/.kunitconfig
new file mode 100644
index 0000000000000..ab2cc5cfc1f5c
--- /dev/null
+++ b/net/mac80211/tests/.kunitconfig
@@ -0,0 +1,4 @@
+CONFIG_KUNIT=y
+CONFIG_CFG80211=y
+CONFIG_MAC80211=y
+CONFIG_MAC80211_KUNIT_TEST=y
diff --git a/net/mac80211/tests/Makefile b/net/mac80211/tests/Makefile
index 3c7f874e5c412..2e9ade90f7b63 100644
--- a/net/mac80211/tests/Makefile
+++ b/net/mac80211/tests/Makefile
@@ -1,3 +1,3 @@
-mac80211-tests-y += module.o util.o elems.o mfp.o tpe.o chan-mode.o s1g_tim.o
+mac80211-tests-y += module.o util.o elems.o mfp.o tpe.o chan-mode.o s1g_tim.o ttlm.o
 
 obj-$(CONFIG_MAC80211_KUNIT_TEST) += mac80211-tests.o
diff --git a/net/mac80211/tests/ttlm.c b/net/mac80211/tests/ttlm.c
new file mode 100644
index 0000000000000..18d0592b13d9e
--- /dev/null
+++ b/net/mac80211/tests/ttlm.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * KUnit tests for negotiated TTLM (TID-To-Link Mapping) parsing
+ *
+ * Copyright (C) 2026 Michael Bommarito <michael.bommarito@gmail.com>
+ */
+#include <kunit/test.h>
+#include <linux/ieee80211.h>
+#include "../ieee80211_i.h"
+
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
+
+/*
+ * Build a negotiated TTLM element in caller-supplied buffer.
+ *
+ * @buf:       destination buffer (must be at least elem_size bytes)
+ * @elem_size: sizeof(ttlm_elem) + 1 (presence byte) + npresent * bm_size
+ * @presence:  link_map_presence bitmask; each set bit => one map follows
+ * @bm_size:   bytes per map (1 or 2); 2 => LINK_MAP_SIZE bit clear
+ * @maps:      array of npresent u16 maps, one per set bit in presence
+ *
+ * Control field encodes direction=BOTH; no switch-time, no expected-dur,
+ * no DEF_LINK_MAP.  LINK_MAP_SIZE bit is set iff bm_size==1.
+ *
+ * Returns pointer to the ieee80211_ttlm_elem at buf.
+ */
+static const struct ieee80211_ttlm_elem *
+build_neg_ttlm_elem(u8 *buf, size_t elem_size,
+		    u8 presence, u8 bm_size, const u16 *maps)
+{
+	struct ieee80211_ttlm_elem *t = (void *)buf;
+	u8 control;
+	u8 *pos;
+	int i, tid;
+
+	memset(buf, 0, elem_size);
+
+	control = IEEE80211_TTLM_DIRECTION_BOTH; /* bits [1:0] = 2 */
+	if (bm_size == 1)
+		control |= IEEE80211_TTLM_CONTROL_LINK_MAP_SIZE;
+
+	t->control = control;
+
+	pos = (u8 *)t->optional;
+	*pos++ = presence;
+
+	i = 0;
+	for (tid = 0; tid < IEEE80211_TTLM_NUM_TIDS; tid++) {
+		if (!(presence & BIT(tid)))
+			continue;
+		if (bm_size == 1)
+			*pos = (u8)maps[i];
+		else
+			put_unaligned_le16(maps[i], pos);
+		pos += bm_size;
+		i++;
+	}
+
+	return t;
+}
+
+/*
+ * sparse_presence_no_oob_read - BIT(0)|BIT(7) presence, bm_size=2
+ *
+ * Only TID 0 and TID 7 have maps; TIDs 1-6 are absent.  Element length
+ * is exactly 6 bytes (1 control + 1 presence + 2 * 2-byte maps).
+ *
+ * Pre-fix the parser advanced pos by bm_size AFTER the switch() block
+ * (i.e. unconditionally for every TID), so when processing TID 7 it
+ * had already advanced 6 * bm_size = 12 bytes past the presence byte
+ * for the absent TIDs before reading the TID-7 map - 14 bytes past the
+ * end of the 2-byte TID-7 map.  Under KASAN that is a slab-out-of-bounds.
+ *
+ * After the fix pos is advanced only inside the presence-bit branch so
+ * the cursor lands exactly at end-of-element after processing TID 7.
+ */
+static void sparse_presence_no_oob_read(struct kunit *test)
+{
+	/*
+	 * presence = BIT(0)|BIT(7): 2 maps present.
+	 * elem_size = sizeof(ttlm_elem) + 1 (presence) + 2*2 (maps) = 6.
+	 */
+	const u8 presence = BIT(0) | BIT(7);
+	const u8 bm_size = 2;
+	const int npresent = 2;
+	const size_t elem_size = sizeof(struct ieee80211_ttlm_elem)
+				 + 1 + npresent * bm_size;
+	/*
+	 * Allocate exact-size buffer so a pre-fix OOB read walks into the
+	 * KASAN red zone immediately after the allocation.
+	 */
+	u8 *buf = kunit_kzalloc(test, elem_size, GFP_KERNEL);
+	const struct ieee80211_ttlm_elem *ttlm;
+	struct ieee80211_neg_ttlm neg_ttlm = {};
+	/* Non-zero maps so the parser does not reject with -EINVAL. */
+	const u16 maps[2] = { 0x0001, 0x0001 };
+	u8 direction = 0;
+	int ret;
+
+	KUNIT_ASSERT_NOT_NULL(test, buf);
+
+	ttlm = build_neg_ttlm_elem(buf, elem_size, presence, bm_size, maps);
+
+	/*
+	 * Pass NULL for sdata: the only sdata dereference in this code path
+	 * is inside mlme_dbg() on error returns, which are guarded by
+	 * MAC80211_MLME_DEBUG == 0 in non-debug builds and by the dead-code
+	 * eliminator in KUnit builds.  The success path does not touch sdata.
+	 */
+	ret = ieee80211_parse_neg_ttlm(NULL, ttlm, &neg_ttlm, &direction);
+
+	KUNIT_EXPECT_EQ(test, ret, 0);
+	KUNIT_EXPECT_EQ(test, (int)direction, IEEE80211_TTLM_DIRECTION_BOTH);
+	/* TID 0: map present */
+	KUNIT_EXPECT_EQ(test, (int)neg_ttlm.downlink[0], 0x0001);
+	KUNIT_EXPECT_EQ(test, (int)neg_ttlm.uplink[0],   0x0001);
+	/* TID 3: absent => map should be 0 */
+	KUNIT_EXPECT_EQ(test, (int)neg_ttlm.downlink[3], 0);
+	KUNIT_EXPECT_EQ(test, (int)neg_ttlm.uplink[3],   0);
+	/* TID 7: map present */
+	KUNIT_EXPECT_EQ(test, (int)neg_ttlm.downlink[7], 0x0001);
+	KUNIT_EXPECT_EQ(test, (int)neg_ttlm.uplink[7],   0x0001);
+}
+
+/*
+ * dense_presence_baseline - presence=0xff (all 8 TIDs), bm_size=2
+ *
+ * Every TID has a map; this is the dense layout the parser handled
+ * correctly even before the fix.  Confirms the cursor-advance fix
+ * does not regress the already-correct path.
+ */
+static void dense_presence_baseline(struct kunit *test)
+{
+	const u8 presence = 0xff;
+	const u8 bm_size = 2;
+	const int npresent = 8;
+	const size_t elem_size = sizeof(struct ieee80211_ttlm_elem)
+				 + 1 + npresent * bm_size;
+	u8 *buf = kunit_kzalloc(test, elem_size, GFP_KERNEL);
+	const struct ieee80211_ttlm_elem *ttlm;
+	struct ieee80211_neg_ttlm neg_ttlm = {};
+	const u16 maps[8] = {
+		0x0003, 0x0003, 0x0003, 0x0003,
+		0x0003, 0x0003, 0x0003, 0x0003,
+	};
+	u8 direction = 0;
+	int ret;
+
+	KUNIT_ASSERT_NOT_NULL(test, buf);
+
+	ttlm = build_neg_ttlm_elem(buf, elem_size, presence, bm_size, maps);
+
+	ret = ieee80211_parse_neg_ttlm(NULL, ttlm, &neg_ttlm, &direction);
+
+	KUNIT_EXPECT_EQ(test, ret, 0);
+	KUNIT_EXPECT_EQ(test, (int)direction, IEEE80211_TTLM_DIRECTION_BOTH);
+	/* All TIDs present: every downlink/uplink entry must be 0x0003. */
+	for (int tid = 0; tid < IEEE80211_TTLM_NUM_TIDS; tid++) {
+		KUNIT_EXPECT_EQ(test, (int)neg_ttlm.downlink[tid], 0x0003);
+		KUNIT_EXPECT_EQ(test, (int)neg_ttlm.uplink[tid],   0x0003);
+	}
+}
+
+static struct kunit_case mac80211_ttlm_test_cases[] = {
+	KUNIT_CASE(sparse_presence_no_oob_read),
+	KUNIT_CASE(dense_presence_baseline),
+	{}
+};
+
+static struct kunit_suite mac80211_ttlm = {
+	.name = "mac80211-ttlm",
+	.test_cases = mac80211_ttlm_test_cases,
+};
+
+kunit_test_suite(mac80211_ttlm);
-- 
2.53.0


^ permalink raw reply related

* Question: nl80211 testmode_dump and prepare_vendor_dump  continuation missing netns recheck
From: Xie Maoyi @ 2026-05-15 15:40 UTC (permalink / raw)
  To: johannes@sipsolutions.net; +Cc: linux-wireless@vger.kernel.org

Hi Johannes,

After your acceptance of 79240f3f6d76 ("wifi: nl80211: re-check
wiphy netns in nl80211_prepare_wdev_dump() continuation"), I
looked at the other dumpit callbacks in net/wireless/nl80211.c.
Two sites read state from cb->args[] across continuations without
a comparable net_eq() recheck.

Site 1: nl80211_testmode_dump().

The continuation branch resolves rdev via
cfg80211_rdev_by_wiphy_idx() on cb->args[0]. It does not verify
that wiphy_net matches sock_net(cb->skb->sk).

Site 2: nl80211_prepare_vendor_dump().

The continuation branch resolves wiphy via wiphy_idx_to_wiphy()
on cb->args[0] and proceeds. Same gap. This helper is called by
nl80211_vendor_cmd_dump, so a fix here covers that path too.

I notice one practical limit. No in-tree mainline driver currently
registers .testmode_dump or wiphy_vendor_command.dumpit, so the
paths are latent today. Out-of-tree drivers may register either.

I wanted to check with you before sending anything. If you read
these as the same class of bug as 79240f3f6d76 and a short series
mirroring that fix would be useful, I would be glad to put one
together when it fits your queue, or to drop the thread if you
prefer.

Thanks,
Maoyi
--
Nanyang Technological University
https://maoyixie.com/
________________________________

CONFIDENTIALITY: This email is intended solely for the person(s) named and may be confidential and/or privileged. If you are not the intended recipient, please delete it, notify us and do not copy, use, or disclose its contents.
Towards a sustainable earth: Print only when necessary. Thank you.

^ permalink raw reply

* Re: [PATCH] wifi: mt76: mt7996: avoid memset overwriting tx_info->control.flags
From: Lorenzo Bianconi @ 2026-05-15 16:29 UTC (permalink / raw)
  To: Ryder Lee
  Cc: Felix Fietkau, linux-mediatek, linux-wireless, Shayne Chen,
	Roy Luo
In-Reply-To: <5ecac6a9b7d29526e8438dea105b58f5487c93aa.1778521232.git.ryder.lee@mediatek.com>

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

> mt76_tx_status_skb_add uses memset on status.status_driver_data, which
> overwrite  info->control.flags in ieee80211_tx_info. Copy tx_info before
> calling mt76_tx_status_skb_add to ensure control fields are preserved
> and remain valid for later processing.
> 
> Reported-By: Roy Luo <roy-ch.luo@mediatek.com>
> Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>

Hi Ryder,

I have not completely got the issue here:

struct ieee80211_tx_info {
        u32                        flags;                /*     0     4 */
        u32                        band:3;               /*     4: 0  4 */
        u32                        status_data_idr:1;    /*     4: 3  4 */
        u32                        status_data:13;       /*     4: 4  4 */
        u32                        hw_queue:4;           /*     4:17  4 */
        u32                        tx_time_est:10;       /*     4:21  4 */

        /* XXX 1 bit hole, try to pack */

        union {
                struct {
                        union {
                                struct {
                                        struct ieee80211_tx_rate rates[4]; /*     8    12 */
                                        s8     rts_cts_rate_idx; /*    20     1 */
                                        u8     use_rts:1; /*    21: 0  1 */
                                        u8     use_cts_prot:1; /*    21: 1  1 */
                                        u8     short_preamble:1; /*    21: 2  1 */
                                        u8     skip_table:1; /*    21: 3  1 */
                                        u8     antennas:2; /*    21: 4  1 */
                                };                       /*     8    14 */
                                long unsigned int jiffies; /*     8     8 */
                        };                               /*     8    16 */
                        struct ieee80211_vif * vif;      /*    24     8 */
                        struct ieee80211_key_conf * hw_key; /*    32     8 */
                        u32        flags;                /*    40     4 */
                        codel_time_t enqueue_time;       /*    44     4 */
                } control;                               /*     8    40 */
                struct {
                        u64        cookie;               /*     8     8 */
                } ack;                                   /*     8     8 */
                struct {
                        struct ieee80211_tx_rate rates[4]; /*     8    12 */
                        s32        ack_signal;           /*    20     4 */
                        u8         ampdu_ack_len;        /*    24     1 */
                        u8         ampdu_len;            /*    25     1 */
                        u8         antenna;              /*    26     1 */
                        u8         pad;                  /*    27     1 */
                        u16        tx_time;              /*    28     2 */
                        u8         flags;                /*    30     1 */
                        u8         pad2;                 /*    31     1 */
                        void *     status_driver_data[2]; /*    32    16 */
                } status;                                /*     8    40 */
                struct {
                        struct ieee80211_tx_rate driver_rates[4]; /*     8    12 */
                        u8         pad[4];               /*    20     4 */
                        void *     rate_driver_data[3];  /*    24    24 */
                };                                       /*     8    40 */
                void *             driver_data[5];       /*     8    40 */
        };                                               /*     8    40 */

        /* size: 48, cachelines: 1, members: 7 */
        /* sum members: 44 */
        /* sum bitfield members: 31 bits, bit holes: 1, sum bit holes: 1 bits */
        /* last cacheline: 48 bytes */
};

According to pahole, the size of the control inner union is actually 16 bytes
since the compiler adds 2 bytes of padding. Since mt76_tx_status_skb_add()
meset to 0 just mt76_tx_cb size (that is 16 bytes) I can't see how
control.flags is overwritten. Am I missing something?

struct mt76_tx_cb {
        long unsigned int          jiffies;              /*     0     8 */
        u16                        wcid;                 /*     8     2 */
        u8                         pktid;                /*    10     1 */
        u8                         flags;                /*    11     1 */

        /* size: 16, cachelines: 1, members: 4 */
        /* padding: 4 */
        /* last cacheline: 16 bytes */
};

Regards,
Lorenzo

> ---
>  drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 17 +++++++++--------
>  .../net/wireless/mediatek/mt76/mt7996/mt7996.h  |  2 +-
>  2 files changed, 10 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
> index e2a83da3a09c..a59c14c8f2af 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
> @@ -855,11 +855,12 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
>  
>  void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
>  			   struct sk_buff *skb, struct mt76_wcid *wcid,
> -			   struct ieee80211_key_conf *key, int pid,
> +			   struct ieee80211_tx_info *tx_info, int pid,
>  			   enum mt76_txq_id qid, u32 changed)
>  {
>  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
> -	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> +	struct ieee80211_key_conf *key = tx_info ? tx_info->control.hw_key : NULL;
> +	struct ieee80211_tx_info *info = tx_info ? tx_info : IEEE80211_SKB_CB(skb);
>  	struct ieee80211_vif *vif = info->control.vif;
>  	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
>  	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
> @@ -1006,15 +1007,15 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
>  {
>  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;
>  	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
> -	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
> -	struct ieee80211_key_conf *key = info->control.hw_key;
> -	struct ieee80211_vif *vif = info->control.vif;
> +	struct ieee80211_tx_info info = *IEEE80211_SKB_CB(tx_info->skb);
> +	struct ieee80211_key_conf *key = info.control.hw_key;
> +	struct ieee80211_vif *vif = info.control.vif;
>  	struct mt7996_vif *mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL;
>  	struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv : NULL;
>  	struct mt76_vif_link *mlink = NULL;
>  	struct mt76_txwi_cache *t;
>  	int id, i, pid, nbuf = tx_info->nbuf - 1;
> -	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
> +	bool is_8023 = info.flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
>  	__le32 *ptr = (__le32 *)txwi_ptr;
>  	u8 *txwi = (u8 *)txwi_ptr;
>  	u8 link_id;
> @@ -1031,7 +1032,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
>  
>  		link_id = (tid % 2) ? msta->seclink_id : msta->deflink_id;
>  	} else {
> -		link_id = u32_get_bits(info->control.flags,
> +		link_id = u32_get_bits(info.control.flags,
>  				       IEEE80211_TX_CTRL_MLO_LINK);
>  	}
>  
> @@ -1095,7 +1096,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
>  	memset(txwi_ptr, 0, MT_TXD_SIZE);
>  	/* Transmit non qos data by 802.11 header and need to fill txd by host*/
>  	if (!is_8023 || pid >= MT_PACKET_ID_FIRST)
> -		mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
> +		mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, &info,
>  				      pid, qid, 0);
>  
>  	/* MT7996 and MT7992 require driver to provide the MAC TXP for AddBA
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
> index bdcf72457954..319fcc4fb469 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
> @@ -854,7 +854,7 @@ void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy);
>  void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band);
>  void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
>  			   struct sk_buff *skb, struct mt76_wcid *wcid,
> -			   struct ieee80211_key_conf *key, int pid,
> +			   struct ieee80211_tx_info *tx_info, int pid,
>  			   enum mt76_txq_id qid, u32 changed);
>  void mt7996_mac_update_beacons(struct mt7996_phy *phy);
>  void mt7996_mac_set_coverage_class(struct mt7996_phy *phy);
> -- 
> 2.45.2
> 
> 

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

^ permalink raw reply

* Re: [PATCH v2 v2] wifi: wilc1000: fix dma_buffer leak on bus acquire failure
From: Simon Horman @ 2026-05-15 17:15 UTC (permalink / raw)
  To: Shitalkumar Gandhi
  Cc: ajay.kathat, claudiu.beznea, kvalo, linux-wireless, netdev,
	linux-kernel, Shitalkumar Gandhi
In-Reply-To: <20260511042732.998311-1-shitalkumar.gandhi@cambiumnetworks.com>

On Mon, May 11, 2026 at 09:57:32AM +0530, Shitalkumar Gandhi wrote:
> wilc_wlan_firmware_download() allocates dma_buffer with kmalloc() at
> the top of the function and uses a 'fail:' label to free it via
> kfree(dma_buffer) on error.
> 
> All later error paths correctly use 'goto fail' to route through this
> cleanup. However, the early failure path after the first acquire_bus()
> call uses a bare 'return ret;', which leaks dma_buffer whenever the bus
> acquire fails.
> 
> Replace the early return with goto fail so the existing cleanup path
> runs.
> 
> Found via a custom Coccinelle semantic patch hunting for kmalloc'd
> locals leaked on early-return error paths in driver firmware-download
> code.
> 
> Fixes: 1241c5650ff7 ("wifi: wilc1000: Fill in missing error handling")
> Signed-off-by: Shitalkumar Gandhi <shitalkumar.gandhi@cambiumnetworks.com>
> ---
> Changes since v1:
>   - Corrected From: and Signed-off-by: to author's real identity
>     (Shitalkumar Gandhi <shitalkumar.gandhi@cambiumnetworks.com>).
>     v1 was sent with incorrect author attribution due to a local
>     git config mistake. No code changes.

Reviewed-by: Simon Horman <horms@kernel.org>


^ permalink raw reply

* Re: [PATCH] wifi: mt76: mt7996: avoid memset overwriting tx_info->control.flags
From: Cheng Hao Luo @ 2026-05-15 18:04 UTC (permalink / raw)
  To: Lorenzo Bianconi
  Cc: Ryder Lee, Felix Fietkau, linux-mediatek, linux-wireless,
	Shayne Chen, Roy Luo
In-Reply-To: <agdJ1EtZjjWh2R1h@lore-desk>

> struct ieee80211_tx_info {
>         u32                        flags;                /*     0     4 */
>         u32                        band:3;               /*     4: 0  4 */
>         u32                        status_data_idr:1;    /*     4: 3  4 */
>         u32                        status_data:13;       /*     4: 4  4 */
>         u32                        hw_queue:4;           /*     4:17  4 */
>         u32                        tx_time_est:10;       /*     4:21  4 */
>
>         /* XXX 1 bit hole, try to pack */
>
>         union {
>                 struct {
>                         union {
>                                 struct {
>                                         struct ieee80211_tx_rate rates[4]; /*     8    12 */
>                                         s8     rts_cts_rate_idx; /*    20     1 */
>                                         u8     use_rts:1; /*    21: 0  1 */
>                                         u8     use_cts_prot:1; /*    21: 1  1 */
>                                         u8     short_preamble:1; /*    21: 2  1 */
>                                         u8     skip_table:1; /*    21: 3  1 */
>                                         u8     antennas:2; /*    21: 4  1 */
>                                 };                       /*     8    14 */
>                                 long unsigned int jiffies; /*     8     8 */
>                         };                               /*     8    16 */
>                         struct ieee80211_vif * vif;      /*    24     8 */
>                         struct ieee80211_key_conf * hw_key; /*    32     8 */
>                         u32        flags;                /*    40     4 */
>                         codel_time_t enqueue_time;       /*    44     4 */
>                 } control;                               /*     8    40 */
>                 struct {
>                         u64        cookie;               /*     8     8 */
>                 } ack;                                   /*     8     8 */
>                 struct {
>                         struct ieee80211_tx_rate rates[4]; /*     8    12 */
>                         s32        ack_signal;           /*    20     4 */
>                         u8         ampdu_ack_len;        /*    24     1 */
>                         u8         ampdu_len;            /*    25     1 */
>                         u8         antenna;              /*    26     1 */
>                         u8         pad;                  /*    27     1 */
>                         u16        tx_time;              /*    28     2 */
>                         u8         flags;                /*    30     1 */
>                         u8         pad2;                 /*    31     1 */
>                         void *     status_driver_data[2]; /*    32    16 */
>                 } status;                                /*     8    40 */
>                 struct {
>                         struct ieee80211_tx_rate driver_rates[4]; /*     8    12 */
>                         u8         pad[4];               /*    20     4 */
>                         void *     rate_driver_data[3];  /*    24    24 */
>                 };                                       /*     8    40 */
>                 void *             driver_data[5];       /*     8    40 */
>         };                                               /*     8    40 */
>
>         /* size: 48, cachelines: 1, members: 7 */
>         /* sum members: 44 */
>         /* sum bitfield members: 31 bits, bit holes: 1, sum bit holes: 1 bits */
>         /* last cacheline: 48 bytes */
> };
>
> According to pahole, the size of the control inner union is actually 16 bytes
> since the compiler adds 2 bytes of padding. Since mt76_tx_status_skb_add()
> meset to 0 just mt76_tx_cb size (that is 16 bytes) I can't see how
> control.flags is overwritten. Am I missing something?
>
> struct mt76_tx_cb {
>         long unsigned int          jiffies;              /*     0     8 */
>         u16                        wcid;                 /*     8     2 */
>         u8                         pktid;                /*    10     1 */
>         u8                         flags;                /*    11     1 */
>
>         /* size: 16, cachelines: 1, members: 4 */
>         /* padding: 4 */
>         /* last cacheline: 16 bytes */
> };

Hi Lorenzo,

The mt76_tx_cb is placed at status.status_driver_data (offset 32).
It overlaps with hw_key, flags and enqueue_time in the control union.

static inline struct mt76_tx_cb *mt76_tx_skb_cb(struct sk_buff *skb)
{
BUILD_BUG_ON(sizeof(struct mt76_tx_cb) >
    sizeof(IEEE80211_SKB_CB(skb)->status.status_driver_data));
return ((void *)IEEE80211_SKB_CB(skb)->status.status_driver_data);
}

Regards,
Roy Luo

^ permalink raw reply

* [PATCH] wifi: mt76: mt7921: assert sniffer on chanctx change
From: Devin Wittmayer @ 2026-05-15 18:39 UTC (permalink / raw)
  To: linux-wireless
  Cc: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
	Sean Wang, Deren Wu, Nick Morrow, linux-mediatek, linux-kernel

mt7921_change_chanctx() configures the channel for monitor vifs but
does not re-assert sniffer mode. mt7925_change_chanctx() does. Match
mt7925 by adding the missing mt7921_mcu_set_sniffer(true) call,
completing the architectural pattern from commit 914189af23b8 ("wifi:
mt76: mt7921: fix channel switch fail in monitor mode").

The user-visible regression this asymmetry produced on v6.17 and v6.18
was addressed by commit cdb2941a516c ("Revert "wifi: mt76: mt792x:
improve monitor interface handling"") in v6.19 and backported to the
6.17.y and 6.18.y stable trees. This patch is defense in depth in
case the NO_VIRTUAL_MONITOR change is reintroduced in a future series.

Tested-by: Nick Morrow <morrownr@gmail.com>
Tested-on: RasPi4B, RasPiOS 64 bit, Alfa AWUS036AXML mt7921u
Tested-on: RasPi4B, RasPiOS 64 bit, Netgear A9000 mt7925u
Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 3d74fabe7408..fec9ab577dd1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -1405,10 +1405,12 @@ mt7921_change_chanctx(struct ieee80211_hw *hw,
 	vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv);
 
 	mt792x_mutex_acquire(phy->dev);
-	if (vif->type == NL80211_IFTYPE_MONITOR)
+	if (vif->type == NL80211_IFTYPE_MONITOR) {
+		mt7921_mcu_set_sniffer(mvif->phy->dev, vif, true);
 		mt7921_mcu_config_sniffer(mvif, ctx);
-	else
+	} else {
 		mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->bss_conf.mt76, ctx);
+	}
 	mt792x_mutex_release(phy->dev);
 }
 
-- 
2.54.0


^ permalink raw reply related

* [PATCH v6 1/6] wifi: mac80211: Use struct instead of macro for PREQ frame
From: Masashi Honma @ 2026-05-15 23:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Masashi Honma

Signed-off-by: Masashi Honma <masashi.honma@gmail.com>
---
 include/linux/ieee80211-mesh.h | 43 +++++++++++++++++++++
 net/mac80211/mesh_hwmp.c       | 68 +++++++++++++++++-----------------
 2 files changed, 76 insertions(+), 35 deletions(-)

diff --git a/include/linux/ieee80211-mesh.h b/include/linux/ieee80211-mesh.h
index 4b829bcb38b6..623894140300 100644
--- a/include/linux/ieee80211-mesh.h
+++ b/include/linux/ieee80211-mesh.h
@@ -28,12 +28,40 @@ struct ieee80211s_hdr {
 	u8 eaddr2[ETH_ALEN];
 } __packed __aligned(2);
 
+struct ieee80211_mesh_hwmp_preq_target {
+	u8 flags;
+	u8 addr[ETH_ALEN];
+	__le32 sn;
+} __packed;
+
+struct ieee80211_mesh_hwmp_preq_top {
+	u8 flags;
+	u8 hopcount;
+	u8 ttl;
+	__le32 preq_id;
+	u8 orig_addr[ETH_ALEN];
+	__le32 orig_sn;
+
+	/* optional AE, lifetime, metric, target */
+	u8 variable[];
+} __packed;
+
+struct ieee80211_mesh_hwmp_preq_bottom {
+	__le32 lifetime;
+	__le32 metric;
+	u8 target_count;
+	struct ieee80211_mesh_hwmp_preq_target targets[];
+} __packed;
+
 /* Mesh flags */
 #define MESH_FLAGS_AE_A4 	0x1
 #define MESH_FLAGS_AE_A5_A6	0x2
 #define MESH_FLAGS_AE		0x3
 #define MESH_FLAGS_PS_DEEP	0x4
 
+/* HWMP IE processing macros */
+#define AE_F			(1<<6)
+
 /**
  * enum ieee80211_preq_flags - mesh PREQ element flags
  *
@@ -227,4 +255,19 @@ enum ieee80211_root_mode_identifier {
 	IEEE80211_PROACTIVE_RANN = 4,
 };
 
+static inline bool ieee80211_mesh_preq_prep_ae_enabled(const u8 *ie)
+{
+	return ie[0] & AE_F;
+}
+
+static inline struct ieee80211_mesh_hwmp_preq_bottom *
+	ieee80211_mesh_hwmp_preq_get_bottom(const u8 *ie)
+{
+	struct ieee80211_mesh_hwmp_preq_top *top =
+		(struct ieee80211_mesh_hwmp_preq_top *)ie;
+	return (struct ieee80211_mesh_hwmp_preq_bottom *)
+		&top->variable[ieee80211_mesh_preq_prep_ae_enabled(ie) ?
+			ETH_ALEN : 0];
+}
+
 #endif /* LINUX_IEEE80211_MESH_H */
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 9d89ebcce1c1..e0c8ba8cb1e0 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -35,24 +35,11 @@ static inline u16 u16_field_get(const u8 *preq_elem, int offset, bool ae)
 }
 
 /* HWMP IE processing macros */
-#define AE_F			(1<<6)
 #define AE_F_SET(x)		(*x & AE_F)
-#define PREQ_IE_FLAGS(x)	(*(x))
-#define PREQ_IE_HOPCOUNT(x)	(*(x + 1))
-#define PREQ_IE_TTL(x)		(*(x + 2))
-#define PREQ_IE_PREQ_ID(x)	u32_field_get(x, 3, 0)
-#define PREQ_IE_ORIG_ADDR(x)	(x + 7)
-#define PREQ_IE_ORIG_SN(x)	u32_field_get(x, 13, 0)
-#define PREQ_IE_LIFETIME(x)	u32_field_get(x, 17, AE_F_SET(x))
-#define PREQ_IE_METRIC(x) 	u32_field_get(x, 21, AE_F_SET(x))
-#define PREQ_IE_TARGET_F(x)	(*(AE_F_SET(x) ? x + 32 : x + 26))
-#define PREQ_IE_TARGET_ADDR(x) 	(AE_F_SET(x) ? x + 33 : x + 27)
-#define PREQ_IE_TARGET_SN(x) 	u32_field_get(x, 33, AE_F_SET(x))
-
-
-#define PREP_IE_FLAGS(x)	PREQ_IE_FLAGS(x)
-#define PREP_IE_HOPCOUNT(x)	PREQ_IE_HOPCOUNT(x)
-#define PREP_IE_TTL(x)		PREQ_IE_TTL(x)
+
+#define PREP_IE_FLAGS(x)	(*(x))
+#define PREP_IE_HOPCOUNT(x)	(*(x + 1))
+#define PREP_IE_TTL(x)		(*(x + 2))
 #define PREP_IE_ORIG_ADDR(x)	(AE_F_SET(x) ? x + 27 : x + 21)
 #define PREP_IE_ORIG_SN(x)	u32_field_get(x, 27, AE_F_SET(x))
 #define PREP_IE_LIFETIME(x)	u32_field_get(x, 13, AE_F_SET(x))
@@ -415,11 +402,16 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
 
 	switch (action) {
 	case MPATH_PREQ:
-		orig_addr = PREQ_IE_ORIG_ADDR(hwmp_ie);
-		orig_sn = PREQ_IE_ORIG_SN(hwmp_ie);
-		orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie);
-		orig_metric = PREQ_IE_METRIC(hwmp_ie);
-		hopcount = PREQ_IE_HOPCOUNT(hwmp_ie) + 1;
+		struct ieee80211_mesh_hwmp_preq_top *preq_elem_top =
+			(struct ieee80211_mesh_hwmp_preq_top *)hwmp_ie;
+		struct ieee80211_mesh_hwmp_preq_bottom *preq_elem_bottom =
+			ieee80211_mesh_hwmp_preq_get_bottom(hwmp_ie);
+
+		orig_addr = preq_elem_top->orig_addr;
+		orig_sn = get_unaligned_le32(&preq_elem_top->orig_sn);
+		orig_lifetime = get_unaligned_le32(&preq_elem_bottom->lifetime);
+		orig_metric = get_unaligned_le32(&preq_elem_bottom->metric);
+		hopcount = preq_elem_top->hopcount + 1;
 		break;
 	case MPATH_PREP:
 		/* Originator here refers to the MP that was the target in the
@@ -579,6 +571,12 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 				    const u8 *preq_elem, u32 orig_metric)
 {
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	struct ieee80211_mesh_hwmp_preq_top *preq_elem_top =
+		(struct ieee80211_mesh_hwmp_preq_top *)preq_elem;
+	struct ieee80211_mesh_hwmp_preq_bottom *preq_elem_bottom =
+		ieee80211_mesh_hwmp_preq_get_bottom(preq_elem);
+	struct ieee80211_mesh_hwmp_preq_target *target =
+		preq_elem_bottom->targets;
 	struct mesh_path *mpath = NULL;
 	const u8 *target_addr, *orig_addr;
 	const u8 *da;
@@ -589,13 +587,13 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 	bool root_is_gate;
 
 	/* Update target SN, if present */
-	target_addr = PREQ_IE_TARGET_ADDR(preq_elem);
-	orig_addr = PREQ_IE_ORIG_ADDR(preq_elem);
-	target_sn = PREQ_IE_TARGET_SN(preq_elem);
-	orig_sn = PREQ_IE_ORIG_SN(preq_elem);
-	target_flags = PREQ_IE_TARGET_F(preq_elem);
+	target_addr = target[0].addr;
+	orig_addr = preq_elem_top->orig_addr;
+	target_sn = get_unaligned_le32(&target[0].sn);
+	orig_sn = get_unaligned_le32(&preq_elem_top->orig_sn);
+	target_flags = target[0].flags;
 	/* Proactive PREQ gate announcements */
-	flags = PREQ_IE_FLAGS(preq_elem);
+	flags = preq_elem_top->flags;
 	root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
 
 	mhwmp_dbg(sdata, "received PREQ from %pM\n", orig_addr);
@@ -655,7 +653,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 	}
 
 	if (reply) {
-		lifetime = PREQ_IE_LIFETIME(preq_elem);
+		lifetime = get_unaligned_le32(&preq_elem_bottom->lifetime);
 		ttl = ifmsh->mshcfg.element_ttl;
 		if (ttl != 0) {
 			mhwmp_dbg(sdata, "replying to the PREQ\n");
@@ -673,22 +671,22 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 		u32 preq_id;
 		u8 hopcount;
 
-		ttl = PREQ_IE_TTL(preq_elem);
-		lifetime = PREQ_IE_LIFETIME(preq_elem);
+		ttl = preq_elem_top->ttl;
+		lifetime = get_unaligned_le32(&preq_elem_bottom->lifetime);
 		if (ttl <= 1) {
 			ifmsh->mshstats.dropped_frames_ttl++;
 			return;
 		}
 		mhwmp_dbg(sdata, "forwarding the PREQ from %pM\n", orig_addr);
 		--ttl;
-		preq_id = PREQ_IE_PREQ_ID(preq_elem);
-		hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
+		preq_id = get_unaligned_le32(&preq_elem_top->preq_id);
+		hopcount = preq_elem_top->hopcount + 1;
 		da = (mpath && mpath->is_root) ?
 			mpath->rann_snd_addr : broadcast_addr;
 
 		if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) {
-			target_addr = PREQ_IE_TARGET_ADDR(preq_elem);
-			target_sn = PREQ_IE_TARGET_SN(preq_elem);
+			target_addr = target[0].addr;
+			target_sn = get_unaligned_le32(&target[0].sn);
 		}
 
 		mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
-- 
2.43.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