Commit 4484de23 authored by Johannes Berg's avatar Johannes Berg
Browse files

wifi: mac80211: always hold sdata lock in chanctx assign/unassign



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: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230619161906.a5cf7534beda.I5b51664231abee27e02f222083df7ccf88722929@changeid


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 5c1f9753
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -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 if (local->open_count == local->monitors) {
	} else {
		mutex_lock(&local->mtx);
		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;
}
+7 −0
Original line number Diff line number Diff line
@@ -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);
}