aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/main.c
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/main.c
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/main.c')
-rw-r--r--net/mac80211/main.c27
1 files changed, 16 insertions, 11 deletions
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);