wifi: mac80211: always hold sdata lock in chanctx assign/unassign
authorJohannes Berg <johannes.berg@intel.com>
Mon, 19 Jun 2023 13:26:49 +0000 (16:26 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 21 Jun 2023 12:01:28 +0000 (14:01 +0200)
Due to all the multi-link handling, we now expose the fact that
the sdata/vif is locked to drivers, e.g. when the driver uses
ieee80211_set_monitor_channel(). This was true when a chanctx
is added to or removed from a link, _except_ in monitor mode
with the virtual sdata/vif. Change that, so that drivers can
make that assumption.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230619161906.a5cf7534beda.I5b51664231abee27e02f222083df7ccf88722929@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/cfg.c
net/mac80211/iface.c

index eea7028..e7ac246 100644 (file)
@@ -913,24 +913,30 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
        if (cfg80211_chandef_identical(&local->monitor_chandef, chandef))
                return 0;
 
-       mutex_lock(&local->mtx);
        if (local->use_chanctx) {
                sdata = wiphy_dereference(local->hw.wiphy,
                                          local->monitor_sdata);
                if (sdata) {
+                       sdata_lock(sdata);
+                       mutex_lock(&local->mtx);
                        ieee80211_link_release_channel(&sdata->deflink);
                        ret = ieee80211_link_use_channel(&sdata->deflink,
                                                         chandef,
                                                         IEEE80211_CHANCTX_EXCLUSIVE);
+                       mutex_unlock(&local->mtx);
+                       sdata_unlock(sdata);
+               }
+       } else {
+               mutex_lock(&local->mtx);
+               if (local->open_count == local->monitors) {
+                       local->_oper_chandef = *chandef;
+                       ieee80211_hw_config(local, 0);
                }
-       } else if (local->open_count == local->monitors) {
-               local->_oper_chandef = *chandef;
-               ieee80211_hw_config(local, 0);
+               mutex_unlock(&local->mtx);
        }
 
        if (ret == 0)
                local->monitor_chandef = *chandef;
-       mutex_unlock(&local->mtx);
 
        return ret;
 }
index 9518acf..be586bc 100644 (file)
@@ -1133,6 +1133,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
        snprintf(sdata->name, IFNAMSIZ, "%s-monitor",
                 wiphy_name(local->hw.wiphy));
        sdata->wdev.iftype = NL80211_IFTYPE_MONITOR;
+       mutex_init(&sdata->wdev.mtx);
 
        ieee80211_sdata_init(local, sdata);
 
@@ -1157,16 +1158,19 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
        rcu_assign_pointer(local->monitor_sdata, sdata);
        mutex_unlock(&local->iflist_mtx);
 
+       sdata_lock(sdata);
        mutex_lock(&local->mtx);
        ret = ieee80211_link_use_channel(&sdata->deflink, &local->monitor_chandef,
                                         IEEE80211_CHANCTX_EXCLUSIVE);
        mutex_unlock(&local->mtx);
+       sdata_unlock(sdata);
        if (ret) {
                mutex_lock(&local->iflist_mtx);
                RCU_INIT_POINTER(local->monitor_sdata, NULL);
                mutex_unlock(&local->iflist_mtx);
                synchronize_net();
                drv_remove_interface(local, sdata);
+               mutex_destroy(&sdata->wdev.mtx);
                kfree(sdata);
                return ret;
        }
@@ -1202,12 +1206,15 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
 
        synchronize_net();
 
+       sdata_lock(sdata);
        mutex_lock(&local->mtx);
        ieee80211_link_release_channel(&sdata->deflink);
        mutex_unlock(&local->mtx);
+       sdata_unlock(sdata);
 
        drv_remove_interface(local, sdata);
 
+       mutex_destroy(&sdata->wdev.mtx);
        kfree(sdata);
 }