Commit 47afbaf5 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: correct wext transmit power handler

Wext makes no assumptions about the contents of
data->txpower.fixed and data->txpower.value when
data->txpower.disabled is set, so do not update
the user-requested power level while disabling.

Also, when wext configures a really _fixed_ power
output [1], we should reject it instead of limiting it
to the regulatory constraint. If the user wants to set
a _limit_ [2] then we should honour that.

[1] iwconfig wlan0 txpower 20dBm fixed
[2] iwconfig wlan0 txpower 10dBm

This fixes
http://www.intellinuxwireless.org/bugzilla/show_bug.cgi?id=1942Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 853da11b
...@@ -258,7 +258,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) ...@@ -258,7 +258,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
(chan->max_power - local->power_constr_level) : (chan->max_power - local->power_constr_level) :
chan->max_power; chan->max_power;
if (local->user_power_level) if (local->user_power_level >= 0)
power = min(power, local->user_power_level); power = min(power, local->user_power_level);
if (local->hw.conf.power_level != power) { if (local->hw.conf.power_level != power) {
......
...@@ -417,6 +417,7 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, ...@@ -417,6 +417,7 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_channel* chan = local->hw.conf.channel; struct ieee80211_channel* chan = local->hw.conf.channel;
bool reconf = false;
u32 reconf_flags = 0; u32 reconf_flags = 0;
int new_power_level; int new_power_level;
...@@ -427,14 +428,38 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, ...@@ -427,14 +428,38 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
if (!chan) if (!chan)
return -EINVAL; return -EINVAL;
if (data->txpower.fixed) /* only change when not disabling */
new_power_level = min(data->txpower.value, chan->max_power); if (!data->txpower.disabled) {
else /* Automatic power level setting */ if (data->txpower.fixed) {
new_power_level = chan->max_power; if (data->txpower.value < 0)
return -EINVAL;
new_power_level = data->txpower.value;
/*
* Debatable, but we cannot do a fixed power
* level above the regulatory constraint.
* Use "iwconfig wlan0 txpower 15dBm" instead.
*/
if (new_power_level > chan->max_power)
return -EINVAL;
} else {
/*
* Automatic power level setting, max being the value
* passed in from userland.
*/
if (data->txpower.value < 0)
new_power_level = -1;
else
new_power_level = data->txpower.value;
}
reconf = true;
local->user_power_level = new_power_level; /*
if (local->hw.conf.power_level != new_power_level) * ieee80211_hw_config() will limit to the channel's
reconf_flags |= IEEE80211_CONF_CHANGE_POWER; * max power and possibly power constraint from AP.
*/
local->user_power_level = new_power_level;
}
if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
local->hw.conf.radio_enabled = !(data->txpower.disabled); local->hw.conf.radio_enabled = !(data->txpower.disabled);
...@@ -442,7 +467,7 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, ...@@ -442,7 +467,7 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
ieee80211_led_radio(local, local->hw.conf.radio_enabled); ieee80211_led_radio(local, local->hw.conf.radio_enabled);
} }
if (reconf_flags) if (reconf || reconf_flags)
ieee80211_hw_config(local, reconf_flags); ieee80211_hw_config(local, reconf_flags);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment