[PATCH] wifi: mac80211: fix monitor mode frame capture for real chanctx drivers

From: 傅继晗

Date: Sun Mar 08 2026 - 12:45:45 EST


Commit 0a44dfc07074 ("wifi: mac80211: simplify non-chanctx drivers")
removed the fallback path in ieee80211_monitor_start_xmit() for when
the monitor interface has no channel context assigned. This broke frame
capture and injection for drivers that implement real channel context
ops (as opposed to the ieee80211_emulate_* helpers), such as the mt76
family, when a monitor interface runs alongside another interface
(e.g. managed mode).

In that scenario the (virtual) monitor sdata does not get a chanctx of
its own, even though there is an active one from the other interface.
Before the simplification the code fell back to local->_oper_chandef;
after it, the code goes straight to fail_rcu and silently drops every
injected frame.

Commit d594cc6f2c58 ("wifi: mac80211: restore non-chanctx injection
behaviour") restored the fallback for drivers using emulate_chanctx,
but explicitly left real chanctx drivers unfixed.

Fix this by falling back to the first entry in local->chanctx_list
when the monitor vif has no chanctx and the driver uses real channel
contexts. This is analogous to how ieee80211_hw_conf_chan() already
uses the same pattern.

Tested on MT7921AU (mt76) USB adapter:
- v6.13: managed + monitor coexistence restored (0 -> 37 frames/5s)
- v6.19: managed + monitor coexistence restored (0 -> 39 frames/5s)
- v7.0-rc2: managed + monitor coexistence restored (0 -> 33 frames/5s)

Cc: stable@xxxxxxxxxxxxxxx
Fixes: 0a44dfc07074 ("wifi: mac80211: simplify non-chanctx drivers")
Link: https://github.com/morrownr/USB-WiFi/issues/682
Signed-off-by: 傅继晗 <fjhhz1997@xxxxxxxxx>
---
net/mac80211/tx.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 8cdbd41..56eaf9a 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2396,12 +2396,28 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
rcu_dereference(tmp_sdata->vif.bss_conf.chanctx_conf);
}

- if (chanctx_conf)
+ if (chanctx_conf) {
chandef = &chanctx_conf->def;
- else if (local->emulate_chanctx)
+ } else if (local->emulate_chanctx) {
chandef = &local->hw.conf.chandef;
- else
- goto fail_rcu;
+ } else {
+ /*
+ * For real chanctx drivers (e.g. mt76), the monitor
+ * interface may not have a chanctx assigned when running
+ * concurrently with another interface. Fall back to any
+ * active chanctx so that injection can still work on the
+ * operating channel.
+ */
+ struct ieee80211_chanctx *ctx;
+
+ ctx = list_first_entry_or_null(&local->chanctx_list,
+ struct ieee80211_chanctx,
+ list);
+ if (ctx)
+ chandef = &ctx->conf.def;
+ else
+ goto fail_rcu;
+ }

/*
* If driver/HW supports IEEE80211_CHAN_CAN_MONITOR we still
--
2.43.0