summaryrefslogtreecommitdiff
path: root/net/wireless
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-02-03 12:41:58 -0800
committerDavid S. Miller <davem@davemloft.net>2009-02-03 12:41:58 -0800
commit1725d409caba16ea5fc694bd50e95e79e8ced11a (patch)
tree688fe26dd4ceda5364692f0ce307aadb6f04f331 /net/wireless
parentb3ff29d2ccfe3af065a9b393699a8fbf2abd1b15 (diff)
parentb8abde45d7d6ab9e8ceced9b5990eeb1149d0b97 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.c12
-rw-r--r--net/wireless/nl80211.c81
-rw-r--r--net/wireless/reg.c285
-rw-r--r--net/wireless/reg.h7
-rw-r--r--net/wireless/sysfs.c30
-rw-r--r--net/wireless/util.c2
6 files changed, 328 insertions, 89 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index b96fc0c3f1c4..125226476089 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -273,10 +273,16 @@ int wiphy_register(struct wiphy *wiphy)
sband->band = band;
- if (!sband->n_channels || !sband->n_bitrates) {
- WARN_ON(1);
+ if (WARN_ON(!sband->n_channels || !sband->n_bitrates))
+ return -EINVAL;
+
+ /*
+ * Since we use a u32 for rate bitmaps in
+ * ieee80211_get_response_rate, we cannot
+ * have more than 32 legacy rates.
+ */
+ if (WARN_ON(sband->n_bitrates > 32))
return -EINVAL;
- }
for (i = 0; i < sband->n_channels; i++) {
sband->channels[i].orig_flags =
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1e728fff474e..e69da8d20474 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -105,6 +105,10 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
[NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY,
.len = NL80211_HT_CAPABILITY_LEN },
+
+ [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
+ [NL80211_ATTR_IE] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_DATA_LEN },
};
/* message building helper */
@@ -738,7 +742,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_KEY_IDX])
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
- if (key_idx > 3)
+ if (key_idx > 5)
return -EINVAL;
if (info->attrs[NL80211_ATTR_MAC])
@@ -804,30 +808,41 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
int err;
struct net_device *dev;
u8 key_idx;
+ int (*func)(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index);
if (!info->attrs[NL80211_ATTR_KEY_IDX])
return -EINVAL;
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
- if (key_idx > 3)
+ if (info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) {
+ if (key_idx < 4 || key_idx > 5)
+ return -EINVAL;
+ } else if (key_idx > 3)
return -EINVAL;
/* currently only support setting default key */
- if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
+ if (!info->attrs[NL80211_ATTR_KEY_DEFAULT] &&
+ !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT])
return -EINVAL;
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err)
return err;
- if (!drv->ops->set_default_key) {
+ if (info->attrs[NL80211_ATTR_KEY_DEFAULT])
+ func = drv->ops->set_default_key;
+ else
+ func = drv->ops->set_default_mgmt_key;
+
+ if (!func) {
err = -EOPNOTSUPP;
goto out;
}
rtnl_lock();
- err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
+ err = func(&drv->wiphy, dev, key_idx);
rtnl_unlock();
out:
@@ -863,7 +878,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
- if (key_idx > 3)
+ if (key_idx > 5)
return -EINVAL;
/*
@@ -894,6 +909,10 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
if (params.key_len != 13)
return -EINVAL;
break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ if (params.key_len != 16)
+ return -EINVAL;
+ break;
default:
return -EINVAL;
}
@@ -928,7 +947,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_KEY_IDX])
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
- if (key_idx > 3)
+ if (key_idx > 5)
return -EINVAL;
if (info->attrs[NL80211_ATTR_MAC])
@@ -1889,6 +1908,11 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
mutex_lock(&cfg80211_drv_mutex);
r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY);
mutex_unlock(&cfg80211_drv_mutex);
+ /* This means the regulatory domain was already set, however
+ * we don't want to confuse userspace with a "successful error"
+ * message so lets just treat it as a success */
+ if (r == -EALREADY)
+ r = 0;
return r;
}
@@ -2134,6 +2158,43 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}
+static int nl80211_set_mgmt_extra_ie(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ struct mgmt_extra_ie_params params;
+
+ memset(&params, 0, sizeof(params));
+
+ if (!info->attrs[NL80211_ATTR_MGMT_SUBTYPE])
+ return -EINVAL;
+ params.subtype = nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
+ if (params.subtype > 15)
+ return -EINVAL; /* FC Subtype field is 4 bits (0..15) */
+
+ if (info->attrs[NL80211_ATTR_IE]) {
+ params.ies = nla_data(info->attrs[NL80211_ATTR_IE]);
+ params.ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ }
+
+ err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ if (err)
+ return err;
+
+ if (drv->ops->set_mgmt_extra_ie) {
+ rtnl_lock();
+ err = drv->ops->set_mgmt_extra_ie(&drv->wiphy, dev, &params);
+ rtnl_unlock();
+ } else
+ err = -EOPNOTSUPP;
+
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -2295,6 +2356,12 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = NL80211_CMD_SET_MGMT_EXTRA_IE,
+ .doit = nl80211_set_mgmt_extra_ie,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};
/* multicast groups */
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 85c9034c59b2..f643d3981102 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -42,38 +42,6 @@
#include "core.h"
#include "reg.h"
-/**
- * struct regulatory_request - receipt of last regulatory request
- *
- * @wiphy: this is set if this request's initiator is
- * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
- * can be used by the wireless core to deal with conflicts
- * and potentially inform users of which devices specifically
- * cased the conflicts.
- * @initiator: indicates who sent this request, could be any of
- * of those set in reg_set_by, %REGDOM_SET_BY_*
- * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested
- * regulatory domain. We have a few special codes:
- * 00 - World regulatory domain
- * 99 - built by driver but a specific alpha2 cannot be determined
- * 98 - result of an intersection between two regulatory domains
- * @intersect: indicates whether the wireless core should intersect
- * the requested regulatory domain with the presently set regulatory
- * domain.
- * @country_ie_checksum: checksum of the last processed and accepted
- * country IE
- * @country_ie_env: lets us know if the AP is telling us we are outdoor,
- * indoor, or if it doesn't matter
- */
-struct regulatory_request {
- struct wiphy *wiphy;
- enum reg_set_by initiator;
- char alpha2[2];
- bool intersect;
- u32 country_ie_checksum;
- enum environment_cap country_ie_env;
-};
-
/* Receipt of information from last regulatory request */
static struct regulatory_request *last_request;
@@ -790,42 +758,35 @@ static u32 map_regdom_flags(u32 rd_flags)
return channel_flags;
}
-/**
- * freq_reg_info - get regulatory information for the given frequency
- * @center_freq: Frequency in KHz for which we want regulatory information for
- * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one
- * you can set this to 0. If this frequency is allowed we then set
- * this value to the maximum allowed bandwidth.
- * @reg_rule: the regulatory rule which we have for this frequency
- *
- * Use this function to get the regulatory rule for a specific frequency on
- * a given wireless device. If the device has a specific regulatory domain
- * it wants to follow we respect that unless a country IE has been received
- * and processed already.
- *
- * Returns 0 if it was able to find a valid regulatory rule which does
- * apply to the given center_freq otherwise it returns non-zero. It will
- * also return -ERANGE if we determine the given center_freq does not even have
- * a regulatory rule for a frequency range in the center_freq's band. See
- * freq_in_rule_band() for our current definition of a band -- this is purely
- * subjective and right now its 802.11 specific.
- */
-static int freq_reg_info(u32 center_freq, u32 *bandwidth,
- const struct ieee80211_reg_rule **reg_rule)
+static int freq_reg_info_regd(struct wiphy *wiphy,
+ u32 center_freq,
+ u32 *bandwidth,
+ const struct ieee80211_reg_rule **reg_rule,
+ const struct ieee80211_regdomain *custom_regd)
{
int i;
bool band_rule_found = false;
+ const struct ieee80211_regdomain *regd;
u32 max_bandwidth = 0;
- if (!cfg80211_regdomain)
+ regd = custom_regd ? custom_regd : cfg80211_regdomain;
+
+ /* Follow the driver's regulatory domain, if present, unless a country
+ * IE has been processed or a user wants to help complaince further */
+ if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE &&
+ last_request->initiator != REGDOM_SET_BY_USER &&
+ wiphy->regd)
+ regd = wiphy->regd;
+
+ if (!regd)
return -EINVAL;
- for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) {
+ for (i = 0; i < regd->n_reg_rules; i++) {
const struct ieee80211_reg_rule *rr;
const struct ieee80211_freq_range *fr = NULL;
const struct ieee80211_power_rule *pr = NULL;
- rr = &cfg80211_regdomain->reg_rules[i];
+ rr = &regd->reg_rules[i];
fr = &rr->freq_range;
pr = &rr->power_rule;
@@ -849,6 +810,14 @@ static int freq_reg_info(u32 center_freq, u32 *bandwidth,
return !max_bandwidth;
}
+EXPORT_SYMBOL(freq_reg_info);
+
+int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
+ const struct ieee80211_reg_rule **reg_rule)
+{
+ return freq_reg_info_regd(wiphy, center_freq,
+ bandwidth, reg_rule, NULL);
+}
static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
unsigned int chan_idx)
@@ -867,7 +836,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
flags = chan->orig_flags;
- r = freq_reg_info(MHZ_TO_KHZ(chan->center_freq),
+ r = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq),
&max_bandwidth, &reg_rule);
if (r) {
@@ -907,6 +876,22 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
power_rule = &reg_rule->power_rule;
+ if (last_request->initiator == REGDOM_SET_BY_DRIVER &&
+ last_request->wiphy && last_request->wiphy == wiphy &&
+ last_request->wiphy->strict_regulatory) {
+ /* This gaurantees the driver's requested regulatory domain
+ * will always be used as a base for further regulatory
+ * settings */
+ chan->flags = chan->orig_flags =
+ map_regdom_flags(reg_rule->flags);
+ chan->max_antenna_gain = chan->orig_mag =
+ (int) MBI_TO_DBI(power_rule->max_antenna_gain);
+ chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth);
+ chan->max_power = chan->orig_mpwr =
+ (int) MBM_TO_DBM(power_rule->max_eirp);
+ return;
+ }
+
chan->flags = flags | map_regdom_flags(reg_rule->flags);
chan->max_antenna_gain = min(chan->orig_mag,
(int) MBI_TO_DBI(power_rule->max_antenna_gain));
@@ -935,7 +920,12 @@ static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby)
if (!last_request)
return true;
if (setby == REGDOM_SET_BY_CORE &&
- wiphy->fw_handles_regulatory)
+ wiphy->custom_regulatory)
+ return true;
+ /* wiphy->regd will be set once the device has its own
+ * desired regulatory domain set */
+ if (wiphy->strict_regulatory && !wiphy->regd &&
+ !is_world_regdom(last_request->alpha2))
return true;
return false;
}
@@ -945,20 +935,103 @@ static void update_all_wiphy_regulatory(enum reg_set_by setby)
struct cfg80211_registered_device *drv;
list_for_each_entry(drv, &cfg80211_drv_list, list)
- if (!ignore_reg_update(&drv->wiphy, setby))
- wiphy_update_regulatory(&drv->wiphy, setby);
+ wiphy_update_regulatory(&drv->wiphy, setby);
}
void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
{
enum ieee80211_band band;
+
+ if (ignore_reg_update(wiphy, setby))
+ return;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (wiphy->bands[band])
handle_band(wiphy, band);
- if (wiphy->reg_notifier)
- wiphy->reg_notifier(wiphy, setby);
+ }
+ if (wiphy->reg_notifier)
+ wiphy->reg_notifier(wiphy, last_request);
+}
+
+static void handle_channel_custom(struct wiphy *wiphy,
+ enum ieee80211_band band,
+ unsigned int chan_idx,
+ const struct ieee80211_regdomain *regd)
+{
+ int r;
+ u32 max_bandwidth = 0;
+ const struct ieee80211_reg_rule *reg_rule = NULL;
+ const struct ieee80211_power_rule *power_rule = NULL;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *chan;
+
+ sband = wiphy->bands[band];
+ BUG_ON(chan_idx >= sband->n_channels);
+ chan = &sband->channels[chan_idx];
+
+ r = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq),
+ &max_bandwidth, &reg_rule, regd);
+
+ if (r) {
+ chan->flags = IEEE80211_CHAN_DISABLED;
+ return;
+ }
+
+ power_rule = &reg_rule->power_rule;
+
+ chan->flags |= map_regdom_flags(reg_rule->flags);
+ chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain);
+ chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth);
+ chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);
+}
+
+static void handle_band_custom(struct wiphy *wiphy, enum ieee80211_band band,
+ const struct ieee80211_regdomain *regd)
+{
+ unsigned int i;
+ struct ieee80211_supported_band *sband;
+
+ BUG_ON(!wiphy->bands[band]);
+ sband = wiphy->bands[band];
+
+ for (i = 0; i < sband->n_channels; i++)
+ handle_channel_custom(wiphy, band, i, regd);
+}
+
+/* Used by drivers prior to wiphy registration */
+void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
+ const struct ieee80211_regdomain *regd)
+{
+ enum ieee80211_band band;
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ if (wiphy->bands[band])
+ handle_band_custom(wiphy, band, regd);
}
}
+EXPORT_SYMBOL(wiphy_apply_custom_regulatory);
+
+static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
+ const struct ieee80211_regdomain *src_regd)
+{
+ struct ieee80211_regdomain *regd;
+ int size_of_regd = 0;
+ unsigned int i;
+
+ size_of_regd = sizeof(struct ieee80211_regdomain) +
+ ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
+
+ regd = kzalloc(size_of_regd, GFP_KERNEL);
+ if (!regd)
+ return -ENOMEM;
+
+ memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
+
+ for (i = 0; i < src_regd->n_reg_rules; i++)
+ memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i],
+ sizeof(struct ieee80211_reg_rule));
+
+ *dst_regd = regd;
+ return 0;
+}
/* Return value which can be used by ignore_request() to indicate
* it has been determined we should intersect two regulatory domains */
@@ -1007,9 +1080,14 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
}
return REG_INTERSECT;
case REGDOM_SET_BY_DRIVER:
- if (last_request->initiator == REGDOM_SET_BY_DRIVER)
+ if (last_request->initiator == REGDOM_SET_BY_CORE) {
+ if (is_old_static_regdom(cfg80211_regdomain))
+ return 0;
+ if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
+ return 0;
return -EALREADY;
- return 0;
+ }
+ return REG_INTERSECT;
case REGDOM_SET_BY_USER:
if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
return REG_INTERSECT;
@@ -1018,6 +1096,20 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
if (last_request->initiator == REGDOM_SET_BY_USER &&
last_request->intersect)
return -EOPNOTSUPP;
+ /* Process user requests only after previous user/driver/core
+ * requests have been processed */
+ if (last_request->initiator == REGDOM_SET_BY_CORE ||
+ last_request->initiator == REGDOM_SET_BY_DRIVER ||
+ last_request->initiator == REGDOM_SET_BY_USER) {
+ if (!alpha2_equal(last_request->alpha2,
+ cfg80211_regdomain->alpha2))
+ return -EAGAIN;
+ }
+
+ if (!is_old_static_regdom(cfg80211_regdomain) &&
+ alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
+ return -EALREADY;
+
return 0;
}
@@ -1036,11 +1128,28 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
r = ignore_request(wiphy, set_by, alpha2);
- if (r == REG_INTERSECT)
+ if (r == REG_INTERSECT) {
+ if (set_by == REGDOM_SET_BY_DRIVER) {
+ r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
+ if (r)
+ return r;
+ }
intersect = true;
- else if (r)
+ } else if (r) {
+ /* If the regulatory domain being requested by the
+ * driver has already been set just copy it to the
+ * wiphy */
+ if (r == -EALREADY && set_by == REGDOM_SET_BY_DRIVER) {
+ r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
+ if (r)
+ return r;
+ r = -EALREADY;
+ goto new_request;
+ }
return r;
+ }
+new_request:
request = kzalloc(sizeof(struct regulatory_request),
GFP_KERNEL);
if (!request)
@@ -1056,6 +1165,11 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
kfree(last_request);
last_request = request;
+
+ /* When r == REG_INTERSECT we do need to call CRDA */
+ if (r < 0)
+ return r;
+
/*
* Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled
* AND if CRDA is NOT present nothing will happen, if someone
@@ -1071,10 +1185,15 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
void regulatory_hint(struct wiphy *wiphy, const char *alpha2)
{
+ int r;
BUG_ON(!alpha2);
mutex_lock(&cfg80211_drv_mutex);
- __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, 0, ENVIRON_ANY);
+ r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER,
+ alpha2, 0, ENVIRON_ANY);
+ /* This is required so that the orig_* parameters are saved */
+ if (r == -EALREADY && wiphy->strict_regulatory)
+ wiphy_update_regulatory(wiphy, REGDOM_SET_BY_DRIVER);
mutex_unlock(&cfg80211_drv_mutex);
}
EXPORT_SYMBOL(regulatory_hint);
@@ -1247,7 +1366,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
"domain intersected: \n");
} else
printk(KERN_INFO "cfg80211: Current regulatory "
- "intersected: \n");
+ "domain intersected: \n");
} else if (is_world_regdom(rd->alpha2))
printk(KERN_INFO "cfg80211: World regulatory "
"domain updated:\n");
@@ -1349,6 +1468,23 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
}
if (!last_request->intersect) {
+ int r;
+
+ if (last_request->initiator != REGDOM_SET_BY_DRIVER) {
+ reset_regdomains();
+ cfg80211_regdomain = rd;
+ return 0;
+ }
+
+ /* For a driver hint, lets copy the regulatory domain the
+ * driver wanted to the wiphy to deal with conflicts */
+
+ BUG_ON(last_request->wiphy->regd);
+
+ r = reg_copy_regd(&last_request->wiphy->regd, rd);
+ if (r)
+ return r;
+
reset_regdomains();
cfg80211_regdomain = rd;
return 0;
@@ -1362,8 +1498,14 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
if (!intersected_rd)
return -EINVAL;
- /* We can trash what CRDA provided now */
- kfree(rd);
+ /* We can trash what CRDA provided now.
+ * However if a driver requested this specific regulatory
+ * domain we keep it for its private use */
+ if (last_request->initiator == REGDOM_SET_BY_DRIVER)
+ last_request->wiphy->regd = rd;
+ else
+ kfree(rd);
+
rd = NULL;
reset_regdomains();
@@ -1447,6 +1589,7 @@ int set_regdom(const struct ieee80211_regdomain *rd)
/* Caller must hold cfg80211_drv_mutex */
void reg_device_remove(struct wiphy *wiphy)
{
+ kfree(wiphy->regd);
if (!last_request || !last_request->wiphy)
return;
if (last_request->wiphy != wiphy)
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index a76ea3ff7cd6..eb1dd5bc9b27 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -11,13 +11,6 @@ void regulatory_exit(void);
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
* @wiphy: if the hint comes from country information from an AP, this
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index 79a382877641..26a72b0797a0 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -55,6 +55,34 @@ static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
}
#endif
+static int wiphy_suspend(struct device *dev, pm_message_t state)
+{
+ struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
+ int ret = 0;
+
+ if (rdev->ops->suspend) {
+ rtnl_lock();
+ ret = rdev->ops->suspend(&rdev->wiphy);
+ rtnl_unlock();
+ }
+
+ return ret;
+}
+
+static int wiphy_resume(struct device *dev)
+{
+ struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
+ int ret = 0;
+
+ if (rdev->ops->resume) {
+ rtnl_lock();
+ ret = rdev->ops->resume(&rdev->wiphy);
+ rtnl_unlock();
+ }
+
+ return ret;
+}
+
struct class ieee80211_class = {
.name = "ieee80211",
.owner = THIS_MODULE,
@@ -63,6 +91,8 @@ struct class ieee80211_class = {
#ifdef CONFIG_HOTPLUG
.dev_uevent = wiphy_uevent,
#endif
+ .suspend = wiphy_suspend,
+ .resume = wiphy_resume,
};
int wiphy_sysfs_init(void)
diff --git a/net/wireless/util.c b/net/wireless/util.c
index e76cc28b0345..487cdd9bcffc 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -9,7 +9,7 @@
struct ieee80211_rate *
ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
- u64 basic_rates, int bitrate)
+ u32 basic_rates, int bitrate)
{
struct ieee80211_rate *result = &sband->bitrates[0];
int i;