diff mbox

mac80211: Fix setting TX power on monitor interfaces

Message ID 20171213172946.19976-1-pegro@friiks.de (mailing list archive)
State Accepted
Delegated to: Johannes Berg
Headers show

Commit Message

Peter Große Dec. 13, 2017, 5:29 p.m. UTC
Instead of calling ieee80211_recalc_txpower on monitor interfaces
directly, call it using the virtual monitor interface, if one exists.

In case of a single monitor interface given, reject setting TX power,
if no virtual monitor interface exists.

That being checked, don't warn in ieee80211_bss_info_change_notify,
after setting TX power on a monitor interface.

Fixes warning:
------------[ cut here ]------------
 WARNING: CPU: 0 PID: 2193 at net/mac80211/driver-ops.h:167
 ieee80211_bss_info_change_notify+0x111/0x190 Modules linked in: uvcvideo
 videobuf2_vmalloc videobuf2_memops videobuf2_v4l2 videobuf2_core
rndis_host cdc_ether usbnet mii tp_smapi(O) thinkpad_ec(O) ohci_hcd vboxpci(O)
 vboxnetadp(O) vboxnetflt(O) v boxdrv(O) x86_pkg_temp_thermal kvm_intel kvm
 irqbypass iwldvm iwlwifi ehci_pci ehci_hcd tpm_tis tpm_tis_core tpm CPU: 0
 PID: 2193 Comm: iw Tainted: G           O    4.12.12-gentoo #2 task:
 ffff880186fd5cc0 task.stack: ffffc90001b54000 RIP:
 0010:ieee80211_bss_info_change_notify+0x111/0x190 RSP: 0018:ffffc90001b57a10
 EFLAGS: 00010246 RAX: 0000000000000006 RBX: ffff8801052ce840 RCX:
 0000000000000064 RDX: 00000000fffffffc RSI: 0000000000040000 RDI:
 ffff8801052ce840 RBP: ffffc90001b57a38 R08: 0000000000000062 R09:
 0000000000000000 R10: ffff8802144b5000 R11: ffff880049dc4614 R12:
 0000000000040000 R13: 0000000000000064 R14: ffff8802105f0760 R15:
 ffffc90001b57b48 FS:  00007f92644b4580(0000) GS:ffff88021e200000(0000)
 knlGS:0000000000000000 CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
 CR2: 00007f9263c109f0 CR3: 00000001df850000 CR4: 00000000000406f0
 Call Trace:
  ieee80211_recalc_txpower+0x33/0x40
  ieee80211_set_tx_power+0x40/0x180
  nl80211_set_wiphy+0x32e/0x950

Reported-by: Peter Große <pegro@friiks.de>
Signed-off-by: Peter Große <pegro@friiks.de>
---

Since monitor_sdata->vif.type is also NL80211_IFTYPE_MONITOR,
the warning would still appear with the patch to cfg.c, so I excluded 
that case from the WARN_ON_ONCE condition.

I hope that makes sense?!

It fixes the warning for me though.

Regards
Peter

 net/mac80211/cfg.c        | 28 +++++++++++++++++++++++++++-
 net/mac80211/driver-ops.h |  3 ++-
 2 files changed, 29 insertions(+), 2 deletions(-)

Comments

Johannes Berg Dec. 19, 2017, 9:53 a.m. UTC | #1
Hi,

> Since monitor_sdata->vif.type is also NL80211_IFTYPE_MONITOR,
> the warning would still appear with the patch to cfg.c, so I excluded 
> that case from the WARN_ON_ONCE condition.
> 
> I hope that makes sense?!

Yeah, looks good.

>  	if (wdev) {
>  		sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
>  
> +		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
> +			sdata = rtnl_dereference(local->monitor_sdata);
> +			if (!sdata)
> +				return -EOPNOTSUPP;
> +		}

This part makes perfect sense.

>  	mutex_lock(&local->iflist_mtx);
>  	list_for_each_entry(sdata, &local->interfaces, list) {
> +		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
> +			has_monitor = true;
> +			continue;
> +		}
>  		sdata->user_power_level = local->user_power_level;
>  		if (txp_type != sdata->vif.bss_conf.txpower_type)
>  			update_txp_type = true;
>  		sdata->vif.bss_conf.txpower_type = txp_type;
>  	}
> -	list_for_each_entry(sdata, &local->interfaces, list)
> +	list_for_each_entry(sdata, &local->interfaces, list) {
> +		if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
> +			continue;
>  		ieee80211_recalc_txpower(sdata, update_txp_type);
> +	}
>  	mutex_unlock(&local->iflist_mtx);
>  
> +	if (has_monitor) {
> +		sdata = rtnl_dereference(local->monitor_sdata);
> +		if (sdata) {
> +			sdata->user_power_level = local->user_power_level;
> +			if (txp_type != sdata->vif.bss_conf.txpower_type)
> +				update_txp_type = true;
> +			sdata->vif.bss_conf.txpower_type = txp_type;
> +
> +			ieee80211_recalc_txpower(sdata, update_txp_type);
> +		}
> +	}

But do we really need this? I think we can probably live with just not
having monitor handled here, i.e. only have the "if monitor continue;"
part?

johannes
Peter Große Dec. 19, 2017, 7:25 p.m. UTC | #2
On Tue, 19 Dec 2017 10:53:30 +0100
Johannes Berg <johannes@sipsolutions.net> wrote:

> > +	if (has_monitor) {
> > +		sdata = rtnl_dereference(local->monitor_sdata);
> > +		if (sdata) {
> > +			sdata->user_power_level = local->user_power_level;
> > +			if (txp_type != sdata->vif.bss_conf.txpower_type)
> > +				update_txp_type = true;
> > +			sdata->vif.bss_conf.txpower_type = txp_type;
> > +
> > +			ieee80211_recalc_txpower(sdata, update_txp_type);
> > +		}
> > +	}  
> 
> But do we really need this? I think we can probably live with just not
> having monitor handled here, i.e. only have the "if monitor continue;"
> part?

I don't mind. I just thought, if I call ieee80211_recalc_txpower on the
monitor_sdata interface when called explicitly, I would also do it when
iterating over all interfaces, just to be consistent. I don't know, whether
there are drivers out there, that store power limits on monitor interfaces
separately for injection or whatever.

I can send a patch without the quoted part.

Regards
Peter
diff mbox

Patch

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a354f1939e49..29874052e162 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2373,10 +2373,17 @@  static int ieee80211_set_tx_power(struct wiphy *wiphy,
 	struct ieee80211_sub_if_data *sdata;
 	enum nl80211_tx_power_setting txp_type = type;
 	bool update_txp_type = false;
+	bool has_monitor = false;
 
 	if (wdev) {
 		sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
 
+		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+			sdata = rtnl_dereference(local->monitor_sdata);
+			if (!sdata)
+				return -EOPNOTSUPP;
+		}
+
 		switch (type) {
 		case NL80211_TX_POWER_AUTOMATIC:
 			sdata->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
@@ -2415,15 +2422,34 @@  static int ieee80211_set_tx_power(struct wiphy *wiphy,
 
 	mutex_lock(&local->iflist_mtx);
 	list_for_each_entry(sdata, &local->interfaces, list) {
+		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+			has_monitor = true;
+			continue;
+		}
 		sdata->user_power_level = local->user_power_level;
 		if (txp_type != sdata->vif.bss_conf.txpower_type)
 			update_txp_type = true;
 		sdata->vif.bss_conf.txpower_type = txp_type;
 	}
-	list_for_each_entry(sdata, &local->interfaces, list)
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
+			continue;
 		ieee80211_recalc_txpower(sdata, update_txp_type);
+	}
 	mutex_unlock(&local->iflist_mtx);
 
+	if (has_monitor) {
+		sdata = rtnl_dereference(local->monitor_sdata);
+		if (sdata) {
+			sdata->user_power_level = local->user_power_level;
+			if (txp_type != sdata->vif.bss_conf.txpower_type)
+				update_txp_type = true;
+			sdata->vif.bss_conf.txpower_type = txp_type;
+
+			ieee80211_recalc_txpower(sdata, update_txp_type);
+		}
+	}
+
 	return 0;
 }
 
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 09f77e4a8a79..49c8a9c9b91f 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -164,7 +164,8 @@  static inline void drv_bss_info_changed(struct ieee80211_local *local,
 	if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
 			 sdata->vif.type == NL80211_IFTYPE_NAN ||
 			 (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
-			  !sdata->vif.mu_mimo_owner)))
+			  !sdata->vif.mu_mimo_owner &&
+			  !(changed & BSS_CHANGED_TXPOWER))))
 		return;
 
 	if (!check_sdata_in_driver(sdata))