Commit 8f4fa087 authored by Johannes Berg's avatar Johannes Berg
Browse files

wifi: mac80211: use monitor sdata with driver only if desired



In commit 0d9c2bee ("wifi: mac80211: fix monitor channel
with chanctx emulation") I changed mac80211 to always have an
internal monitor_sdata to have something to have the chanctx
bound to.

However, if the driver didn't also have the WANT_MONITOR flag
this would cause mac80211 to allocate it without telling the
driver (which was intentional) but also use it for later APIs
to the driver without it ever having known about it which was
_not_ intentional.

Check through the code and only use the monitor_sdata in the
relevant places (TX, MU-MIMO follow settings, TX power, and
interface iteration) when the WANT_MONITOR flag is set.

Cc: stable@vger.kernel.org
Fixes: 0d9c2bee ("wifi: mac80211: fix monitor channel with chanctx emulation")
Reported-by: default avatarZeroBeat <ZeroBeat@gmx.de>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219086


Tested-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20240725184836.25d334157a8e.I02574086da2c5cf0e18264ce5807db6f14ffd9c0@changeid


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 1722389b
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -114,7 +114,7 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,

	/* apply all changes now - no failures allowed */

	if (monitor_sdata)
	if (monitor_sdata && ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
		ieee80211_set_mu_mimo_follow(monitor_sdata, params);

	if (params->flags) {
@@ -3053,6 +3053,9 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
		sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);

		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
			if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
				return -EOPNOTSUPP;

			sdata = wiphy_dereference(local->hw.wiphy,
						  local->monitor_sdata);
			if (!sdata)
@@ -3115,7 +3118,7 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
	if (has_monitor) {
		sdata = wiphy_dereference(local->hw.wiphy,
					  local->monitor_sdata);
		if (sdata) {
		if (sdata && ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF)) {
			sdata->deflink.user_power_level = local->user_power_level;
			if (txp_type != sdata->vif.bss_conf.txpower_type)
				update_txp_type = true;
+3 −2
Original line number Diff line number Diff line
@@ -1768,7 +1768,7 @@ static bool __ieee80211_tx(struct ieee80211_local *local,
			break;
		}
		sdata = rcu_dereference(local->monitor_sdata);
		if (sdata) {
		if (sdata && ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF)) {
			vif = &sdata->vif;
			info->hw_queue =
				vif->hw_queue[skb_get_queue_mapping(skb)];
@@ -3957,7 +3957,8 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
			break;
		}
		tx.sdata = rcu_dereference(local->monitor_sdata);
		if (tx.sdata) {
		if (tx.sdata &&
		    ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF)) {
			vif = &tx.sdata->vif;
			info->hw_queue =
				vif->hw_queue[skb_get_queue_mapping(skb)];
+1 −1
Original line number Diff line number Diff line
@@ -776,7 +776,7 @@ static void __iterate_interfaces(struct ieee80211_local *local,
	sdata = rcu_dereference_check(local->monitor_sdata,
				      lockdep_is_held(&local->iflist_mtx) ||
				      lockdep_is_held(&local->hw.wiphy->mtx));
	if (sdata &&
	if (sdata && ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
	    (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || !active_only ||
	     sdata->flags & IEEE80211_SDATA_IN_DRIVER))
		iterator(data, sdata->vif.addr, &sdata->vif);