if (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) { res = drv_add_interface(local, sdata); if (res) goto err_stop; } else if (local->monitors == 0 && local->open_count == 0) { res = ieee80211_add_virtual_monitor(local); So I'm not sure if the patch is what we want... I'm also wondering, if we couldn't/shouldn't also drop %MONITOR_FLAG_ACTIVE and %MONITOR_FLAG_COOK_FRAMES. I did not find a single use for them. Thus, I'm also not sure I handle them correctly here. A monitor interface with %MONITOR_FLAG_COOK_FRAMES was not picking up any frames with or without this patch.. And %MONITOR_FLAG_ACTIVE does not work for iwlmvm. (At least one of them was probably for ancient versions of hostapd...) Alexander --- net/mac80211/cfg.c | 9 +++++---- net/mac80211/ethtool.c | 7 ++++--- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/iface.c | 26 ++++++++++++++++++-------- net/mac80211/pm.c | 1 - net/mac80211/scan.c | 2 +- net/mac80211/util.c | 2 +- 7 files changed, 30 insertions(+), 19 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b8495d5f2297..fbdd6b46b154 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -4366,10 +4366,11 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy, if (chanctx_conf) { *chandef = link->conf->chanreq.oper; ret = 0; - } else if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) && - local->open_count > 0 && - local->open_count == local->monitors && - sdata->vif.type == NL80211_IFTYPE_MONITOR) { + } else if (local->virt_monitors && + local->open_count == local->virt_monitors && + sdata->vif.type == NL80211_IFTYPE_MONITOR && + !(sdata->u.mntr.flags & (MONITOR_FLAG_ACTIVE | + MONITOR_FLAG_COOK_FRAMES))) { *chandef = local->monitor_chanreq.oper; ret = 0; } diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c index 42f7ee142ce3..52a278232c9d 100644 --- a/net/mac80211/ethtool.c +++ b/net/mac80211/ethtool.c @@ -157,9 +157,10 @@ static void ieee80211_get_stats(struct net_device *dev, chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (chanctx_conf) channel = chanctx_conf->def.chan; - else if (local->open_count > 0 && - local->open_count == local->monitors && - sdata->vif.type == NL80211_IFTYPE_MONITOR) + else if (local->virt_monitors && + sdata->vif.type == NL80211_IFTYPE_MONITOR && + !(sdata->u.mntr.flags & (MONITOR_FLAG_ACTIVE | + MONITOR_FLAG_COOK_FRAMES))) channel = local->monitor_chanreq.oper.chan; else channel = NULL; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a98133d5c362..8aceec18ffaf 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1367,7 +1367,7 @@ struct ieee80211_local { spinlock_t queue_stop_reason_lock; int open_count; - int monitors, cooked_mntrs, tx_mntrs; + int monitors, virt_monitors, cooked_mntrs, tx_mntrs; /* number of interfaces with corresponding FIF_ flags */ int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll, fif_probe_req; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 2e170dbde732..b0c02942dac3 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -589,6 +589,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do break; } + if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) && + !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) && + !WARN_ON(local->virt_monitors <= 0)) + local->virt_monitors--; + local->monitors--; if (local->monitors == 0) { local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; @@ -686,7 +691,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do case NL80211_IFTYPE_AP_VLAN: break; case NL80211_IFTYPE_MONITOR: - if (local->monitors == 0) + if (local->virt_monitors == 0) ieee80211_del_virtual_monitor(local); ieee80211_recalc_idle(local); @@ -723,7 +728,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do ieee80211_configure_filter(local); ieee80211_hw_config(local, hw_reconf_flags); - if (local->monitors == local->open_count) + if (local->virt_monitors && + local->virt_monitors == local->open_count) ieee80211_add_virtual_monitor(local); } @@ -1129,7 +1135,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) lockdep_assert_wiphy(local->hw.wiphy); if (local->monitor_sdata || - ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) + WARN_ON(ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))) return 0; sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); @@ -1336,15 +1342,19 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) res = drv_add_interface(local, sdata); if (res) goto err_stop; - } else if (local->monitors == 0 && local->open_count == 0) { - res = ieee80211_add_virtual_monitor(local); - if (res) - goto err_stop; + } else { + if (local->virt_monitors == 0 && + local->open_count == 0) { + res = ieee80211_add_virtual_monitor(local); + if (res) + goto err_stop; + } + local->virt_monitors++; } /* must be before the call to ieee80211_configure_filter */ local->monitors++; - if (local->monitors == 1) { + if (local->monitors == 1 && local->virt_monitors == 1) { local->hw.conf.flags |= IEEE80211_CONF_MONITOR; hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; } diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 7be52345f218..b914a1eeba82 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -150,7 +150,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) continue; switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_MONITOR: continue; case NL80211_IFTYPE_STATION: ieee80211_mgd_quiesce(sdata); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index cb7079071885..4eb0cf5f73ca 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -334,7 +334,7 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) } /* Do not update the BSS table in case of only monitor interfaces */ - if (local->open_count == local->monitors) + if (local->open_count == local->monitors + local->cooked_mntrs) return; bss = ieee80211_bss_info_update(local, rx_status, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7b656326e68a..86320ecf306c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2153,7 +2153,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) wake_up: - if (local->monitors == local->open_count && local->monitors > 0) + if (local->virt_monitors == local->open_count && local->monitors > 0) ieee80211_add_virtual_monitor(local); /* -- 2.48.1