summaryrefslogtreecommitdiff
path: root/net/wireless
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-03-17 15:04:31 -0700
committerDavid S. Miller <davem@davemloft.net>2009-03-17 15:04:31 -0700
commitaf4330631cd48987755f1a8d324dc318f60cf16b (patch)
tree3c9233e81b450921326da13a7f8abacb58ab1f5e /net/wireless
parent2d6a5e9500103680464a723a4564961675652680 (diff)
parent808ff697b357cee54e214efd27921a9ec6461a94 (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.c13
-rw-r--r--net/wireless/core.h3
-rw-r--r--net/wireless/nl80211.c62
-rw-r--r--net/wireless/nl80211.h5
-rw-r--r--net/wireless/reg.c116
5 files changed, 153 insertions, 46 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index dd7f222919fe..17fe39049740 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -350,7 +350,7 @@ int wiphy_register(struct wiphy *wiphy)
mutex_lock(&cfg80211_mutex);
/* set up regulatory info */
- wiphy_update_regulatory(wiphy, REGDOM_SET_BY_CORE);
+ wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
res = device_add(&drv->wiphy.dev);
if (res)
@@ -365,6 +365,17 @@ int wiphy_register(struct wiphy *wiphy)
if (IS_ERR(drv->wiphy.debugfsdir))
drv->wiphy.debugfsdir = NULL;
+ if (wiphy->custom_regulatory) {
+ struct regulatory_request request;
+
+ request.wiphy_idx = get_wiphy_idx(wiphy);
+ request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
+ request.alpha2[0] = '9';
+ request.alpha2[1] = '9';
+
+ nl80211_send_reg_change_event(&request);
+ }
+
res = 0;
out_unlock:
mutex_unlock(&cfg80211_mutex);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index f6c53f5807f4..6acd483a61f8 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -136,7 +136,8 @@ extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv,
char *newname);
void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
-void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby);
+void wiphy_update_regulatory(struct wiphy *wiphy,
+ enum nl80211_reg_initiator setby);
void cfg80211_bss_expire(struct cfg80211_registered_device *dev);
void cfg80211_bss_age(struct cfg80211_registered_device *dev,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 531bb67cf502..8ac3d26014a8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2739,6 +2739,9 @@ static struct genl_multicast_group nl80211_config_mcgrp = {
static struct genl_multicast_group nl80211_scan_mcgrp = {
.name = "scan",
};
+static struct genl_multicast_group nl80211_regulatory_mcgrp = {
+ .name = "regulatory",
+};
/* notification functions */
@@ -2818,6 +2821,61 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
}
+/*
+ * This can happen on global regulatory changes or device specific settings
+ * based on custom world regulatory domains.
+ */
+void nl80211_send_reg_change_event(struct regulatory_request *request)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ /* Userspace can always count this one always being set */
+ NLA_PUT_U8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator);
+
+ if (request->alpha2[0] == '0' && request->alpha2[1] == '0')
+ NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
+ NL80211_REGDOM_TYPE_WORLD);
+ else if (request->alpha2[0] == '9' && request->alpha2[1] == '9')
+ NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
+ NL80211_REGDOM_TYPE_CUSTOM_WORLD);
+ else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
+ request->intersect)
+ NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
+ NL80211_REGDOM_TYPE_INTERSECTION);
+ else {
+ NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
+ NL80211_REGDOM_TYPE_COUNTRY);
+ NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, request->alpha2);
+ }
+
+ if (wiphy_idx_valid(request->wiphy_idx))
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx);
+
+ if (genlmsg_end(msg, hdr) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_KERNEL);
+
+ return;
+
+nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+}
+
/* initialisation/exit functions */
int nl80211_init(void)
@@ -2842,6 +2900,10 @@ int nl80211_init(void)
if (err)
goto err_out;
+ err = genl_register_mc_group(&nl80211_fam, &nl80211_regulatory_mcgrp);
+ if (err)
+ goto err_out;
+
return 0;
err_out:
genl_unregister_family(&nl80211_fam);
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 69787b621365..e65a3c38c52f 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -11,6 +11,7 @@ extern void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
struct net_device *netdev);
extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
struct net_device *netdev);
+extern void nl80211_send_reg_change_event(struct regulatory_request *request);
#else
static inline int nl80211_init(void)
{
@@ -31,6 +32,10 @@ static inline void nl80211_send_scan_aborted(
struct cfg80211_registered_device *rdev,
struct net_device *netdev)
{}
+static inline void
+nl80211_send_reg_change_event(struct regulatory_request *request)
+{
+}
#endif /* CONFIG_NL80211 */
#endif /* __NET_WIRELESS_NL80211_H */
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 58df98f10990..eb8b8ed16155 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -41,6 +41,7 @@
#include <net/cfg80211.h>
#include "core.h"
#include "reg.h"
+#include "nl80211.h"
/* Receipt of information from last regulatory request */
static struct regulatory_request *last_request;
@@ -86,20 +87,31 @@ struct reg_beacon {
/* We keep a static world regulatory domain in case of the absence of CRDA */
static const struct ieee80211_regdomain world_regdom = {
- .n_reg_rules = 3,
+ .n_reg_rules = 5,
.alpha2 = "00",
.reg_rules = {
/* IEEE 802.11b/g, channels 1..11 */
REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),
- /* IEEE 802.11a, channel 36..48 */
- REG_RULE(5180-10, 5240+10, 40, 6, 23,
+ /* IEEE 802.11b/g, channels 12..13. No HT40
+ * channel fits here. */
+ REG_RULE(2467-10, 2472+10, 20, 6, 20,
NL80211_RRF_PASSIVE_SCAN |
NL80211_RRF_NO_IBSS),
+ /* IEEE 802.11 channel 14 - Only JP enables
+ * this and for 802.11b only */
+ REG_RULE(2484-10, 2484+10, 20, 6, 20,
+ NL80211_RRF_PASSIVE_SCAN |
+ NL80211_RRF_NO_IBSS |
+ NL80211_RRF_NO_OFDM),
+ /* IEEE 802.11a, channel 36..48 */
+ REG_RULE(5180-10, 5240+10, 40, 6, 20,
+ NL80211_RRF_PASSIVE_SCAN |
+ NL80211_RRF_NO_IBSS),
/* NB: 5260 MHz - 5700 MHz requies DFS */
/* IEEE 802.11a, channel 149..165 */
- REG_RULE(5745-10, 5825+10, 40, 6, 23,
+ REG_RULE(5745-10, 5825+10, 40, 6, 20,
NL80211_RRF_PASSIVE_SCAN |
NL80211_RRF_NO_IBSS),
}
@@ -846,8 +858,8 @@ static int freq_reg_info_regd(struct wiphy *wiphy,
* 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 &&
+ if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+ last_request->initiator != NL80211_REGDOM_SET_BY_USER &&
wiphy->regd)
regd = wiphy->regd;
@@ -932,7 +944,8 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
* http://tinyurl.com/11d-clarification
*/
if (r == -ERANGE &&
- last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
+ last_request->initiator ==
+ NL80211_REGDOM_SET_BY_COUNTRY_IE) {
#ifdef CONFIG_CFG80211_REG_DEBUG
printk(KERN_DEBUG "cfg80211: Leaving channel %d MHz "
"intact on %s - no rule found in band on "
@@ -945,7 +958,8 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
* for the band so we respect its band definitions
*/
#ifdef CONFIG_CFG80211_REG_DEBUG
- if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
+ if (last_request->initiator ==
+ NL80211_REGDOM_SET_BY_COUNTRY_IE)
printk(KERN_DEBUG "cfg80211: Disabling "
"channel %d MHz on %s due to "
"Country IE\n",
@@ -959,7 +973,7 @@ 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 &&
+ if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
request_wiphy && request_wiphy == wiphy &&
request_wiphy->strict_regulatory) {
/*
@@ -1000,11 +1014,12 @@ static void handle_band(struct wiphy *wiphy, enum ieee80211_band band)
handle_channel(wiphy, band, i);
}
-static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby)
+static bool ignore_reg_update(struct wiphy *wiphy,
+ enum nl80211_reg_initiator initiator)
{
if (!last_request)
return true;
- if (setby == REGDOM_SET_BY_CORE &&
+ if (initiator == NL80211_REGDOM_SET_BY_CORE &&
wiphy->custom_regulatory)
return true;
/*
@@ -1017,12 +1032,12 @@ static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby)
return false;
}
-static void update_all_wiphy_regulatory(enum reg_set_by setby)
+static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
{
struct cfg80211_registered_device *drv;
list_for_each_entry(drv, &cfg80211_drv_list, list)
- wiphy_update_regulatory(&drv->wiphy, setby);
+ wiphy_update_regulatory(&drv->wiphy, initiator);
}
static void handle_reg_beacon(struct wiphy *wiphy,
@@ -1113,7 +1128,7 @@ static bool reg_is_world_roaming(struct wiphy *wiphy)
if (is_world_regdom(cfg80211_regdomain->alpha2) ||
(wiphy->regd && is_world_regdom(wiphy->regd->alpha2)))
return true;
- if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE &&
+ if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
wiphy->custom_regulatory)
return true;
return false;
@@ -1127,11 +1142,12 @@ static void reg_process_beacons(struct wiphy *wiphy)
wiphy_update_beacon_reg(wiphy);
}
-void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
+void wiphy_update_regulatory(struct wiphy *wiphy,
+ enum nl80211_reg_initiator initiator)
{
enum ieee80211_band band;
- if (ignore_reg_update(wiphy, setby))
+ if (ignore_reg_update(wiphy, initiator))
goto out;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (wiphy->bands[band])
@@ -1244,17 +1260,16 @@ static int ignore_request(struct wiphy *wiphy,
return 0;
switch (pending_request->initiator) {
- case REGDOM_SET_BY_INIT:
+ case NL80211_REGDOM_SET_BY_CORE:
return -EINVAL;
- case REGDOM_SET_BY_CORE:
- return -EINVAL;
- case REGDOM_SET_BY_COUNTRY_IE:
+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:
last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
if (unlikely(!is_an_alpha2(pending_request->alpha2)))
return -EINVAL;
- if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
+ if (last_request->initiator ==
+ NL80211_REGDOM_SET_BY_COUNTRY_IE) {
if (last_wiphy != wiphy) {
/*
* Two cards with two APs claiming different
@@ -1275,8 +1290,8 @@ static int ignore_request(struct wiphy *wiphy,
return -EALREADY;
}
return REG_INTERSECT;
- case REGDOM_SET_BY_DRIVER:
- if (last_request->initiator == REGDOM_SET_BY_CORE) {
+ case NL80211_REGDOM_SET_BY_DRIVER:
+ if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) {
if (is_old_static_regdom(cfg80211_regdomain))
return 0;
if (regdom_changes(pending_request->alpha2))
@@ -1289,28 +1304,28 @@ static int ignore_request(struct wiphy *wiphy,
* back in or if you add a new device for which the previously
* loaded card also agrees on the regulatory domain.
*/
- if (last_request->initiator == REGDOM_SET_BY_DRIVER &&
+ if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
!regdom_changes(pending_request->alpha2))
return -EALREADY;
return REG_INTERSECT;
- case REGDOM_SET_BY_USER:
- if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
+ case NL80211_REGDOM_SET_BY_USER:
+ if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
return REG_INTERSECT;
/*
* If the user knows better the user should set the regdom
* to their country before the IE is picked up
*/
- if (last_request->initiator == REGDOM_SET_BY_USER &&
+ if (last_request->initiator == NL80211_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 (last_request->initiator == NL80211_REGDOM_SET_BY_CORE ||
+ last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
+ last_request->initiator == NL80211_REGDOM_SET_BY_USER) {
if (regdom_changes(last_request->alpha2))
return -EAGAIN;
}
@@ -1350,7 +1365,8 @@ static int __regulatory_hint(struct wiphy *wiphy,
r = ignore_request(wiphy, pending_request);
if (r == REG_INTERSECT) {
- if (pending_request->initiator == REGDOM_SET_BY_DRIVER) {
+ if (pending_request->initiator ==
+ NL80211_REGDOM_SET_BY_DRIVER) {
r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
if (r) {
kfree(pending_request);
@@ -1365,7 +1381,8 @@ static int __regulatory_hint(struct wiphy *wiphy,
* wiphy
*/
if (r == -EALREADY &&
- pending_request->initiator == REGDOM_SET_BY_DRIVER) {
+ pending_request->initiator ==
+ NL80211_REGDOM_SET_BY_DRIVER) {
r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
if (r) {
kfree(pending_request);
@@ -1387,8 +1404,16 @@ new_request:
pending_request = NULL;
/* When r == REG_INTERSECT we do need to call CRDA */
- if (r < 0)
+ if (r < 0) {
+ /*
+ * Since CRDA will not be called in this case as we already
+ * have applied the requested regulatory domain before we just
+ * inform userspace we have processed the request
+ */
+ if (r == -EALREADY)
+ nl80211_send_reg_change_event(last_request);
return r;
+ }
/*
* Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled
@@ -1416,7 +1441,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
if (wiphy_idx_valid(reg_request->wiphy_idx))
wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
- if (reg_request->initiator == REGDOM_SET_BY_DRIVER &&
+ if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
!wiphy) {
kfree(reg_request);
goto out;
@@ -1430,7 +1455,7 @@ out:
mutex_unlock(&cfg80211_mutex);
}
-/* Processes regulatory hints, this is all the REGDOM_SET_BY_* */
+/* Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* */
static void reg_process_pending_hints(void)
{
struct regulatory_request *reg_request;
@@ -1514,7 +1539,7 @@ static int regulatory_hint_core(const char *alpha2)
request->alpha2[0] = alpha2[0];
request->alpha2[1] = alpha2[1];
- request->initiator = REGDOM_SET_BY_CORE;
+ request->initiator = NL80211_REGDOM_SET_BY_CORE;
queue_regulatory_request(request);
@@ -1535,7 +1560,7 @@ int regulatory_hint_user(const char *alpha2)
request->wiphy_idx = WIPHY_IDX_STALE;
request->alpha2[0] = alpha2[0];
request->alpha2[1] = alpha2[1];
- request->initiator = REGDOM_SET_BY_USER,
+ request->initiator = NL80211_REGDOM_SET_BY_USER,
queue_regulatory_request(request);
@@ -1561,7 +1586,7 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
request->alpha2[0] = alpha2[0];
request->alpha2[1] = alpha2[1];
- request->initiator = REGDOM_SET_BY_DRIVER;
+ request->initiator = NL80211_REGDOM_SET_BY_DRIVER;
queue_regulatory_request(request);
@@ -1710,7 +1735,7 @@ void regulatory_hint_11d(struct wiphy *wiphy,
request->wiphy_idx = get_wiphy_idx(wiphy);
request->alpha2[0] = rd->alpha2[0];
request->alpha2[1] = rd->alpha2[1];
- request->initiator = REGDOM_SET_BY_COUNTRY_IE;
+ request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE;
request->country_ie_checksum = checksum;
request->country_ie_env = env;
@@ -1818,7 +1843,8 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
if (is_intersected_alpha2(rd->alpha2)) {
- if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
+ if (last_request->initiator ==
+ NL80211_REGDOM_SET_BY_COUNTRY_IE) {
struct cfg80211_registered_device *drv;
drv = cfg80211_drv_by_wiphy_idx(
last_request->wiphy_idx);
@@ -1910,7 +1936,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
* rd is non static (it means CRDA was present and was used last)
* and the pending request came in from a country IE
*/
- if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) {
+ if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
/*
* If someone else asked us to change the rd lets only bother
* checking if the alpha2 changes if CRDA was already called
@@ -1942,7 +1968,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
if (!last_request->intersect) {
int r;
- if (last_request->initiator != REGDOM_SET_BY_DRIVER) {
+ if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) {
reset_regdomains();
cfg80211_regdomain = rd;
return 0;
@@ -1966,7 +1992,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
/* Intersection requires a bit more work */
- if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) {
+ if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
if (!intersected_rd)
@@ -1977,7 +2003,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
* However if a driver requested this specific regulatory
* domain we keep it for its private use
*/
- if (last_request->initiator == REGDOM_SET_BY_DRIVER)
+ if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER)
request_wiphy->regd = rd;
else
kfree(rd);
@@ -2067,6 +2093,8 @@ int set_regdom(const struct ieee80211_regdomain *rd)
print_regdomain(cfg80211_regdomain);
+ nl80211_send_reg_change_event(last_request);
+
return r;
}