Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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=1942



Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 853da11b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -258,7 +258,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
			(chan->max_power - local->power_constr_level) :
			chan->max_power;

	if (local->user_power_level)
	if (local->user_power_level >= 0)
		power = min(power, local->user_power_level);

	if (local->hw.conf.power_level != power) {
+33 −8
Original line number Diff line number Diff line
@@ -417,6 +417,7 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
{
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
	struct ieee80211_channel* chan = local->hw.conf.channel;
	bool reconf = false;
	u32 reconf_flags = 0;
	int new_power_level;

@@ -427,14 +428,38 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
	if (!chan)
		return -EINVAL;

	if (data->txpower.fixed)
		new_power_level = min(data->txpower.value, chan->max_power);
	else /* Automatic power level setting */
		new_power_level = chan->max_power;
	/* only change when not disabling */
	if (!data->txpower.disabled) {
		if (data->txpower.fixed) {
			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;

		/*
		 * ieee80211_hw_config() will limit to the channel's
		 * max power and possibly power constraint from AP.
		 */
		local->user_power_level = new_power_level;
	if (local->hw.conf.power_level != new_power_level)
		reconf_flags |= IEEE80211_CONF_CHANGE_POWER;
	}

	if (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,
		ieee80211_led_radio(local, local->hw.conf.radio_enabled);
	}

	if (reconf_flags)
	if (reconf || reconf_flags)
		ieee80211_hw_config(local, reconf_flags);

	return 0;