Commit 3f2355cb authored by Luis R. Rodriguez's avatar Luis R. Rodriguez Committed by John W. Linville

cfg80211/mac80211: Add 802.11d support

This adds country IE parsing to mac80211 and enables its usage
within the new regulatory infrastructure in cfg80211. We parse
the country IEs only on management beacons for the BSSID you are
associated to and disregard the IEs when the country and environment
(indoor, outdoor, any) matches the already processed country IE.

To avoid following misinformed or outdated APs we build and use
a regulatory domain out of the intersection between what the AP
provides us on the country IE and what CRDA is aware is allowed
on the same country.

A secondary device is allowed to follow only the same country IE
as it make no sense for two devices on a system to be in two
different countries.

In the case the AP is using country IEs for an incorrect country
the user may help compliance further by setting the regulatory
domain before or after the IE is parsed and in that case another
intersection will be performed.

CONFIG_WIRELESS_OLD_REGULATORY is supported but requires CRDA
present.
Signed-off-by: default avatarLuis R. Rodriguez <lrodriguez@atheros.com>
Acked-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 88dc1c3f
...@@ -1042,6 +1042,68 @@ enum ieee80211_spectrum_mgmt_actioncode { ...@@ -1042,6 +1042,68 @@ enum ieee80211_spectrum_mgmt_actioncode {
WLAN_ACTION_SPCT_CHL_SWITCH = 4, WLAN_ACTION_SPCT_CHL_SWITCH = 4,
}; };
/*
* IEEE 802.11-2007 7.3.2.9 Country information element
*
* Minimum length is 8 octets, ie len must be evenly
* divisible by 2
*/
/* Although the spec says 8 I'm seeing 6 in practice */
#define IEEE80211_COUNTRY_IE_MIN_LEN 6
/*
* For regulatory extension stuff see IEEE 802.11-2007
* Annex I (page 1141) and Annex J (page 1147). Also
* review 7.3.2.9.
*
* When dot11RegulatoryClassesRequired is true and the
* first_channel/reg_extension_id is >= 201 then the IE
* compromises of the 'ext' struct represented below:
*
* - Regulatory extension ID - when generating IE this just needs
* to be monotonically increasing for each triplet passed in
* the IE
* - Regulatory class - index into set of rules
* - Coverage class - index into air propagation time (Table 7-27),
* in microseconds, you can compute the air propagation time from
* the index by multiplying by 3, so index 10 yields a propagation
* of 10 us. Valid values are 0-31, values 32-255 are not defined
* yet. A value of 0 inicates air propagation of <= 1 us.
*
* See also Table I.2 for Emission limit sets and table
* I.3 for Behavior limit sets. Table J.1 indicates how to map
* a reg_class to an emission limit set and behavior limit set.
*/
#define IEEE80211_COUNTRY_EXTENSION_ID 201
/*
* Channels numbers in the IE must be monotonically increasing
* if dot11RegulatoryClassesRequired is not true.
*
* If dot11RegulatoryClassesRequired is true consecutive
* subband triplets following a regulatory triplet shall
* have monotonically increasing first_channel number fields.
*
* Channel numbers shall not overlap.
*
* Note that max_power is signed.
*/
struct ieee80211_country_ie_triplet {
union {
struct {
u8 first_channel;
u8 num_channels;
s8 max_power;
} __attribute__ ((packed)) chans;
struct {
u8 reg_extension_id;
u8 reg_class;
u8 coverage_class;
} __attribute__ ((packed)) ext;
};
} __attribute__ ((packed));
/* BACK action code */ /* BACK action code */
enum ieee80211_back_actioncode { enum ieee80211_back_actioncode {
WLAN_ACTION_ADDBA_REQ = 0, WLAN_ACTION_ADDBA_REQ = 0,
......
...@@ -373,4 +373,19 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband, ...@@ -373,4 +373,19 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
* for a regulatory domain structure for the respective country. * for a regulatory domain structure for the respective country.
*/ */
extern void regulatory_hint(struct wiphy *wiphy, const char *alpha2); extern void regulatory_hint(struct wiphy *wiphy, const char *alpha2);
/**
* regulatory_hint_11d - hints a country IE as a regulatory domain
* @wiphy: the wireless device giving the hint (used only for reporting
* conflicts)
* @country_ie: pointer to the country IE
* @country_ie_len: length of the country IE
*
* We will intersect the rd with the what CRDA tells us should apply
* for the alpha2 this country IE belongs to, this prevents APs from
* sending us incorrect or outdated information against a country.
*/
extern void regulatory_hint_11d(struct wiphy *wiphy,
u8 *country_ie,
u8 country_ie_len);
#endif /* __NET_WIRELESS_H */ #endif /* __NET_WIRELESS_H */
...@@ -1736,6 +1736,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, ...@@ -1736,6 +1736,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ap_ht_cap_flags); ap_ht_cap_flags);
} }
if (elems.country_elem) {
/* Note we are only reviewing this on beacons
* for the BSSID we are associated to */
regulatory_hint_11d(local->hw.wiphy,
elems.country_elem, elems.country_elem_len);
}
ieee80211_bss_info_change_notify(sdata, changed); ieee80211_bss_info_change_notify(sdata, changed);
} }
......
config CFG80211 config CFG80211
tristate "Improved wireless configuration API" tristate "Improved wireless configuration API"
config CFG80211_REG_DEBUG
bool "cfg80211 regulatory debugging"
depends on CFG80211
default n
---help---
You can enable this if you want to debug regulatory changes.
If unsure, say N.
config NL80211 config NL80211
bool "nl80211 new netlink interface support" bool "nl80211 new netlink interface support"
depends on CFG80211 depends on CFG80211
...@@ -40,6 +49,8 @@ config WIRELESS_OLD_REGULATORY ...@@ -40,6 +49,8 @@ config WIRELESS_OLD_REGULATORY
ieee80211_regdom module parameter. This is being phased out and you ieee80211_regdom module parameter. This is being phased out and you
should stop using them ASAP. should stop using them ASAP.
Note: You will need CRDA if you want 802.11d support
Say Y unless you have installed a new userspace application. Say Y unless you have installed a new userspace application.
Also say Y if have one currently depending on the ieee80211_regdom Also say Y if have one currently depending on the ieee80211_regdom
module parameter and cannot port it to use the new userspace module parameter and cannot port it to use the new userspace
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include "nl80211.h" #include "nl80211.h"
#include "core.h" #include "core.h"
#include "sysfs.h" #include "sysfs.h"
#include "reg.h"
/* name for sysfs, %d is appended */ /* name for sysfs, %d is appended */
#define PHY_NAME "phy" #define PHY_NAME "phy"
...@@ -348,6 +347,10 @@ void wiphy_unregister(struct wiphy *wiphy) ...@@ -348,6 +347,10 @@ void wiphy_unregister(struct wiphy *wiphy)
/* unlock again before freeing */ /* unlock again before freeing */
mutex_unlock(&drv->mtx); mutex_unlock(&drv->mtx);
/* If this device got a regulatory hint tell core its
* free to listen now to a new shiny device regulatory hint */
reg_device_remove(wiphy);
list_del(&drv->list); list_del(&drv->list);
device_del(&drv->wiphy.dev); device_del(&drv->wiphy.dev);
debugfs_remove(drv->wiphy.debugfsdir); debugfs_remove(drv->wiphy.debugfsdir);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <net/genetlink.h> #include <net/genetlink.h>
#include <net/wireless.h> #include <net/wireless.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include "reg.h"
struct cfg80211_registered_device { struct cfg80211_registered_device {
struct cfg80211_ops *ops; struct cfg80211_ops *ops;
...@@ -21,6 +22,18 @@ struct cfg80211_registered_device { ...@@ -21,6 +22,18 @@ struct cfg80211_registered_device {
* any call is in progress */ * any call is in progress */
struct mutex mtx; struct mutex mtx;
/* ISO / IEC 3166 alpha2 for which this device is receiving
* country IEs on, this can help disregard country IEs from APs
* on the same alpha2 quickly. The alpha2 may differ from
* cfg80211_regdomain's alpha2 when an intersection has occurred.
* If the AP is reconfigured this can also be used to tell us if
* the country on the country IE changed. */
char country_ie_alpha2[2];
/* If a Country IE has been received this tells us the environment
* which its telling us its in. This defaults to ENVIRON_ANY */
enum environment_cap env;
/* wiphy index, internal only */ /* wiphy index, internal only */
int idx; int idx;
......
...@@ -1760,7 +1760,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) ...@@ -1760,7 +1760,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
return -EINVAL; return -EINVAL;
#endif #endif
mutex_lock(&cfg80211_drv_mutex); mutex_lock(&cfg80211_drv_mutex);
r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data); r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY);
mutex_unlock(&cfg80211_drv_mutex); mutex_unlock(&cfg80211_drv_mutex);
return r; return r;
} }
......
This diff is collapsed.
...@@ -4,28 +4,41 @@ ...@@ -4,28 +4,41 @@
bool is_world_regdom(const char *alpha2); bool is_world_regdom(const char *alpha2);
bool reg_is_valid_request(const char *alpha2); bool reg_is_valid_request(const char *alpha2);
void reg_device_remove(struct wiphy *wiphy);
int regulatory_init(void); int regulatory_init(void);
void regulatory_exit(void); void regulatory_exit(void);
int set_regdom(const struct ieee80211_regdomain *rd); int set_regdom(const struct ieee80211_regdomain *rd);
enum environment_cap {
ENVIRON_ANY,
ENVIRON_INDOOR,
ENVIRON_OUTDOOR,
};
/** /**
* __regulatory_hint - hint to the wireless core a regulatory domain * __regulatory_hint - hint to the wireless core a regulatory domain
* @wiphy: if the hint comes from country information from an AP, this * @wiphy: if the hint comes from country information from an AP, this
* is required to be set to the wiphy that received the information * is required to be set to the wiphy that received the information
* @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain * @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain
* should be in. * should be in.
* @country_ie_checksum: checksum of processed country IE, set this to 0
* if the hint did not come from a country IE
* @country_ie_env: the environment the IE told us we are in, %ENVIRON_*
* *
* The Wireless subsystem can use this function to hint to the wireless core * The Wireless subsystem can use this function to hint to the wireless core
* what it believes should be the current regulatory domain by * what it believes should be the current regulatory domain by giving it an
* giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory * ISO/IEC 3166 alpha2 country code it knows its regulatory domain should be
* domain should be in. * in.
* *
* Returns zero if all went fine, %-EALREADY if a regulatory domain had * Returns zero if all went fine, %-EALREADY if a regulatory domain had
* already been set or other standard error codes. * already been set or other standard error codes.
* *
*/ */
extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
const char *alpha2); const char *alpha2, u32 country_ie_checksum,
enum environment_cap country_ie_env);
#endif /* __NET_WIRELESS_REG_H */ #endif /* __NET_WIRELESS_REG_H */
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