summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/ieee80211_i.h4
-rw-r--r--net/mac80211/main.c10
-rw-r--r--net/mac80211/mlme.c9
-rw-r--r--net/mac80211/spectmgmt.c21
4 files changed, 42 insertions, 2 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9112c5247c3..c9ffadb55d3 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -715,6 +715,7 @@ struct ieee80211_local {
struct timer_list dynamic_ps_timer;
int user_power_level; /* in dBm */
+ int power_constr_level; /* in dBm */
#ifdef CONFIG_MAC80211_DEBUGFS
struct local_debugfsdentries {
@@ -985,6 +986,9 @@ void ieee80211_chswitch_work(struct work_struct *work);
void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel_sw_ie *sw_elem,
struct ieee80211_bss *bss);
+void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
+ u16 capab_info, u8 *pwr_constr_elem,
+ u8 pwr_constr_elem_len);
/* utility functions/constants */
extern void *mac80211_wiphy_privid; /* for wiphy privid */
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index e9f3e85d1a9..c78304db475 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -214,10 +214,16 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
changed |= IEEE80211_CONF_CHANGE_CHANNEL;
}
- if (!local->user_power_level)
+ if (local->sw_scanning)
power = chan->max_power;
else
- power = min(chan->max_power, local->user_power_level);
+ power = local->power_constr_level ?
+ (chan->max_power - local->power_constr_level) :
+ chan->max_power;
+
+ if (local->user_power_level)
+ power = min(power, local->user_power_level);
+
if (local->hw.conf.power_level != power) {
changed |= IEEE80211_CONF_CHANGE_POWER;
local->hw.conf.power_level = power;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 82c598a8368..f0d42498c25 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -905,6 +905,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
/* channel(_type) changes are handled by ieee80211_hw_config */
local->oper_channel_type = NL80211_CHAN_NO_HT;
+ local->power_constr_level = 0;
+
del_timer_sync(&local->dynamic_ps_timer);
cancel_work_sync(&local->dynamic_ps_enable_work);
@@ -1849,6 +1851,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
* for the BSSID we are associated to */
regulatory_hint_11d(local->hw.wiphy,
elems.country_elem, elems.country_elem_len);
+
+ /* TODO: IBSS also needs this */
+ if (elems.pwr_constr_elem)
+ ieee80211_handle_pwr_constr(sdata,
+ le16_to_cpu(mgmt->u.probe_resp.capab_info),
+ elems.pwr_constr_elem,
+ elems.pwr_constr_elem_len);
}
ieee80211_bss_info_change_notify(sdata, changed);
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 8396b5a77e8..8d4ec2968f8 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -161,3 +161,24 @@ void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata,
jiffies + msecs_to_jiffies(sw_elem->count * bss->beacon_int));
}
}
+
+void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
+ u16 capab_info, u8 *pwr_constr_elem,
+ u8 pwr_constr_elem_len)
+{
+ struct ieee80211_conf *conf = &sdata->local->hw.conf;
+
+ if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT))
+ return;
+
+ /* Power constraint IE length should be 1 octet */
+ if (pwr_constr_elem_len != 1)
+ return;
+
+ if ((*pwr_constr_elem <= conf->channel->max_power) &&
+ (*pwr_constr_elem != sdata->local->power_constr_level)) {
+ sdata->local->power_constr_level = *pwr_constr_elem;
+ ieee80211_hw_config(sdata->local, 0);
+ }
+}
+