mac80211: Fix setting TX power on monitor interfaces
authorPeter Große <pegro@friiks.de>
Wed, 13 Dec 2017 17:29:46 +0000 (18:29 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 13 Apr 2018 17:48:10 +0000 (19:48 +0200)
[ Upstream commit 3a3713ec360138f806c6fc368d1de570f692b347 ]

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>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/mac80211/cfg.c
net/mac80211/driver-ops.h

index efa2a2fcae72b92ba61c08533b1f8cdb84bceaea..d7801f6877af1c4aa9ec5c1e40457fa8e6144e4e 100644 (file)
@@ -2341,10 +2341,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;
@@ -2383,15 +2390,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;
 }
 
index 09f77e4a8a79d78f5722a85470bfa0862671e43e..49c8a9c9b91f4078fac9b0191122874edef4f28c 100644 (file)
@@ -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))