summaryrefslogtreecommitdiff
path: root/net/mac80211/cfg.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-10-24 10:59:25 +0200
committerJohannes Berg <johannes.berg@intel.com>2012-10-30 09:11:34 +0100
commit1ea6f9c0d48b11b6ec3ec4b5579ec74fc3951cf8 (patch)
tree5a589d0bccfcac6ba0952942a04482b99752ddcc /net/mac80211/cfg.c
parentc8442118ad9cd05cfe3b993f058e70ab25b1009a (diff)
downloadlwn-1ea6f9c0d48b11b6ec3ec4b5579ec74fc3951cf8.tar.gz
lwn-1ea6f9c0d48b11b6ec3ec4b5579ec74fc3951cf8.zip
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/cfg.c')
-rw-r--r--net/mac80211/cfg.c47
1 files changed, 32 insertions, 15 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,
enum nl80211_tx_power_setting type, int mbm)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
- struct ieee80211_channel *chan = local->_oper_channel;
- u32 changes = 0;
+ struct ieee80211_sub_if_data *sdata;
- /* FIXME */
- if (local->use_chanctx)
- return -EOPNOTSUPP;
+ if (wdev) {
+ sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+
+ switch (type) {
+ case NL80211_TX_POWER_AUTOMATIC:
+ sdata->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
+ break;
+ case NL80211_TX_POWER_LIMITED:
+ case NL80211_TX_POWER_FIXED:
+ if (mbm < 0 || (mbm % 100))
+ return -EOPNOTSUPP;
+ sdata->user_power_level = MBM_TO_DBM(mbm);
+ break;
+ }
+
+ ieee80211_recalc_txpower(sdata);
+
+ return 0;
+ }
switch (type) {
case NL80211_TX_POWER_AUTOMATIC:
- local->user_power_level = -1;
+ local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
break;
case NL80211_TX_POWER_LIMITED:
- if (mbm < 0 || (mbm % 100))
- return -EOPNOTSUPP;
- local->user_power_level = MBM_TO_DBM(mbm);
- break;
case NL80211_TX_POWER_FIXED:
if (mbm < 0 || (mbm % 100))
return -EOPNOTSUPP;
- /* TODO: move to cfg80211 when it knows the channel */
- if (MBM_TO_DBM(mbm) > chan->max_power)
- return -EINVAL;
local->user_power_level = MBM_TO_DBM(mbm);
break;
}
- ieee80211_hw_config(local, changes);
+ mutex_lock(&local->iflist_mtx);
+ list_for_each_entry(sdata, &local->interfaces, list)
+ sdata->user_power_level = local->user_power_level;
+ list_for_each_entry(sdata, &local->interfaces, list)
+ ieee80211_recalc_txpower(sdata);
+ mutex_unlock(&local->iflist_mtx);
return 0;
}
@@ -2032,8 +2045,12 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy,
int *dbm)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
- *dbm = local->hw.conf.power_level;
+ if (!local->use_chanctx)
+ *dbm = local->hw.conf.power_level;
+ else
+ *dbm = sdata->vif.bss_conf.txpower;
return 0;
}