* [PATCH v5 1/2] mac80211: split 802.11h parsing from transmit power policy
2014-08-30 18:45 ` Steinar H. Gunderson
@ 2014-08-29 17:27 ` Steinar H. Gunderson
2014-09-03 11:56 ` Johannes Berg
2014-08-29 17:27 ` [PATCH " Steinar H. Gunderson
` (2 subsequent siblings)
3 siblings, 1 reply; 26+ messages in thread
From: Steinar H. Gunderson @ 2014-08-29 17:27 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless
Decouple the logic of parsing the 802.11d and 802.11h IEs from the
part of deciding what to do about the data (messaging, clamping to
0 dBm, doing the actual setting). This paves the way for the next
patch, which introduces more data sources for transmit power limitation.
Signed-off-by: Steinar H. Gunderson <sgunderson@bigfoot.com>
---
net/mac80211/mlme.c | 61 +++++++++++++++++++++++++++++++++++----------------
1 file changed, 42 insertions(+), 19 deletions(-)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index b82a12a..524c7cc 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1157,19 +1157,22 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
TU_TO_EXP_TIME(csa_ie.count * cbss->beacon_interval));
}
-static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_channel *channel,
- const u8 *country_ie, u8 country_ie_len,
- const u8 *pwr_constr_elem)
+static bool ieee80211_find_80211h_pwr_constr(
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel *channel,
+ const u8 *country_ie, u8 country_ie_len,
+ const u8 *pwr_constr_elem,
+ int *chan_pwr,
+ int *pwr_reduction)
{
struct ieee80211_country_ie_triplet *triplet;
int chan = ieee80211_frequency_to_channel(channel->center_freq);
- int i, chan_pwr, chan_increment, new_ap_level;
+ int i, chan_increment;
bool have_chan_pwr = false;
/* Invalid IE */
if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
- return 0;
+ return false;
triplet = (void *)(country_ie + 3);
country_ie_len -= 3;
@@ -1197,7 +1200,7 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
for (i = 0; i < triplet->chans.num_channels; i++) {
if (first_channel + i * chan_increment == chan) {
have_chan_pwr = true;
- chan_pwr = triplet->chans.max_power;
+ *chan_pwr = triplet->chans.max_power;
break;
}
}
@@ -1209,18 +1212,41 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
country_ie_len -= 3;
}
- if (!have_chan_pwr)
- return 0;
+ if (have_chan_pwr)
+ *pwr_reduction = *pwr_constr_elem;
+ return have_chan_pwr;
+}
- new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem);
+static bool ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel *channel,
+ struct ieee80211_mgmt *mgmt,
+ const u8 *country_ie, u8 country_ie_len,
+ const u8 *pwr_constr_ie)
+{
+ bool has_80211h_pwr = false;
+ int chan_pwr, pwr_reduction_80211h;
+ int new_ap_level;
- if (sdata->ap_power_level == new_ap_level)
+ if (country_ie && pwr_constr_ie &&
+ mgmt->u.probe_resp.capab_info &
+ cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) {
+ has_80211h_pwr = ieee80211_find_80211h_pwr_constr(
+ sdata, channel, country_ie, country_ie_len,
+ pwr_constr_ie, &chan_pwr, &pwr_reduction_80211h);
+ new_ap_level = max_t(int, 0, chan_pwr - pwr_reduction_80211h);
+ }
+
+ if (!has_80211h_pwr)
return 0;
sdata_info(sdata,
"Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
- new_ap_level, chan_pwr, *pwr_constr_elem,
+ new_ap_level, chan_pwr, pwr_reduction_80211h,
sdata->u.mgd.bssid);
+
+ if (sdata->ap_power_level == new_ap_level)
+ return 0;
+
sdata->ap_power_level = new_ap_level;
if (__ieee80211_recalc_txpower(sdata))
return BSS_CHANGED_TXPOWER;
@@ -3190,13 +3216,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
rx_status->band, true);
mutex_unlock(&local->sta_mtx);
- if (elems.country_elem && elems.pwr_constr_elem &&
- mgmt->u.probe_resp.capab_info &
- cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
- changed |= ieee80211_handle_pwr_constr(sdata, chan,
- elems.country_elem,
- elems.country_elem_len,
- elems.pwr_constr_elem);
+ changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt,
+ elems.country_elem,
+ elems.country_elem_len,
+ elems.pwr_constr_elem);
ieee80211_bss_info_change_notify(sdata, changed);
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH v5 1/2] mac80211: split 802.11h parsing from transmit power policy
2014-08-29 17:27 ` [PATCH v5 1/2] mac80211: split 802.11h parsing from transmit power policy Steinar H. Gunderson
@ 2014-09-03 11:56 ` Johannes Berg
2014-09-03 13:21 ` Steinar H. Gunderson
0 siblings, 1 reply; 26+ messages in thread
From: Johannes Berg @ 2014-09-03 11:56 UTC (permalink / raw)
To: Steinar H. Gunderson; +Cc: linux-wireless
On Fri, 2014-08-29 at 19:27 +0200, Steinar H. Gunderson wrote:
> ieee80211_find_80211h_pwr_constr
Please format the code like this:
static bool
ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *channel,
const u8 *country_ie, u8
country_ie_len,
const u8 *pwr_constr_elem,
int *chan_pwr, int *pwr_reduction)
Do we need the pwr_reduction? Couldn't we just return it? We don't
handle 0/negative anyway, do we?
> -static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
> +static bool ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
I think you meant to keep u32 here? Otherwise return values from the
function simply get converted to 0/1 which doesn't seem right.
johannes
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v5 1/2] mac80211: split 802.11h parsing from transmit power policy
2014-09-03 11:56 ` Johannes Berg
@ 2014-09-03 13:21 ` Steinar H. Gunderson
0 siblings, 0 replies; 26+ messages in thread
From: Steinar H. Gunderson @ 2014-09-03 13:21 UTC (permalink / raw)
To: linux-wireless
Thanks for reviewing. I'll send out a new patch series as soon as I'm
through all of your comments.
On Wed, Sep 03, 2014 at 01:56:40PM +0200, Johannes Berg wrote:
> Please format the code like this:
>
> static bool
> ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata,
> struct ieee80211_channel *channel,
> const u8 *country_ie, u8
> country_ie_len,
> const u8 *pwr_constr_elem,
> int *chan_pwr, int *pwr_reduction)
Done.
> Do we need the pwr_reduction? Couldn't we just return it? We don't
> handle 0/negative anyway, do we?
We could do the calculation directly in ieee80211_find_80211h_pwr_constr;
however, then we couldn't message the calculation in the printk (it currently
says e.g. 0 (17 - 23) dBm). I don't know if that is important or not, but I
opted to let it stay as-is.
>> -static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
>
>> +static bool ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
>
> I think you meant to keep u32 here? Otherwise return values from the
> function simply get converted to 0/1 which doesn't seem right.
You're right; this function is supposed to return a bitmask. Fixed.
/* Steinar */
--
Homepage: http://www.sesse.net/
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH 1/2] mac80211: split 802.11h parsing from transmit power policy
2014-08-30 18:45 ` Steinar H. Gunderson
2014-08-29 17:27 ` [PATCH v5 1/2] mac80211: split 802.11h parsing from transmit power policy Steinar H. Gunderson
@ 2014-08-29 17:27 ` Steinar H. Gunderson
2014-08-29 17:38 ` [PATCH v5 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions) Steinar H. Gunderson
2014-08-29 17:38 ` [PATCH " Steinar H. Gunderson
3 siblings, 0 replies; 26+ messages in thread
From: Steinar H. Gunderson @ 2014-08-29 17:27 UTC (permalink / raw)
To: linux-wireless
Decouple the logic of parsing the 802.11d and 802.11h IEs from the
part of deciding what to do about the data (messaging, clamping to
0 dBm, doing the actual setting). This paves the way for the next
patch, which introduces more data sources for transmit power limitation.
Signed-off-by: Steinar H. Gunderson <sgunderson@bigfoot.com>
---
net/mac80211/mlme.c | 61 +++++++++++++++++++++++++++++++++++----------------
1 file changed, 42 insertions(+), 19 deletions(-)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index b82a12a..524c7cc 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1157,19 +1157,22 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
TU_TO_EXP_TIME(csa_ie.count * cbss->beacon_interval));
}
-static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_channel *channel,
- const u8 *country_ie, u8 country_ie_len,
- const u8 *pwr_constr_elem)
+static bool ieee80211_find_80211h_pwr_constr(
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel *channel,
+ const u8 *country_ie, u8 country_ie_len,
+ const u8 *pwr_constr_elem,
+ int *chan_pwr,
+ int *pwr_reduction)
{
struct ieee80211_country_ie_triplet *triplet;
int chan = ieee80211_frequency_to_channel(channel->center_freq);
- int i, chan_pwr, chan_increment, new_ap_level;
+ int i, chan_increment;
bool have_chan_pwr = false;
/* Invalid IE */
if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
- return 0;
+ return false;
triplet = (void *)(country_ie + 3);
country_ie_len -= 3;
@@ -1197,7 +1200,7 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
for (i = 0; i < triplet->chans.num_channels; i++) {
if (first_channel + i * chan_increment == chan) {
have_chan_pwr = true;
- chan_pwr = triplet->chans.max_power;
+ *chan_pwr = triplet->chans.max_power;
break;
}
}
@@ -1209,18 +1212,41 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
country_ie_len -= 3;
}
- if (!have_chan_pwr)
- return 0;
+ if (have_chan_pwr)
+ *pwr_reduction = *pwr_constr_elem;
+ return have_chan_pwr;
+}
- new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem);
+static bool ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel *channel,
+ struct ieee80211_mgmt *mgmt,
+ const u8 *country_ie, u8 country_ie_len,
+ const u8 *pwr_constr_ie)
+{
+ bool has_80211h_pwr = false;
+ int chan_pwr, pwr_reduction_80211h;
+ int new_ap_level;
- if (sdata->ap_power_level == new_ap_level)
+ if (country_ie && pwr_constr_ie &&
+ mgmt->u.probe_resp.capab_info &
+ cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) {
+ has_80211h_pwr = ieee80211_find_80211h_pwr_constr(
+ sdata, channel, country_ie, country_ie_len,
+ pwr_constr_ie, &chan_pwr, &pwr_reduction_80211h);
+ new_ap_level = max_t(int, 0, chan_pwr - pwr_reduction_80211h);
+ }
+
+ if (!has_80211h_pwr)
return 0;
sdata_info(sdata,
"Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
- new_ap_level, chan_pwr, *pwr_constr_elem,
+ new_ap_level, chan_pwr, pwr_reduction_80211h,
sdata->u.mgd.bssid);
+
+ if (sdata->ap_power_level == new_ap_level)
+ return 0;
+
sdata->ap_power_level = new_ap_level;
if (__ieee80211_recalc_txpower(sdata))
return BSS_CHANGED_TXPOWER;
@@ -3190,13 +3216,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
rx_status->band, true);
mutex_unlock(&local->sta_mtx);
- if (elems.country_elem && elems.pwr_constr_elem &&
- mgmt->u.probe_resp.capab_info &
- cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
- changed |= ieee80211_handle_pwr_constr(sdata, chan,
- elems.country_elem,
- elems.country_elem_len,
- elems.pwr_constr_elem);
+ changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt,
+ elems.country_elem,
+ elems.country_elem_len,
+ elems.pwr_constr_elem);
ieee80211_bss_info_change_notify(sdata, changed);
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v5 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions)
2014-08-30 18:45 ` Steinar H. Gunderson
2014-08-29 17:27 ` [PATCH v5 1/2] mac80211: split 802.11h parsing from transmit power policy Steinar H. Gunderson
2014-08-29 17:27 ` [PATCH " Steinar H. Gunderson
@ 2014-08-29 17:38 ` Steinar H. Gunderson
2014-09-03 12:00 ` Johannes Berg
2014-08-29 17:38 ` [PATCH " Steinar H. Gunderson
3 siblings, 1 reply; 26+ messages in thread
From: Steinar H. Gunderson @ 2014-08-29 17:38 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless
Linux already supports 802.11h, where the access point can tell the
client to reduce its transmission power. However, 802.11h is only
defined for 5 GHz, where the need for this is much smaller than on
2.4 GHz.
Cisco has their own solution, called DTPC (Dynamic Transmit Power
Control). Cisco APs on a controller sometimes but not always send
802.11h; they always send DTPC, even on 2.4 GHz. This patch adds support
for parsing and honoring the DTPC IE in addition to the 802.11h
element (they do not always contain the same limits, so both must
be honored); the format is not documented, but very simple.
Tested (on top of wireless.git and on 3.16.1) against a Cisco Aironet
1142 joined to a Cisco 2504 WLC, by setting various transmit power
levels for the given access points and observing the results.
The Wireshark 802.11 dissector agrees with the interpretation of the
element, except for negative numbers, which seem to never happen
anyway.
Signed-off-by: Steinar H. Gunderson <sgunderson@bigfoot.com>
---
include/linux/ieee80211.h | 3 ++-
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mlme.c | 59 +++++++++++++++++++++++++++++++++++---------
net/mac80211/util.c | 22 +++++++++++++++++
4 files changed, 73 insertions(+), 12 deletions(-)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 63ab3873..d0ec287 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1806,7 +1806,8 @@ enum ieee80211_eid {
WLAN_EID_DMG_TSPEC = 146,
WLAN_EID_DMG_AT = 147,
WLAN_EID_DMG_CAP = 148,
- /* 149-150 reserved for Cisco */
+ /* 149 reserved for Cisco */
+ WLAN_EID_CISCO_VENDOR_SPECIFIC = 150,
WLAN_EID_DMG_OPERATION = 151,
WLAN_EID_DMG_BSS_PARAM_CHANGE = 152,
WLAN_EID_DMG_BEAM_REFINEMENT = 153,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ef7a089..e995556 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1367,6 +1367,7 @@ struct ieee802_11_elems {
const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
const u8 *country_elem;
const u8 *pwr_constr_elem;
+ const u8 *cisco_dtpc_elem;
const struct ieee80211_timeout_interval_ie *timeout_int;
const u8 *opmode_notif;
const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 524c7cc..49d743b 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1217,14 +1217,31 @@ static bool ieee80211_find_80211h_pwr_constr(
return have_chan_pwr;
}
+static bool ieee80211_find_cisco_dtpc(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel *channel,
+ const u8 *cisco_dtpc_ie,
+ int *pwr_level)
+{
+ /* From practical testing, the first data byte of the DTPC element
+ * seems to contain the requested dBm level, and the CLI on Cisco
+ * APs clearly state the range is -127 to 127 dBm, which indicates
+ * a signed byte, although it seemingly never actually goes negative.
+ * The other byte seems to always be zero.
+ */
+ *pwr_level = (__s8)cisco_dtpc_ie[4];
+ return true;
+}
+
static bool ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *channel,
struct ieee80211_mgmt *mgmt,
const u8 *country_ie, u8 country_ie_len,
- const u8 *pwr_constr_ie)
+ const u8 *pwr_constr_ie,
+ const u8 *cisco_dtpc_ie)
{
- bool has_80211h_pwr = false;
- int chan_pwr, pwr_reduction_80211h;
+ bool has_80211h_pwr = false, has_cisco_pwr = false;
+ int chan_pwr = 0, pwr_reduction_80211h = 0;
+ int pwr_level_cisco, pwr_level_80211h;
int new_ap_level;
if (country_ie && pwr_constr_ie &&
@@ -1233,16 +1250,33 @@ static bool ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
has_80211h_pwr = ieee80211_find_80211h_pwr_constr(
sdata, channel, country_ie, country_ie_len,
pwr_constr_ie, &chan_pwr, &pwr_reduction_80211h);
- new_ap_level = max_t(int, 0, chan_pwr - pwr_reduction_80211h);
+ pwr_level_80211h =
+ max_t(int, 0, chan_pwr - pwr_reduction_80211h);
}
- if (!has_80211h_pwr)
+ if (cisco_dtpc_ie)
+ has_cisco_pwr = ieee80211_find_cisco_dtpc(
+ sdata, channel, cisco_dtpc_ie, &pwr_level_cisco);
+
+ if (!has_80211h_pwr && !has_cisco_pwr)
return 0;
- sdata_info(sdata,
- "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
- new_ap_level, chan_pwr, pwr_reduction_80211h,
- sdata->u.mgd.bssid);
+ /* If we have both 802.11h and Cisco DTPC, apply both limits
+ * by picking the smallest of the two power levels advertised.
+ */
+ if (has_80211h_pwr &&
+ (!has_cisco_pwr || pwr_level_80211h <= pwr_level_cisco)) {
+ sdata_info(sdata,
+ "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
+ pwr_level_80211h, chan_pwr, pwr_reduction_80211h,
+ sdata->u.mgd.bssid);
+ new_ap_level = pwr_level_80211h;
+ } else { /* has_cisco_pwr is always true here. */
+ sdata_info(sdata,
+ "Limiting TX power to %d dBm as advertised by %pM\n",
+ pwr_level_cisco, sdata->u.mgd.bssid);
+ new_ap_level = pwr_level_cisco;
+ }
if (sdata->ap_power_level == new_ap_level)
return 0;
@@ -2911,7 +2945,9 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
/*
* This is the canonical list of information elements we care about,
* the filter code also gives us all changes to the Microsoft OUI
- * (00:50:F2) vendor IE which is used for WMM which we need to track.
+ * (00:50:F2) vendor IE which is used for WMM which we need to track,
+ * as well as the DTPC IE (part of the Cisco OUI) used for signaling
+ * changes to requested client power.
*
* We implement beacon filtering in software since that means we can
* avoid processing the frame here and in cfg80211, and userspace
@@ -3219,7 +3255,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt,
elems.country_elem,
elems.country_elem_len,
- elems.pwr_constr_elem);
+ elems.pwr_constr_elem,
+ elems.cisco_dtpc_elem);
ieee80211_bss_info_change_notify(sdata, changed);
}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 725af7a..e393dfa 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1014,6 +1014,28 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
}
elems->pwr_constr_elem = pos;
break;
+ case WLAN_EID_CISCO_VENDOR_SPECIFIC:
+ /* Lots of different options exist, but we only care
+ * about the Dynamic Transmit Power Control element.
+ * First check for the Cisco OUI, then for the DTPC
+ * tag (0x00).
+ */
+ if (elen < 4) {
+ elem_parse_failed = true;
+ break;
+ }
+ if (pos[0] != 0x00 || pos[1] != 0x40 ||
+ pos[2] != 0x96 || pos[3] != 0x00) {
+ break;
+ }
+ if (elen != 6) {
+ elem_parse_failed = true;
+ break;
+ }
+ if (calc_crc)
+ crc = crc32_be(crc, pos - 2, elen + 2);
+ elems->cisco_dtpc_elem = pos;
+ break;
case WLAN_EID_TIMEOUT_INTERVAL:
if (elen >= sizeof(struct ieee80211_timeout_interval_ie))
elems->timeout_int = (void *)pos;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH v5 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions)
2014-08-29 17:38 ` [PATCH v5 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions) Steinar H. Gunderson
@ 2014-09-03 12:00 ` Johannes Berg
2014-09-03 13:33 ` Steinar H. Gunderson
0 siblings, 1 reply; 26+ messages in thread
From: Johannes Berg @ 2014-09-03 12:00 UTC (permalink / raw)
To: Steinar H. Gunderson; +Cc: linux-wireless
On Fri, 2014-08-29 at 19:38 +0200, Steinar H. Gunderson wrote:
> Linux already supports 802.11h, where the access point can tell the
> client to reduce its transmission power. However, 802.11h is only
> defined for 5 GHz, where the need for this is much smaller than on
> 2.4 GHz.
>
> Cisco has their own solution, called DTPC (Dynamic Transmit Power
> Control). Cisco APs on a controller sometimes but not always send
> 802.11h; they always send DTPC, even on 2.4 GHz. This patch adds support
> for parsing and honoring the DTPC IE in addition to the 802.11h
> element (they do not always contain the same limits, so both must
> be honored); the format is not documented, but very simple.
The format is documented for CCX partners, I suppose, but we don't have
access to that :)
I think for some vendors shipping our stack this might become
problematic. I think it would make sense to have a Kconfig option for
this, probably hidden away under "if EXPERT" and defaulting to yes, to
enable this code, it might be something that interferes with more CCX
implementations maybe?
> +static bool ieee80211_find_cisco_dtpc(struct ieee80211_sub_if_data
> *sdata,
The return value is useless here, so it could be void?
> + if (pos[0] != 0x00 || pos[1] != 0x40 ||
> + pos[2] != 0x96 || pos[3] != 0x00) {
> + break;
> + }
Please remove those useless braces - maybe run ./scripts/checkpatch.pl?
johannes
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v5 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions)
2014-09-03 12:00 ` Johannes Berg
@ 2014-09-03 13:33 ` Steinar H. Gunderson
2014-09-03 13:22 ` [PATCH v6 1/2] mac80211: split 802.11h parsing from transmit power policy Steinar H. Gunderson
` (3 more replies)
0 siblings, 4 replies; 26+ messages in thread
From: Steinar H. Gunderson @ 2014-09-03 13:33 UTC (permalink / raw)
To: linux-wireless
On Wed, Sep 03, 2014 at 02:00:36PM +0200, Johannes Berg wrote:
> I think for some vendors shipping our stack this might become
> problematic. I think it would make sense to have a Kconfig option for
> this, probably hidden away under "if EXPERT" and defaulting to yes, to
> enable this code, it might be something that interferes with more CCX
> implementations maybe?
Are there any CCX implementations for Linux at this time? Could you even do
that from just userspace? (I sort of doubt it, but it's never easy to know
what illustrious userspace programmers can do :-) )
I can make a config option, but it seems a bit odd, maybe. Are you thinking
there would be problems since this is an undocumented protocol, or because of
the possible conflict?
>> +static bool ieee80211_find_cisco_dtpc(struct ieee80211_sub_if_data
>> *sdata,
> The return value is useless here, so it could be void?
It is useless indeed; I kept it this way for symmetry with the other _find_
function and because it makes for slightly easier code around (you can set
has_cisco_pwr = directly without needing an additional statement to make it
true). But I've changed it so it's void.
I could also change it to use a return instead of an output parameter for
pwr_level_cisco if you want, but I think it might become a bit confusing to
have two so similar functions with different calling style.
>> + if (pos[0] != 0x00 || pos[1] != 0x40 ||
>> + pos[2] != 0x96 || pos[3] != 0x00) {
>> + break;
>> + }
> Please remove those useless braces - maybe run ./scripts/checkpatch.pl?
Removed. But I've already run checkpatch and it didn't complain about this
(the patch set is checkpatch-clean).
I'm in a hotel room in Seattle right now whose Wi-Fi is not Cisco-based,
so I can't test the new version as thoroughly as I'd like, but I'll at least
give it a boot test and then send an updated patch series as reply to this
message.
/* Steinar */
--
Homepage: http://www.sesse.net/
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v6 1/2] mac80211: split 802.11h parsing from transmit power policy
2014-09-03 13:33 ` Steinar H. Gunderson
@ 2014-09-03 13:22 ` Steinar H. Gunderson
2014-09-03 13:48 ` [PATCH v6 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions) Steinar H. Gunderson
` (2 subsequent siblings)
3 siblings, 0 replies; 26+ messages in thread
From: Steinar H. Gunderson @ 2014-09-03 13:22 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless
Decouple the logic of parsing the 802.11d and 802.11h IEs from the
part of deciding what to do about the data (messaging, clamping to
0 dBm, doing the actual setting). This paves the way for the next
patch, which introduces more data sources for transmit power limitation.
Signed-off-by: Steinar H. Gunderson <sgunderson@bigfoot.com>
---
net/mac80211/mlme.c | 60 ++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 41 insertions(+), 19 deletions(-)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index b82a12a..918011a 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1157,19 +1157,21 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
TU_TO_EXP_TIME(csa_ie.count * cbss->beacon_interval));
}
-static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_channel *channel,
- const u8 *country_ie, u8 country_ie_len,
- const u8 *pwr_constr_elem)
+static bool
+ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel *channel,
+ const u8 *country_ie, u8 country_ie_len,
+ const u8 *pwr_constr_elem,
+ int *chan_pwr, int *pwr_reduction)
{
struct ieee80211_country_ie_triplet *triplet;
int chan = ieee80211_frequency_to_channel(channel->center_freq);
- int i, chan_pwr, chan_increment, new_ap_level;
+ int i, chan_increment;
bool have_chan_pwr = false;
/* Invalid IE */
if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
- return 0;
+ return false;
triplet = (void *)(country_ie + 3);
country_ie_len -= 3;
@@ -1197,7 +1199,7 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
for (i = 0; i < triplet->chans.num_channels; i++) {
if (first_channel + i * chan_increment == chan) {
have_chan_pwr = true;
- chan_pwr = triplet->chans.max_power;
+ *chan_pwr = triplet->chans.max_power;
break;
}
}
@@ -1209,18 +1211,41 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
country_ie_len -= 3;
}
- if (!have_chan_pwr)
- return 0;
+ if (have_chan_pwr)
+ *pwr_reduction = *pwr_constr_elem;
+ return have_chan_pwr;
+}
+
+static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel *channel,
+ struct ieee80211_mgmt *mgmt,
+ const u8 *country_ie, u8 country_ie_len,
+ const u8 *pwr_constr_ie)
+{
+ bool has_80211h_pwr = false;
+ int chan_pwr, pwr_reduction_80211h;
+ int new_ap_level;
- new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem);
+ if (country_ie && pwr_constr_ie &&
+ mgmt->u.probe_resp.capab_info &
+ cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) {
+ has_80211h_pwr = ieee80211_find_80211h_pwr_constr(
+ sdata, channel, country_ie, country_ie_len,
+ pwr_constr_ie, &chan_pwr, &pwr_reduction_80211h);
+ new_ap_level = max_t(int, 0, chan_pwr - pwr_reduction_80211h);
+ }
- if (sdata->ap_power_level == new_ap_level)
+ if (!has_80211h_pwr)
return 0;
sdata_info(sdata,
"Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
- new_ap_level, chan_pwr, *pwr_constr_elem,
+ new_ap_level, chan_pwr, pwr_reduction_80211h,
sdata->u.mgd.bssid);
+
+ if (sdata->ap_power_level == new_ap_level)
+ return 0;
+
sdata->ap_power_level = new_ap_level;
if (__ieee80211_recalc_txpower(sdata))
return BSS_CHANGED_TXPOWER;
@@ -3190,13 +3215,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
rx_status->band, true);
mutex_unlock(&local->sta_mtx);
- if (elems.country_elem && elems.pwr_constr_elem &&
- mgmt->u.probe_resp.capab_info &
- cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
- changed |= ieee80211_handle_pwr_constr(sdata, chan,
- elems.country_elem,
- elems.country_elem_len,
- elems.pwr_constr_elem);
+ changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt,
+ elems.country_elem,
+ elems.country_elem_len,
+ elems.pwr_constr_elem);
ieee80211_bss_info_change_notify(sdata, changed);
}
--
2.1.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v6 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions)
2014-09-03 13:33 ` Steinar H. Gunderson
2014-09-03 13:22 ` [PATCH v6 1/2] mac80211: split 802.11h parsing from transmit power policy Steinar H. Gunderson
@ 2014-09-03 13:48 ` Steinar H. Gunderson
2014-09-08 8:53 ` Johannes Berg
2014-09-03 19:12 ` [PATCH v5 " Johannes Berg
2014-09-07 17:02 ` Steinar H. Gunderson
3 siblings, 1 reply; 26+ messages in thread
From: Steinar H. Gunderson @ 2014-09-03 13:48 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless
Linux already supports 802.11h, where the access point can tell the
client to reduce its transmission power. However, 802.11h is only
defined for 5 GHz, where the need for this is much smaller than on
2.4 GHz.
Cisco has their own solution, called DTPC (Dynamic Transmit Power
Control). Cisco APs on a controller sometimes but not always send
802.11h; they always send DTPC, even on 2.4 GHz. This patch adds support
for parsing and honoring the DTPC IE in addition to the 802.11h
element (they do not always contain the same limits, so both must
be honored); the format is not documented, but very simple.
Tested (on top of wireless.git and on 3.16.1) against a Cisco Aironet
1142 joined to a Cisco 2504 WLC, by setting various transmit power
levels for the given access points and observing the results.
The Wireshark 802.11 dissector agrees with the interpretation of the
element, except for negative numbers, which seem to never happen
anyway.
Signed-off-by: Steinar H. Gunderson <sgunderson@bigfoot.com>
---
include/linux/ieee80211.h | 3 ++-
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mlme.c | 60 +++++++++++++++++++++++++++++++++++++---------
net/mac80211/util.c | 21 ++++++++++++++++
4 files changed, 73 insertions(+), 12 deletions(-)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 63ab3873..d0ec287 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1806,7 +1806,8 @@ enum ieee80211_eid {
WLAN_EID_DMG_TSPEC = 146,
WLAN_EID_DMG_AT = 147,
WLAN_EID_DMG_CAP = 148,
- /* 149-150 reserved for Cisco */
+ /* 149 reserved for Cisco */
+ WLAN_EID_CISCO_VENDOR_SPECIFIC = 150,
WLAN_EID_DMG_OPERATION = 151,
WLAN_EID_DMG_BSS_PARAM_CHANGE = 152,
WLAN_EID_DMG_BEAM_REFINEMENT = 153,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ef7a089..e995556 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1367,6 +1367,7 @@ struct ieee802_11_elems {
const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
const u8 *country_elem;
const u8 *pwr_constr_elem;
+ const u8 *cisco_dtpc_elem;
const struct ieee80211_timeout_interval_ie *timeout_int;
const u8 *opmode_notif;
const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 918011a..352f50c 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1216,14 +1216,30 @@ ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata,
return have_chan_pwr;
}
+static void ieee80211_find_cisco_dtpc(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel *channel,
+ const u8 *cisco_dtpc_ie,
+ int *pwr_level)
+{
+ /* From practical testing, the first data byte of the DTPC element
+ * seems to contain the requested dBm level, and the CLI on Cisco
+ * APs clearly state the range is -127 to 127 dBm, which indicates
+ * a signed byte, although it seemingly never actually goes negative.
+ * The other byte seems to always be zero.
+ */
+ *pwr_level = (__s8)cisco_dtpc_ie[4];
+}
+
static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *channel,
struct ieee80211_mgmt *mgmt,
const u8 *country_ie, u8 country_ie_len,
- const u8 *pwr_constr_ie)
+ const u8 *pwr_constr_ie,
+ const u8 *cisco_dtpc_ie)
{
- bool has_80211h_pwr = false;
- int chan_pwr, pwr_reduction_80211h;
+ bool has_80211h_pwr = false, has_cisco_pwr = false;
+ int chan_pwr = 0, pwr_reduction_80211h = 0;
+ int pwr_level_cisco, pwr_level_80211h;
int new_ap_level;
if (country_ie && pwr_constr_ie &&
@@ -1232,16 +1248,35 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
has_80211h_pwr = ieee80211_find_80211h_pwr_constr(
sdata, channel, country_ie, country_ie_len,
pwr_constr_ie, &chan_pwr, &pwr_reduction_80211h);
- new_ap_level = max_t(int, 0, chan_pwr - pwr_reduction_80211h);
+ pwr_level_80211h =
+ max_t(int, 0, chan_pwr - pwr_reduction_80211h);
+ }
+
+ if (cisco_dtpc_ie) {
+ ieee80211_find_cisco_dtpc(
+ sdata, channel, cisco_dtpc_ie, &pwr_level_cisco);
+ has_cisco_pwr = true;
}
- if (!has_80211h_pwr)
+ if (!has_80211h_pwr && !has_cisco_pwr)
return 0;
- sdata_info(sdata,
- "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
- new_ap_level, chan_pwr, pwr_reduction_80211h,
- sdata->u.mgd.bssid);
+ /* If we have both 802.11h and Cisco DTPC, apply both limits
+ * by picking the smallest of the two power levels advertised.
+ */
+ if (has_80211h_pwr &&
+ (!has_cisco_pwr || pwr_level_80211h <= pwr_level_cisco)) {
+ sdata_info(sdata,
+ "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
+ pwr_level_80211h, chan_pwr, pwr_reduction_80211h,
+ sdata->u.mgd.bssid);
+ new_ap_level = pwr_level_80211h;
+ } else { /* has_cisco_pwr is always true here. */
+ sdata_info(sdata,
+ "Limiting TX power to %d dBm as advertised by %pM\n",
+ pwr_level_cisco, sdata->u.mgd.bssid);
+ new_ap_level = pwr_level_cisco;
+ }
if (sdata->ap_power_level == new_ap_level)
return 0;
@@ -2910,7 +2945,9 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
/*
* This is the canonical list of information elements we care about,
* the filter code also gives us all changes to the Microsoft OUI
- * (00:50:F2) vendor IE which is used for WMM which we need to track.
+ * (00:50:F2) vendor IE which is used for WMM which we need to track,
+ * as well as the DTPC IE (part of the Cisco OUI) used for signaling
+ * changes to requested client power.
*
* We implement beacon filtering in software since that means we can
* avoid processing the frame here and in cfg80211, and userspace
@@ -3218,7 +3255,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt,
elems.country_elem,
elems.country_elem_len,
- elems.pwr_constr_elem);
+ elems.pwr_constr_elem,
+ elems.cisco_dtpc_elem);
ieee80211_bss_info_change_notify(sdata, changed);
}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 725af7a..95a9159 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1014,6 +1014,27 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
}
elems->pwr_constr_elem = pos;
break;
+ case WLAN_EID_CISCO_VENDOR_SPECIFIC:
+ /* Lots of different options exist, but we only care
+ * about the Dynamic Transmit Power Control element.
+ * First check for the Cisco OUI, then for the DTPC
+ * tag (0x00).
+ */
+ if (elen < 4) {
+ elem_parse_failed = true;
+ break;
+ }
+ if (pos[0] != 0x00 || pos[1] != 0x40 ||
+ pos[2] != 0x96 || pos[3] != 0x00)
+ break;
+ if (elen != 6) {
+ elem_parse_failed = true;
+ break;
+ }
+ if (calc_crc)
+ crc = crc32_be(crc, pos - 2, elen + 2);
+ elems->cisco_dtpc_elem = pos;
+ break;
case WLAN_EID_TIMEOUT_INTERVAL:
if (elen >= sizeof(struct ieee80211_timeout_interval_ie))
elems->timeout_int = (void *)pos;
--
2.1.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH v6 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions)
2014-09-03 13:48 ` [PATCH v6 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions) Steinar H. Gunderson
@ 2014-09-08 8:53 ` Johannes Berg
2014-09-16 23:47 ` Steinar H. Gunderson
0 siblings, 1 reply; 26+ messages in thread
From: Johannes Berg @ 2014-09-08 8:53 UTC (permalink / raw)
To: Steinar H. Gunderson; +Cc: linux-wireless
On Wed, 2014-09-03 at 06:48 -0700, Steinar H. Gunderson wrote:
> Linux already supports 802.11h, where the access point can tell the
> client to reduce its transmission power. However, 802.11h is only
> defined for 5 GHz, where the need for this is much smaller than on
> 2.4 GHz.
>
> Cisco has their own solution, called DTPC (Dynamic Transmit Power
> Control). Cisco APs on a controller sometimes but not always send
> 802.11h; they always send DTPC, even on 2.4 GHz. This patch adds support
> for parsing and honoring the DTPC IE in addition to the 802.11h
> element (they do not always contain the same limits, so both must
> be honored); the format is not documented, but very simple.
>
> Tested (on top of wireless.git and on 3.16.1) against a Cisco Aironet
> 1142 joined to a Cisco 2504 WLC, by setting various transmit power
> levels for the given access points and observing the results.
> The Wireshark 802.11 dissector agrees with the interpretation of the
> element, except for negative numbers, which seem to never happen
> anyway.
Applied both.
johannes
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v6 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions)
2014-09-08 8:53 ` Johannes Berg
@ 2014-09-16 23:47 ` Steinar H. Gunderson
2014-10-06 14:52 ` Johannes Berg
0 siblings, 1 reply; 26+ messages in thread
From: Steinar H. Gunderson @ 2014-09-16 23:47 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
On Mon, Sep 08, 2014 at 10:53:20AM +0200, Johannes Berg wrote:
>> Linux already supports 802.11h, where the access point can tell the
>> client to reduce its transmission power. However, 802.11h is only
>> defined for 5 GHz, where the need for this is much smaller than on
>> 2.4 GHz.
>>
>> Cisco has their own solution, called DTPC (Dynamic Transmit Power
>> Control). Cisco APs on a controller sometimes but not always send
>> 802.11h; they always send DTPC, even on 2.4 GHz. This patch adds support
>> for parsing and honoring the DTPC IE in addition to the 802.11h
>> element (they do not always contain the same limits, so both must
>> be honored); the format is not documented, but very simple.
>>
>> Tested (on top of wireless.git and on 3.16.1) against a Cisco Aironet
>> 1142 joined to a Cisco 2504 WLC, by setting various transmit power
>> levels for the given access points and observing the results.
>> The Wireshark 802.11 dissector agrees with the interpretation of the
>> element, except for negative numbers, which seem to never happen
>> anyway.
> Applied both.
I found what I believe is an edge case: What happens if the element suddenly
goes away from one beacon to another? Shouldn't there be a reset of the power
level and then a new call to __ieee80211_recalc_txpower()?
(If so, I believe this bug was already present in the code before my first
patch, as I understand the existing logic.)
/* Steinar */
--
Homepage: http://www.sesse.net/
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v6 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions)
2014-09-16 23:47 ` Steinar H. Gunderson
@ 2014-10-06 14:52 ` Johannes Berg
2014-10-06 14:54 ` Steinar H. Gunderson
0 siblings, 1 reply; 26+ messages in thread
From: Johannes Berg @ 2014-10-06 14:52 UTC (permalink / raw)
To: Steinar H. Gunderson; +Cc: linux-wireless
On Wed, 2014-09-17 at 01:47 +0200, Steinar H. Gunderson wrote:
> On Mon, Sep 08, 2014 at 10:53:20AM +0200, Johannes Berg wrote:
> >> Linux already supports 802.11h, where the access point can tell the
> >> client to reduce its transmission power. However, 802.11h is only
> >> defined for 5 GHz, where the need for this is much smaller than on
> >> 2.4 GHz.
> >>
> >> Cisco has their own solution, called DTPC (Dynamic Transmit Power
> >> Control). Cisco APs on a controller sometimes but not always send
> >> 802.11h; they always send DTPC, even on 2.4 GHz. This patch adds support
> >> for parsing and honoring the DTPC IE in addition to the 802.11h
> >> element (they do not always contain the same limits, so both must
> >> be honored); the format is not documented, but very simple.
> >>
> >> Tested (on top of wireless.git and on 3.16.1) against a Cisco Aironet
> >> 1142 joined to a Cisco 2504 WLC, by setting various transmit power
> >> levels for the given access points and observing the results.
> >> The Wireshark 802.11 dissector agrees with the interpretation of the
> >> element, except for negative numbers, which seem to never happen
> >> anyway.
> > Applied both.
>
> I found what I believe is an edge case: What happens if the element suddenly
> goes away from one beacon to another? Shouldn't there be a reset of the power
> level and then a new call to __ieee80211_recalc_txpower()?
>
> (If so, I believe this bug was already present in the code before my first
> patch, as I understand the existing logic.)
I'm not sure it's worth worrying about, but if you want to write a patch
I'd take it :)
johannes
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v6 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions)
2014-10-06 14:52 ` Johannes Berg
@ 2014-10-06 14:54 ` Steinar H. Gunderson
0 siblings, 0 replies; 26+ messages in thread
From: Steinar H. Gunderson @ 2014-10-06 14:54 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
On Mon, Oct 06, 2014 at 04:52:14PM +0200, Johannes Berg wrote:
>> I found what I believe is an edge case: What happens if the element suddenly
>> goes away from one beacon to another? Shouldn't there be a reset of the power
>> level and then a new call to __ieee80211_recalc_txpower()?
>>
>> (If so, I believe this bug was already present in the code before my first
>> patch, as I understand the existing logic.)
> I'm not sure it's worth worrying about, but if you want to write a patch
> I'd take it :)
It actually happened to me in a real situation, which is why I noticed.
It seems neither power element is typically sent at all if the value is 0.
(Well, Aruba seems to do. I haven't found anyone else who does.)
/* Steinar */
--
Homepage: http://www.sesse.net/
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v5 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions)
2014-09-03 13:33 ` Steinar H. Gunderson
2014-09-03 13:22 ` [PATCH v6 1/2] mac80211: split 802.11h parsing from transmit power policy Steinar H. Gunderson
2014-09-03 13:48 ` [PATCH v6 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions) Steinar H. Gunderson
@ 2014-09-03 19:12 ` Johannes Berg
2014-09-07 17:02 ` Steinar H. Gunderson
3 siblings, 0 replies; 26+ messages in thread
From: Johannes Berg @ 2014-09-03 19:12 UTC (permalink / raw)
To: Steinar H. Gunderson; +Cc: linux-wireless
On Wed, 2014-09-03 at 15:33 +0200, Steinar H. Gunderson wrote:
> On Wed, Sep 03, 2014 at 02:00:36PM +0200, Johannes Berg wrote:
> > I think for some vendors shipping our stack this might become
> > problematic. I think it would make sense to have a Kconfig option for
> > this, probably hidden away under "if EXPERT" and defaulting to yes, to
> > enable this code, it might be something that interferes with more CCX
> > implementations maybe?
>
> Are there any CCX implementations for Linux at this time? Could you even do
> that from just userspace? (I sort of doubt it, but it's never easy to know
> what illustrious userspace programmers can do :-) )
I have no idea :-)
> I can make a config option, but it seems a bit odd, maybe. Are you thinking
> there would be problems since this is an undocumented protocol, or because of
> the possible conflict?
I'm just thinking it might be a problem for a vendor to ship an
(obviously incomplete) CCX implementation, even without advertising
such. Most vendors have some relationship with Cisco at least for other
drivers, so I'd prefer to avoid any possible conflict. You could argue
that we shouldn't care upstream, and I'm not really sure where I fall on
that question - it seems that vendors might then decide to patch it out
though (which would be easy enough to do as well.)
> >> +static bool ieee80211_find_cisco_dtpc(struct ieee80211_sub_if_data
> >> *sdata,
> > The return value is useless here, so it could be void?
>
> It is useless indeed; I kept it this way for symmetry with the other _find_
> function and because it makes for slightly easier code around (you can set
> has_cisco_pwr = directly without needing an additional statement to make it
> true). But I've changed it so it's void.
>
> I could also change it to use a return instead of an output parameter for
> pwr_level_cisco if you want, but I think it might become a bit confusing to
> have two so similar functions with different calling style.
Right, that makes sense.
> >> + if (pos[0] != 0x00 || pos[1] != 0x40 ||
> >> + pos[2] != 0x96 || pos[3] != 0x00) {
> >> + break;
> >> + }
> > Please remove those useless braces - maybe run ./scripts/checkpatch.pl?
>
> Removed. But I've already run checkpatch and it didn't complain about this
> (the patch set is checkpatch-clean).
Hmmm, interesting. I thought it warned about that, oh well. Thanks :)
> I'm in a hotel room in Seattle right now whose Wi-Fi is not Cisco-based,
> so I can't test the new version as thoroughly as I'd like, but I'll at least
> give it a boot test and then send an updated patch series as reply to this
> message.
Great, thanks. Safe travels then :-)
It's getting late here, but I'll take a look tomorrow. Regarding the
Kconfig question, I'll make up my mind and just do whichever option I
decide for myself, if that's OK with you?
johannes
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v5 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions)
2014-09-03 13:33 ` Steinar H. Gunderson
` (2 preceding siblings ...)
2014-09-03 19:12 ` [PATCH v5 " Johannes Berg
@ 2014-09-07 17:02 ` Steinar H. Gunderson
3 siblings, 0 replies; 26+ messages in thread
From: Steinar H. Gunderson @ 2014-09-07 17:02 UTC (permalink / raw)
To: linux-wireless
On Wed, Sep 03, 2014 at 03:33:28PM +0200, Steinar H. Gunderson wrote:
> I'm in a hotel room in Seattle right now whose Wi-Fi is not Cisco-based,
> so I can't test the new version as thoroughly as I'd like, but I'll at least
> give it a boot test and then send an updated patch series as reply to this
> message.
It seems the airport in Seattle has Cisco-based Wi-Fi, so while waiting on
the plane to take me on, I got:
wlan0: Limiting TX power to 23 dBm as advertised by 50:06:04:bb:d2:de
In other words, v6 still appears to work fine in practical testing. :-)
/* Steinar */
--
Homepage: http://www.sesse.net/
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions)
2014-08-30 18:45 ` Steinar H. Gunderson
` (2 preceding siblings ...)
2014-08-29 17:38 ` [PATCH v5 2/2] mac80211: support DTPC IE (from Cisco Client eXtensions) Steinar H. Gunderson
@ 2014-08-29 17:38 ` Steinar H. Gunderson
3 siblings, 0 replies; 26+ messages in thread
From: Steinar H. Gunderson @ 2014-08-29 17:38 UTC (permalink / raw)
To: linux-wireless
Linux already supports 802.11h, where the access point can tell the
client to reduce its transmission power. However, 802.11h is only
defined for 5 GHz, where the need for this is much smaller than on
2.4 GHz.
Cisco has their own solution, called DTPC (Dynamic Transmit Power
Control). Cisco APs on a controller sometimes but not always send
802.11h; they always send DTPC, even on 2.4 GHz. This patch adds support
for parsing and honoring the DTPC IE in addition to the 802.11h
element (they do not always contain the same limits, so both must
be honored); the format is not documented, but very simple.
Tested (on top of wireless.git and on 3.16.1) against a Cisco Aironet
1142 joined to a Cisco 2504 WLC, by setting various transmit power
levels for the given access points and observing the results.
The Wireshark 802.11 dissector agrees with the interpretation of the
element, except for negative numbers, which seem to never happen
anyway.
Signed-off-by: Steinar H. Gunderson <sgunderson@bigfoot.com>
---
include/linux/ieee80211.h | 3 ++-
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mlme.c | 55 ++++++++++++++++++++++++++++++++++++--------
net/mac80211/util.c | 20 ++++++++++++++++
4 files changed, 68 insertions(+), 11 deletions(-)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 63ab3873..d0ec287 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1806,7 +1806,8 @@ enum ieee80211_eid {
WLAN_EID_DMG_TSPEC = 146,
WLAN_EID_DMG_AT = 147,
WLAN_EID_DMG_CAP = 148,
- /* 149-150 reserved for Cisco */
+ /* 149 reserved for Cisco */
+ WLAN_EID_CISCO_VENDOR_SPECIFIC = 150,
WLAN_EID_DMG_OPERATION = 151,
WLAN_EID_DMG_BSS_PARAM_CHANGE = 152,
WLAN_EID_DMG_BEAM_REFINEMENT = 153,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ef7a089..e995556 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1367,6 +1367,7 @@ struct ieee802_11_elems {
const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
const u8 *country_elem;
const u8 *pwr_constr_elem;
+ const u8 *cisco_dtpc_elem;
const struct ieee80211_timeout_interval_ie *timeout_int;
const u8 *opmode_notif;
const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 524c7cc..a83b67e 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1217,14 +1217,31 @@ static bool ieee80211_find_80211h_pwr_constr(
return have_chan_pwr;
}
+static bool ieee80211_find_cisco_dtpc(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel *channel,
+ const u8 *cisco_dtpc_ie,
+ int *pwr_level)
+{
+ /* From practical testing, the first data byte of the DTPC element
+ * seems to contain the requested dBm level, and the CLI on Cisco
+ * APs clearly state the range is -127 to 127 dBm, which indicates
+ * a signed byte, although it seemingly never actually goes negative.
+ * The other byte seems to always be zero.
+ */
+ *pwr_level = (__s8)cisco_dtpc_ie[4];
+ return true;
+}
+
static bool ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *channel,
struct ieee80211_mgmt *mgmt,
const u8 *country_ie, u8 country_ie_len,
- const u8 *pwr_constr_ie)
+ const u8 *pwr_constr_ie,
+ const u8 *cisco_dtpc_ie)
{
- bool has_80211h_pwr = false;
- int chan_pwr, pwr_reduction_80211h;
+ bool has_80211h_pwr = false, has_cisco_pwr = false;
+ int chan_pwr = 0, pwr_reduction_80211h = 0;
+ int pwr_level_cisco, pwr_level_80211h;
int new_ap_level;
if (country_ie && pwr_constr_ie &&
@@ -1233,16 +1250,33 @@ static bool ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
has_80211h_pwr = ieee80211_find_80211h_pwr_constr(
sdata, channel, country_ie, country_ie_len,
pwr_constr_ie, &chan_pwr, &pwr_reduction_80211h);
- new_ap_level = max_t(int, 0, chan_pwr - pwr_reduction_80211h);
+ pwr_level_80211h =
+ max_t(int, 0, chan_pwr - pwr_reduction_80211h);
}
- if (!has_80211h_pwr)
+ if (cisco_dtpc_ie)
+ has_cisco_pwr = ieee80211_find_cisco_dtpc(
+ sdata, channel, cisco_dtpc_ie, &pwr_level_cisco);
+
+ if (!has_80211h_pwr && !has_cisco_pwr)
return 0;
- sdata_info(sdata,
- "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
- new_ap_level, chan_pwr, pwr_reduction_80211h,
- sdata->u.mgd.bssid);
+ /* If we have both 802.11h and Cisco DTPC, apply both limits
+ * by picking the smallest of the two power levels advertised.
+ */
+ if (has_80211h_pwr &&
+ (!has_cisco_pwr || pwr_level_80211h <= pwr_level_cisco)) {
+ sdata_info(sdata,
+ "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
+ pwr_level_80211h, chan_pwr, pwr_reduction_80211h,
+ sdata->u.mgd.bssid);
+ new_ap_level = pwr_level_80211h;
+ } else { /* has_cisco_pwr is always true here. */
+ sdata_info(sdata,
+ "Limiting TX power to %d dBm as advertised by %pM\n",
+ pwr_level_cisco, sdata->u.mgd.bssid);
+ new_ap_level = pwr_level_cisco;
+ }
if (sdata->ap_power_level == new_ap_level)
return 0;
@@ -3219,7 +3253,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt,
elems.country_elem,
elems.country_elem_len,
- elems.pwr_constr_elem);
+ elems.pwr_constr_elem,
+ elems.cisco_dtpc_elem);
ieee80211_bss_info_change_notify(sdata, changed);
}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 725af7a..56105f4 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1014,6 +1014,26 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
}
elems->pwr_constr_elem = pos;
break;
+ case WLAN_EID_CISCO_VENDOR_SPECIFIC:
+ /* Lots of different options exist, but we only care
+ * about the Dynamic Transmit Power Control element.
+ * First check for the Cisco OUI, then for the DTPC
+ * tag (0x00).
+ */
+ if (elen < 4) {
+ elem_parse_failed = true;
+ break;
+ }
+ if (pos[0] != 0x00 || pos[1] != 0x40 ||
+ pos[2] != 0x96 || pos[3] != 0x00) {
+ break;
+ }
+ if (elen != 6) {
+ elem_parse_failed = true;
+ break;
+ }
+ elems->cisco_dtpc_elem = pos;
+ break;
case WLAN_EID_TIMEOUT_INTERVAL:
if (elen >= sizeof(struct ieee80211_timeout_interval_ie))
elems->timeout_int = (void *)pos;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 26+ messages in thread