diff options
-rw-r--r-- | include/net/mac80211.h | 7 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 47 | ||||
-rw-r--r-- | net/mac80211/chan.c | 2 | ||||
-rw-r--r-- | net/mac80211/debugfs_netdev.c | 6 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 12 | ||||
-rw-r--r-- | net/mac80211/iface.c | 38 | ||||
-rw-r--r-- | net/mac80211/main.c | 27 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 32 | ||||
-rw-r--r-- | net/mac80211/trace.h | 2 | ||||
-rw-r--r-- | net/mac80211/util.c | 3 |
10 files changed, 131 insertions, 45 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5f5327452c9a..dfa589b721b6 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -207,6 +207,7 @@ struct ieee80211_chanctx_conf { | |||
207 | * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode) | 207 | * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode) |
208 | * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode) | 208 | * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode) |
209 | * @BSS_CHANGED_PS: PS changed for this BSS (STA mode) | 209 | * @BSS_CHANGED_PS: PS changed for this BSS (STA mode) |
210 | * @BSS_CHANGED_TXPOWER: TX power setting changed for this interface | ||
210 | */ | 211 | */ |
211 | enum ieee80211_bss_change { | 212 | enum ieee80211_bss_change { |
212 | BSS_CHANGED_ASSOC = 1<<0, | 213 | BSS_CHANGED_ASSOC = 1<<0, |
@@ -227,6 +228,7 @@ enum ieee80211_bss_change { | |||
227 | BSS_CHANGED_SSID = 1<<15, | 228 | BSS_CHANGED_SSID = 1<<15, |
228 | BSS_CHANGED_AP_PROBE_RESP = 1<<16, | 229 | BSS_CHANGED_AP_PROBE_RESP = 1<<16, |
229 | BSS_CHANGED_PS = 1<<17, | 230 | BSS_CHANGED_PS = 1<<17, |
231 | BSS_CHANGED_TXPOWER = 1<<18, | ||
230 | 232 | ||
231 | /* when adding here, make sure to change ieee80211_reconfig */ | 233 | /* when adding here, make sure to change ieee80211_reconfig */ |
232 | }; | 234 | }; |
@@ -309,6 +311,7 @@ enum ieee80211_rssi_event { | |||
309 | * @ssid: The SSID of the current vif. Only valid in AP-mode. | 311 | * @ssid: The SSID of the current vif. Only valid in AP-mode. |
310 | * @ssid_len: Length of SSID given in @ssid. | 312 | * @ssid_len: Length of SSID given in @ssid. |
311 | * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode. | 313 | * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode. |
314 | * @txpower: TX power in dBm | ||
312 | */ | 315 | */ |
313 | struct ieee80211_bss_conf { | 316 | struct ieee80211_bss_conf { |
314 | const u8 *bssid; | 317 | const u8 *bssid; |
@@ -341,6 +344,7 @@ struct ieee80211_bss_conf { | |||
341 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 344 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
342 | size_t ssid_len; | 345 | size_t ssid_len; |
343 | bool hidden_ssid; | 346 | bool hidden_ssid; |
347 | int txpower; | ||
344 | }; | 348 | }; |
345 | 349 | ||
346 | /** | 350 | /** |
@@ -884,7 +888,8 @@ enum ieee80211_smps_mode { | |||
884 | * powersave documentation below. This variable is valid only when | 888 | * powersave documentation below. This variable is valid only when |
885 | * the CONF_PS flag is set. | 889 | * the CONF_PS flag is set. |
886 | * | 890 | * |
887 | * @power_level: requested transmit power (in dBm) | 891 | * @power_level: requested transmit power (in dBm), backward compatibility |
892 | * value only that is set to the minimum of all interfaces | ||
888 | * | 893 | * |
889 | * @channel: the channel to tune to | 894 | * @channel: the channel to tune to |
890 | * @channel_type: the channel (HT) type | 895 | * @channel_type: the channel (HT) type |
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, | |||
168 | IEEE80211_IF_FILE(flags, flags, HEX); | 168 | IEEE80211_IF_FILE(flags, flags, HEX); |
169 | IEEE80211_IF_FILE(state, state, LHEX); | 169 | IEEE80211_IF_FILE(state, state, LHEX); |
170 | IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC); | 170 | IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC); |
171 | IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC); | ||
172 | IEEE80211_IF_FILE(ap_power_level, ap_power_level, DEC); | ||
173 | IEEE80211_IF_FILE(user_power_level, user_power_level, DEC); | ||
171 | 174 | ||
172 | /* STA attributes */ | 175 | /* STA attributes */ |
173 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); | 176 | IEEE80211_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, | |||
1365 | int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up); | 1370 | int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up); |
1366 | void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); | 1371 | void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); |
1367 | 1372 | ||
1373 | bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); | ||
1374 | void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); | ||
1375 | |||
1368 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) | 1376 | static 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 | ||
45 | bool __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 | |||
75 | void 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 | ||
46 | static u32 ieee80211_idle_off(struct ieee80211_local *local, | 81 | static 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 | ||
96 | static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) | 96 | static 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 | ||
823 | static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | 823 | static 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 | ||
891 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) | 893 | void 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: |