]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: mac80211: fix monitor channel with chanctx emulation
authorJohannes Berg <johannes.berg@intel.com>
Wed, 12 Jun 2024 10:23:51 +0000 (12:23 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Jun 2024 11:52:28 +0000 (13:52 +0200)
commit 0d9c2beed116e623ac30810d382bd67163650f98 upstream.

After the channel context emulation, there were reports that
changing the monitor channel no longer works. This is because
those drivers don't have WANT_MONITOR_VIF, so the setting the
channel always exits out quickly.

Fix this by always allocating the virtual monitor sdata, and
simply not telling the driver about it unless it wanted to.
This way, we have an interface/sdata to bind the chanctx to,
and the emulation can work correctly.

Cc: stable@vger.kernel.org
Fixes: 0a44dfc07074 ("wifi: mac80211: simplify non-chanctx drivers")
Reported-and-tested-by: Savyasaachi Vanga <savyasaachiv@gmail.com>
Closes: https://lore.kernel.org/r/chwoymvpzwtbmzryrlitpwmta5j6mtndocxsyqvdyikqu63lon@gfds653hkknl
Link: https://msgid.link/20240612122351.b12d4a109dde.I1831a44417faaab92bea1071209abbe4efbe3fba@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/mac80211/driver-ops.c
net/mac80211/iface.c
net/mac80211/util.c

index dce37ba8ebe3744700e8dd83abf1ab3216957796..254d745832cbfeda8165c340abe21439067c7102 100644 (file)
@@ -311,6 +311,18 @@ int drv_assign_vif_chanctx(struct ieee80211_local *local,
        might_sleep();
        lockdep_assert_wiphy(local->hw.wiphy);
 
+       /*
+        * We should perhaps push emulate chanctx down and only
+        * make it call ->config() when the chanctx is actually
+        * assigned here (and unassigned below), but that's yet
+        * another change to all drivers to add assign/unassign
+        * emulation callbacks. Maybe later.
+        */
+       if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
+           local->emulate_chanctx &&
+           !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
+               return 0;
+
        if (!check_sdata_in_driver(sdata))
                return -EIO;
 
@@ -338,6 +350,11 @@ void drv_unassign_vif_chanctx(struct ieee80211_local *local,
        might_sleep();
        lockdep_assert_wiphy(local->hw.wiphy);
 
+       if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
+           local->emulate_chanctx &&
+           !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
+               return;
+
        if (!check_sdata_in_driver(sdata))
                return;
 
index d759ef2b88c245691222ff63cfdd4237a5387350..7c8a421f0901d2b90e6b57f98614bfc7eb4093c3 100644 (file)
@@ -1122,9 +1122,6 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
        struct ieee80211_sub_if_data *sdata;
        int ret;
 
-       if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
-               return 0;
-
        ASSERT_RTNL();
        lockdep_assert_wiphy(local->hw.wiphy);
 
@@ -1146,11 +1143,13 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
 
        ieee80211_set_default_queues(sdata);
 
-       ret = drv_add_interface(local, sdata);
-       if (WARN_ON(ret)) {
-               /* ok .. stupid driver, it asked for this! */
-               kfree(sdata);
-               return ret;
+       if (ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF)) {
+               ret = drv_add_interface(local, sdata);
+               if (WARN_ON(ret)) {
+                       /* ok .. stupid driver, it asked for this! */
+                       kfree(sdata);
+                       return ret;
+               }
        }
 
        set_bit(SDATA_STATE_RUNNING, &sdata->state);
@@ -1188,9 +1187,6 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata;
 
-       if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
-               return;
-
        ASSERT_RTNL();
        lockdep_assert_wiphy(local->hw.wiphy);
 
@@ -1210,7 +1206,8 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
 
        ieee80211_link_release_channel(&sdata->deflink);
 
-       drv_remove_interface(local, sdata);
+       if (ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
+               drv_remove_interface(local, sdata);
 
        kfree(sdata);
 }
index a237cbcf7b49100af8da21b54a29707ed8f7ec91..0da5f6082d159104ba687d74ae6f40826f6257fe 100644 (file)
@@ -1841,7 +1841,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 
        /* add interfaces */
        sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata);
-       if (sdata) {
+       if (sdata && ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF)) {
                /* in HW restart it exists already */
                WARN_ON(local->resuming);
                res = drv_add_interface(local, sdata);