Active monitor interfaces are added to the driver as real VIFs so that frames addressed to their MAC address can be acknowledged. However, ieee80211_set_monitor_channel() redirects monitor channel changes to the hidden monitor_sdata whenever the driver does not set NO_VIRTUAL_MONITOR. An active-only monitor does not create monitor_sdata, so the function can return success after only updating monitor_chanreq. The active monitor itself never gets a channel context, making channel changes ineffective. Use the active monitor VIF directly when changing channels, while keeping monitor_chanreq private to the hidden virtual monitor. Also treat active monitors as valid directly channel-bound monitor interfaces in channel width and SMPS accounting. This fixes active monitor channel switching with mac80211_hwsim. Before this change, an active monitor failed to discover any APs while scanning. With the fix applied, scanning works across channels 1, 6 and 11 with both channels=1 and channels=2, and authentication and association on channel 6 succeed without mac80211 or hwsim warnings. Fixes: 0a44dfc07074 ("wifi: mac80211: simplify non-chanctx drivers") Assisted-by: Codex:gpt-5.6-sol Signed-off-by: Matheus Alves de Almeida --- net/mac80211/cfg.c | 9 +++++++-- net/mac80211/chan.c | 8 ++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 43f142624d33..c844ae2abcb4 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1064,12 +1064,16 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_sub_if_data *sdata; struct ieee80211_chan_req chanreq = { .oper = *chandef }; + bool use_virtual_monitor; int ret; lockdep_assert_wiphy(local->hw.wiphy); sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) { + use_virtual_monitor = + !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) && + !(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE); + if (use_virtual_monitor) { if (cfg80211_chandef_identical(&local->monitor_chanreq.oper, &chanreq.oper)) return 0; @@ -1090,7 +1094,8 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, if (ret) return ret; done: - local->monitor_chanreq = chanreq; + if (use_virtual_monitor) + local->monitor_chanreq = chanreq; return 0; } diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 5152b84a3357..800b7585c010 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -543,7 +543,9 @@ ieee80211_get_width_of_link(struct ieee80211_link_data *link) case NL80211_IFTYPE_P2P_DEVICE: break; case NL80211_IFTYPE_MONITOR: - WARN_ON_ONCE(!ieee80211_hw_check(&local->hw, + WARN_ON_ONCE(!(link->sdata->u.mntr.flags & + MONITOR_FLAG_ACTIVE) && + !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)); fallthrough; case NL80211_IFTYPE_ADHOC: @@ -1279,7 +1281,9 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, continue; break; case NL80211_IFTYPE_MONITOR: - if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) + if (!(iter.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) && + !ieee80211_hw_check(&local->hw, + NO_VIRTUAL_MONITOR)) continue; break; case NL80211_IFTYPE_AP: -- 2.47.3