aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-10-24 04:59:25 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-10-30 04:11:34 -0400
commit1ea6f9c0d48b11b6ec3ec4b5579ec74fc3951cf8 (patch)
tree5a589d0bccfcac6ba0952942a04482b99752ddcc /net/mac80211
parentc8442118ad9cd05cfe3b993f058e70ab25b1009a (diff)
mac80211: handle TX power per virtual interface
Even before channel contexts/multi-channel, having a single global TX power limit was already problematic, in particular if two managed interfaces connected to two APs with different power constraints. The channel context introduction completely broke this though and in fact I had disabled TX power configuration there for drivers using channel contexts. Change everything to track TX power per interface so that different user settings and different channel maxima are treated correctly. Also continue tracking the global TX power though for compatibility with applications that attempt to configure the wiphy's TX power globally. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/cfg.c47
-rw-r--r--net/mac80211/chan.c2
-rw-r--r--net/mac80211/debugfs_netdev.c6
-rw-r--r--net/mac80211/ieee80211_i.h12
-rw-r--r--net/mac80211/iface.c38
-rw-r--r--net/mac80211/main.c27
-rw-r--r--net/mac80211/mlme.c32
-rw-r--r--net/mac80211/trace.h2
-rw-r--r--net/mac80211/util.c3
9 files changed, 125 insertions, 44 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a352e4d22dd9..986e9a139d42 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1996,33 +1996,46 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
1996 enum nl80211_tx_power_setting type, int mbm) 1996 enum nl80211_tx_power_setting type, int mbm)
1997{ 1997{
1998 struct ieee80211_local *local = wiphy_priv(wiphy); 1998 struct ieee80211_local *local = wiphy_priv(wiphy);
1999 struct ieee80211_channel *chan = local->_oper_channel; 1999 struct ieee80211_sub_if_data *sdata;
2000 u32 changes = 0;
2001 2000
2002 /* FIXME */ 2001 if (wdev) {
2003 if (local->use_chanctx) 2002 sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
2004 return -EOPNOTSUPP; 2003
2004 switch (type) {
2005 case NL80211_TX_POWER_AUTOMATIC:
2006 sdata->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
2007 break;
2008 case NL80211_TX_POWER_LIMITED:
2009 case NL80211_TX_POWER_FIXED:
2010 if (mbm < 0 || (mbm % 100))
2011 return -EOPNOTSUPP;
2012 sdata->user_power_level = MBM_TO_DBM(mbm);
2013 break;
2014 }
2015
2016 ieee80211_recalc_txpower(sdata);
2017
2018 return 0;
2019 }
2005 2020
2006 switch (type) { 2021 switch (type) {
2007 case NL80211_TX_POWER_AUTOMATIC: 2022 case NL80211_TX_POWER_AUTOMATIC:
2008 local->user_power_level = -1; 2023 local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
2009 break; 2024 break;
2010 case NL80211_TX_POWER_LIMITED: 2025 case NL80211_TX_POWER_LIMITED:
2011 if (mbm < 0 || (mbm % 100))
2012 return -EOPNOTSUPP;
2013 local->user_power_level = MBM_TO_DBM(mbm);
2014 break;
2015 case NL80211_TX_POWER_FIXED: 2026 case NL80211_TX_POWER_FIXED:
2016 if (mbm < 0 || (mbm % 100)) 2027 if (mbm < 0 || (mbm % 100))
2017 return -EOPNOTSUPP; 2028 return -EOPNOTSUPP;
2018 /* TODO: move to cfg80211 when it knows the channel */
2019 if (MBM_TO_DBM(mbm) > chan->max_power)
2020 return -EINVAL;
2021 local->user_power_level = MBM_TO_DBM(mbm); 2029 local->user_power_level = MBM_TO_DBM(mbm);
2022 break; 2030 break;
2023 } 2031 }
2024 2032
2025 ieee80211_hw_config(local, changes); 2033 mutex_lock(&local->iflist_mtx);
2034 list_for_each_entry(sdata, &local->interfaces, list)
2035 sdata->user_power_level = local->user_power_level;
2036 list_for_each_entry(sdata, &local->interfaces, list)
2037 ieee80211_recalc_txpower(sdata);
2038 mutex_unlock(&local->iflist_mtx);
2026 2039
2027 return 0; 2040 return 0;
2028} 2041}
@@ -2032,8 +2045,12 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy,
2032 int *dbm) 2045 int *dbm)
2033{ 2046{
2034 struct ieee80211_local *local = wiphy_priv(wiphy); 2047 struct ieee80211_local *local = wiphy_priv(wiphy);
2048 struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
2035 2049
2036 *dbm = local->hw.conf.power_level; 2050 if (!local->use_chanctx)
2051 *dbm = local->hw.conf.power_level;
2052 else
2053 *dbm = sdata->vif.bss_conf.txpower;
2037 2054
2038 return 0; 2055 return 0;
2039} 2056}
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index f84b86028a9c..a2b06d40aebf 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -173,6 +173,8 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
173 rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); 173 rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
174 ctx->refcount++; 174 ctx->refcount++;
175 175
176 ieee80211_recalc_txpower(sdata);
177
176 return 0; 178 return 0;
177} 179}
178 180
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 3393ad5b8ab1..07c5721323ca 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -168,6 +168,9 @@ IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz,
168IEEE80211_IF_FILE(flags, flags, HEX); 168IEEE80211_IF_FILE(flags, flags, HEX);
169IEEE80211_IF_FILE(state, state, LHEX); 169IEEE80211_IF_FILE(state, state, LHEX);
170IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC); 170IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC);
171IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC);
172IEEE80211_IF_FILE(ap_power_level, ap_power_level, DEC);
173IEEE80211_IF_FILE(user_power_level, user_power_level, DEC);
171 174
172/* STA attributes */ 175/* STA attributes */
173IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); 176IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
@@ -632,6 +635,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
632 DEBUGFS_ADD(flags); 635 DEBUGFS_ADD(flags);
633 DEBUGFS_ADD(state); 636 DEBUGFS_ADD(state);
634 DEBUGFS_ADD(channel_type); 637 DEBUGFS_ADD(channel_type);
638 DEBUGFS_ADD(txpower);
639 DEBUGFS_ADD(user_power_level);
640 DEBUGFS_ADD(ap_power_level);
635 641
636 if (sdata->vif.type != NL80211_IFTYPE_MONITOR) 642 if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
637 add_common_files(sdata); 643 add_common_files(sdata);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3026519b236a..a1f7c139308e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -56,6 +56,9 @@ struct ieee80211_local;
56#define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) 56#define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024))
57#define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) 57#define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x))
58 58
59/* power level hasn't been configured (or set to automatic) */
60#define IEEE80211_UNSET_POWER_LEVEL INT_MIN
61
59/* 62/*
60 * Some APs experience problems when working with U-APSD. Decrease the 63 * Some APs experience problems when working with U-APSD. Decrease the
61 * probability of that happening by using legacy mode for all ACs but VO. 64 * probability of that happening by using legacy mode for all ACs but VO.
@@ -743,6 +746,9 @@ struct ieee80211_sub_if_data {
743 u8 needed_rx_chains; 746 u8 needed_rx_chains;
744 enum ieee80211_smps_mode smps_mode; 747 enum ieee80211_smps_mode smps_mode;
745 748
749 int user_power_level; /* in dBm */
750 int ap_power_level; /* in dBm */
751
746 /* 752 /*
747 * AP this belongs to: self in AP mode and 753 * AP this belongs to: self in AP mode and
748 * corresponding AP in VLAN mode, NULL for 754 * corresponding AP in VLAN mode, NULL for
@@ -1117,8 +1123,7 @@ struct ieee80211_local {
1117 int dynamic_ps_user_timeout; 1123 int dynamic_ps_user_timeout;
1118 bool disable_dynamic_ps; 1124 bool disable_dynamic_ps;
1119 1125
1120 int user_power_level; /* in dBm */ 1126 int user_power_level; /* in dBm, for all interfaces */
1121 int ap_power_level; /* in dBm */
1122 1127
1123 enum ieee80211_smps_mode smps_mode; 1128 enum ieee80211_smps_mode smps_mode;
1124 1129
@@ -1365,6 +1370,9 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
1365int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up); 1370int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up);
1366void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); 1371void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata);
1367 1372
1373bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
1374void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
1375
1368static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) 1376static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
1369{ 1377{
1370 return test_bit(SDATA_STATE_RUNNING, &sdata->state); 1378 return test_bit(SDATA_STATE_RUNNING, &sdata->state);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 1a6fe135f201..80ce90b29d9d 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -42,6 +42,41 @@
42 * by either the RTNL, the iflist_mtx or RCU. 42 * by either the RTNL, the iflist_mtx or RCU.
43 */ 43 */
44 44
45bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
46{
47 struct ieee80211_chanctx_conf *chanctx_conf;
48 int power;
49
50 rcu_read_lock();
51 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
52 if (!chanctx_conf) {
53 rcu_read_unlock();
54 return false;
55 }
56
57 power = chanctx_conf->channel->max_power;
58 rcu_read_unlock();
59
60 if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL)
61 power = min(power, sdata->user_power_level);
62
63 if (sdata->ap_power_level != IEEE80211_UNSET_POWER_LEVEL)
64 power = min(power, sdata->ap_power_level);
65
66 if (power != sdata->vif.bss_conf.txpower) {
67 sdata->vif.bss_conf.txpower = power;
68 ieee80211_hw_config(sdata->local, 0);
69 return true;
70 }
71
72 return false;
73}
74
75void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
76{
77 if (__ieee80211_recalc_txpower(sdata))
78 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER);
79}
45 80
46static u32 ieee80211_idle_off(struct ieee80211_local *local, 81static u32 ieee80211_idle_off(struct ieee80211_local *local,
47 const char *reason) 82 const char *reason)
@@ -1510,6 +1545,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
1510 1545
1511 ieee80211_set_default_queues(sdata); 1546 ieee80211_set_default_queues(sdata);
1512 1547
1548 sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
1549 sdata->user_power_level = local->user_power_level;
1550
1513 /* setup type-dependent data */ 1551 /* setup type-dependent data */
1514 ieee80211_setup_sdata(sdata, type); 1552 ieee80211_setup_sdata(sdata, type);
1515 1553
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index fd8345c20051..70e87600cacc 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -95,11 +95,13 @@ static void ieee80211_reconfig_filter(struct work_struct *work)
95 95
96static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) 96static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
97{ 97{
98 struct ieee80211_sub_if_data *sdata;
98 struct ieee80211_channel *chan; 99 struct ieee80211_channel *chan;
99 u32 changed = 0; 100 u32 changed = 0;
100 int power; 101 int power;
101 enum nl80211_channel_type channel_type; 102 enum nl80211_channel_type channel_type;
102 u32 offchannel_flag; 103 u32 offchannel_flag;
104 bool scanning = false;
103 105
104 offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; 106 offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
105 if (local->scan_channel) { 107 if (local->scan_channel) {
@@ -146,16 +148,18 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
146 changed |= IEEE80211_CONF_CHANGE_SMPS; 148 changed |= IEEE80211_CONF_CHANGE_SMPS;
147 } 149 }
148 150
149 if (test_bit(SCAN_SW_SCANNING, &local->scanning) || 151 scanning = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
150 test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || 152 test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
151 test_bit(SCAN_HW_SCANNING, &local->scanning) || 153 test_bit(SCAN_HW_SCANNING, &local->scanning);
152 !local->ap_power_level) 154 power = chan->max_power;
153 power = chan->max_power;
154 else
155 power = min(chan->max_power, local->ap_power_level);
156 155
157 if (local->user_power_level >= 0) 156 rcu_read_lock();
158 power = min(power, local->user_power_level); 157 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
158 if (!rcu_access_pointer(sdata->vif.chanctx_conf))
159 continue;
160 power = min(power, sdata->vif.bss_conf.txpower);
161 }
162 rcu_read_unlock();
159 163
160 if (local->hw.conf.power_level != power) { 164 if (local->hw.conf.power_level != power) {
161 changed |= IEEE80211_CONF_CHANGE_POWER; 165 changed |= IEEE80211_CONF_CHANGE_POWER;
@@ -600,7 +604,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
600 604
601 wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | 605 wiphy->features |= NL80211_FEATURE_SK_TX_STATUS |
602 NL80211_FEATURE_SAE | 606 NL80211_FEATURE_SAE |
603 NL80211_FEATURE_HT_IBSS; 607 NL80211_FEATURE_HT_IBSS |
608 NL80211_FEATURE_VIF_TXPOWER;
604 609
605 if (!ops->hw_scan) 610 if (!ops->hw_scan)
606 wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | 611 wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
@@ -633,7 +638,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
633 local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS | 638 local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS |
634 IEEE80211_RADIOTAP_MCS_HAVE_GI | 639 IEEE80211_RADIOTAP_MCS_HAVE_GI |
635 IEEE80211_RADIOTAP_MCS_HAVE_BW; 640 IEEE80211_RADIOTAP_MCS_HAVE_BW;
636 local->user_power_level = -1; 641 local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
637 wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; 642 wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
638 643
639 INIT_LIST_HEAD(&local->interfaces); 644 INIT_LIST_HEAD(&local->interfaces);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 1d1fdf0791f0..d29762fdd887 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -820,10 +820,10 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
820 cbss->beacon_interval)); 820 cbss->beacon_interval));
821} 821}
822 822
823static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, 823static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
824 struct ieee80211_channel *channel, 824 struct ieee80211_channel *channel,
825 const u8 *country_ie, u8 country_ie_len, 825 const u8 *country_ie, u8 country_ie_len,
826 const u8 *pwr_constr_elem) 826 const u8 *pwr_constr_elem)
827{ 827{
828 struct ieee80211_country_ie_triplet *triplet; 828 struct ieee80211_country_ie_triplet *triplet;
829 int chan = ieee80211_frequency_to_channel(channel->center_freq); 829 int chan = ieee80211_frequency_to_channel(channel->center_freq);
@@ -832,7 +832,7 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
832 832
833 /* Invalid IE */ 833 /* Invalid IE */
834 if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) 834 if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
835 return; 835 return 0;
836 836
837 triplet = (void *)(country_ie + 3); 837 triplet = (void *)(country_ie + 3);
838 country_ie_len -= 3; 838 country_ie_len -= 3;
@@ -873,19 +873,21 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
873 } 873 }
874 874
875 if (!have_chan_pwr) 875 if (!have_chan_pwr)
876 return; 876 return 0;
877 877
878 new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem); 878 new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem);
879 879
880 if (sdata->local->ap_power_level == new_ap_level) 880 if (sdata->ap_power_level == new_ap_level)
881 return; 881 return 0;
882 882
883 sdata_info(sdata, 883 sdata_info(sdata,
884 "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", 884 "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
885 new_ap_level, chan_pwr, *pwr_constr_elem, 885 new_ap_level, chan_pwr, *pwr_constr_elem,
886 sdata->u.mgd.bssid); 886 sdata->u.mgd.bssid);
887 sdata->local->ap_power_level = new_ap_level; 887 sdata->ap_power_level = new_ap_level;
888 ieee80211_hw_config(sdata->local, 0); 888 if (__ieee80211_recalc_txpower(sdata))
889 return BSS_CHANGED_TXPOWER;
890 return 0;
889} 891}
890 892
891void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) 893void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif)
@@ -1489,7 +1491,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
1489 memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); 1491 memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
1490 memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); 1492 memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
1491 1493
1492 local->ap_power_level = 0; 1494 sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
1493 1495
1494 del_timer_sync(&local->dynamic_ps_timer); 1496 del_timer_sync(&local->dynamic_ps_timer);
1495 cancel_work_sync(&local->dynamic_ps_enable_work); 1497 cancel_work_sync(&local->dynamic_ps_enable_work);
@@ -2623,10 +2625,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2623 if (elems.country_elem && elems.pwr_constr_elem && 2625 if (elems.country_elem && elems.pwr_constr_elem &&
2624 mgmt->u.probe_resp.capab_info & 2626 mgmt->u.probe_resp.capab_info &
2625 cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) 2627 cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
2626 ieee80211_handle_pwr_constr(sdata, chan, 2628 changed |= ieee80211_handle_pwr_constr(sdata, chan,
2627 elems.country_elem, 2629 elems.country_elem,
2628 elems.country_elem_len, 2630 elems.country_elem_len,
2629 elems.pwr_constr_elem); 2631 elems.pwr_constr_elem);
2630 2632
2631 ieee80211_bss_info_change_notify(sdata, changed); 2633 ieee80211_bss_info_change_notify(sdata, changed);
2632} 2634}
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 5e74e77cba9a..eeebbd9cb888 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -342,6 +342,7 @@ TRACE_EVENT(drv_bss_info_changed,
342 __field(bool, ps); 342 __field(bool, ps);
343 __dynamic_array(u8, ssid, info->ssid_len); 343 __dynamic_array(u8, ssid, info->ssid_len);
344 __field(bool, hidden_ssid); 344 __field(bool, hidden_ssid);
345 __field(int, txpower)
345 ), 346 ),
346 347
347 TP_fast_assign( 348 TP_fast_assign(
@@ -376,6 +377,7 @@ TRACE_EVENT(drv_bss_info_changed,
376 __entry->ps = info->ps; 377 __entry->ps = info->ps;
377 memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); 378 memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len);
378 __entry->hidden_ssid = info->hidden_ssid; 379 __entry->hidden_ssid = info->hidden_ssid;
380 __entry->txpower = info->txpower;
379 ), 381 ),
380 382
381 TP_printk( 383 TP_printk(
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 6636d3962317..1a511afbdf07 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1478,7 +1478,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1478 BSS_CHANGED_BSSID | 1478 BSS_CHANGED_BSSID |
1479 BSS_CHANGED_CQM | 1479 BSS_CHANGED_CQM |
1480 BSS_CHANGED_QOS | 1480 BSS_CHANGED_QOS |
1481 BSS_CHANGED_IDLE; 1481 BSS_CHANGED_IDLE |
1482 BSS_CHANGED_TXPOWER;
1482 1483
1483 switch (sdata->vif.type) { 1484 switch (sdata->vif.type) {
1484 case NL80211_IFTYPE_STATION: 1485 case NL80211_IFTYPE_STATION: