cfg80211: clean up regulatory mess
The recent code from Luis is an #ifdef hell and contains lots of
code that's stuffed into the wrong file making a whole bunch of
things needlessly non-static, and besides, what is it doing in
core.c??
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 592b2e3..5fbeab5 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -42,6 +42,18 @@
#include "core.h"
#include "reg.h"
+/* wiphy is set if this request's initiator is REGDOM_SET_BY_DRIVER */
+struct regulatory_request {
+ struct list_head list;
+ struct wiphy *wiphy;
+ int granted;
+ enum reg_set_by initiator;
+ char alpha2[2];
+};
+
+static LIST_HEAD(regulatory_requests);
+DEFINE_MUTEX(cfg80211_reg_mutex);
+
/* To trigger userspace events */
static struct platform_device *reg_pdev;
@@ -51,6 +63,161 @@
MHZ_TO_KHZ(20),
};
+static struct list_head regulatory_requests;
+
+/* Central wireless core regulatory domains, we only need two,
+ * the current one and a world regulatory domain in case we have no
+ * information to give us an alpha2 */
+static struct ieee80211_regdomain *cfg80211_regdomain;
+
+/* We keep a static world regulatory domain in case of the absence of CRDA */
+static const struct ieee80211_regdomain world_regdom = {
+ .n_reg_rules = 1,
+ .alpha2 = "00",
+ .reg_rules = {
+ REG_RULE(2412-10, 2462+10, 40, 6, 20,
+ NL80211_RRF_PASSIVE_SCAN |
+ NL80211_RRF_NO_IBSS),
+ }
+};
+
+static struct ieee80211_regdomain *cfg80211_world_regdom =
+ (struct ieee80211_regdomain *) &world_regdom;
+
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+static char *ieee80211_regdom = "US";
+module_param(ieee80211_regdom, charp, 0444);
+MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
+
+/* We assume 40 MHz bandwidth for the old regulatory work.
+ * We make emphasis we are using the exact same frequencies
+ * as before */
+
+static const struct ieee80211_regdomain us_regdom = {
+ .n_reg_rules = 6,
+ .alpha2 = "US",
+ .reg_rules = {
+ /* IEEE 802.11b/g, channels 1..11 */
+ REG_RULE(2412-10, 2462+10, 40, 6, 27, 0),
+ /* IEEE 802.11a, channel 36 */
+ REG_RULE(5180-10, 5180+10, 40, 6, 23, 0),
+ /* IEEE 802.11a, channel 40 */
+ REG_RULE(5200-10, 5200+10, 40, 6, 23, 0),
+ /* IEEE 802.11a, channel 44 */
+ REG_RULE(5220-10, 5220+10, 40, 6, 23, 0),
+ /* IEEE 802.11a, channels 48..64 */
+ REG_RULE(5240-10, 5320+10, 40, 6, 23, 0),
+ /* IEEE 802.11a, channels 149..165, outdoor */
+ REG_RULE(5745-10, 5825+10, 40, 6, 30, 0),
+ }
+};
+
+static const struct ieee80211_regdomain jp_regdom = {
+ .n_reg_rules = 3,
+ .alpha2 = "JP",
+ .reg_rules = {
+ /* IEEE 802.11b/g, channels 1..14 */
+ REG_RULE(2412-10, 2484+10, 40, 6, 20, 0),
+ /* IEEE 802.11a, channels 34..48 */
+ REG_RULE(5170-10, 5240+10, 40, 6, 20,
+ NL80211_RRF_PASSIVE_SCAN),
+ /* IEEE 802.11a, channels 52..64 */
+ REG_RULE(5260-10, 5320+10, 40, 6, 20,
+ NL80211_RRF_NO_IBSS |
+ NL80211_RRF_DFS),
+ }
+};
+
+static const struct ieee80211_regdomain eu_regdom = {
+ .n_reg_rules = 6,
+ /* This alpha2 is bogus, we leave it here just for stupid
+ * backward compatibility */
+ .alpha2 = "EU",
+ .reg_rules = {
+ /* IEEE 802.11b/g, channels 1..13 */
+ REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
+ /* IEEE 802.11a, channel 36 */
+ REG_RULE(5180-10, 5180+10, 40, 6, 23,
+ NL80211_RRF_PASSIVE_SCAN),
+ /* IEEE 802.11a, channel 40 */
+ REG_RULE(5200-10, 5200+10, 40, 6, 23,
+ NL80211_RRF_PASSIVE_SCAN),
+ /* IEEE 802.11a, channel 44 */
+ REG_RULE(5220-10, 5220+10, 40, 6, 23,
+ NL80211_RRF_PASSIVE_SCAN),
+ /* IEEE 802.11a, channels 48..64 */
+ REG_RULE(5240-10, 5320+10, 40, 6, 20,
+ NL80211_RRF_NO_IBSS |
+ NL80211_RRF_DFS),
+ /* IEEE 802.11a, channels 100..140 */
+ REG_RULE(5500-10, 5700+10, 40, 6, 30,
+ NL80211_RRF_NO_IBSS |
+ NL80211_RRF_DFS),
+ }
+};
+
+static const struct ieee80211_regdomain *static_regdom(char *alpha2)
+{
+ if (alpha2[0] == 'U' && alpha2[1] == 'S')
+ return &us_regdom;
+ if (alpha2[0] == 'J' && alpha2[1] == 'P')
+ return &jp_regdom;
+ if (alpha2[0] == 'E' && alpha2[1] == 'U')
+ return &eu_regdom;
+ /* Default, as per the old rules */
+ return &us_regdom;
+}
+
+static bool is_old_static_regdom(struct ieee80211_regdomain *rd)
+{
+ if (rd == &us_regdom || rd == &jp_regdom || rd == &eu_regdom)
+ return true;
+ return false;
+}
+
+/* The old crap never deals with a world regulatory domain, it only
+ * deals with the static regulatory domain passed and if possible
+ * an updated "US" or "JP" regulatory domain. We do however store the
+ * old static regulatory domain in cfg80211_world_regdom for convenience
+ * of use here */
+static void reset_regdomains_static(void)
+{
+ if (!is_old_static_regdom(cfg80211_regdomain))
+ kfree(cfg80211_regdomain);
+ /* This is setting the regdom to the old static regdom */
+ cfg80211_regdomain =
+ (struct ieee80211_regdomain *) cfg80211_world_regdom;
+}
+#else
+static void reset_regdomains(void)
+{
+ if (cfg80211_world_regdom && cfg80211_world_regdom != &world_regdom) {
+ if (cfg80211_world_regdom == cfg80211_regdomain) {
+ kfree(cfg80211_regdomain);
+ } else {
+ kfree(cfg80211_world_regdom);
+ kfree(cfg80211_regdomain);
+ }
+ } else if (cfg80211_regdomain && cfg80211_regdomain != &world_regdom)
+ kfree(cfg80211_regdomain);
+
+ cfg80211_world_regdom = (struct ieee80211_regdomain *) &world_regdom;
+ cfg80211_regdomain = NULL;
+}
+
+/* Dynamic world regulatory domain requested by the wireless
+ * core upon initialization */
+static void update_world_regdomain(struct ieee80211_regdomain *rd)
+{
+ BUG_ON(list_empty(®ulatory_requests));
+
+ reset_regdomains();
+
+ cfg80211_world_regdom = rd;
+ cfg80211_regdomain = rd;
+}
+#endif
+
bool is_world_regdom(char *alpha2)
{
if (!alpha2)
@@ -555,58 +722,6 @@
print_rd_rules(rd);
}
-#ifdef CONFIG_WIRELESS_OLD_REGULATORY
-
-static bool is_old_static_regdom(struct ieee80211_regdomain *rd)
-{
- if (rd == &us_regdom || rd == &jp_regdom || rd == &eu_regdom)
- return true;
- return false;
-}
-
-/* The old crap never deals with a world regulatory domain, it only
- * deals with the static regulatory domain passed and if possible
- * an updated "US" or "JP" regulatory domain. We do however store the
- * old static regulatory domain in cfg80211_world_regdom for convenience
- * of use here */
-static void reset_regdomains_static(void)
-{
- if (!is_old_static_regdom(cfg80211_regdomain))
- kfree(cfg80211_regdomain);
- /* This is setting the regdom to the old static regdom */
- cfg80211_regdomain =
- (struct ieee80211_regdomain *) cfg80211_world_regdom;
-}
-#else
-static void reset_regdomains(void)
-{
- if (cfg80211_world_regdom && cfg80211_world_regdom != &world_regdom) {
- if (cfg80211_world_regdom == cfg80211_regdomain) {
- kfree(cfg80211_regdomain);
- } else {
- kfree(cfg80211_world_regdom);
- kfree(cfg80211_regdomain);
- }
- } else if (cfg80211_regdomain && cfg80211_regdomain != &world_regdom)
- kfree(cfg80211_regdomain);
-
- cfg80211_world_regdom = (struct ieee80211_regdomain *) &world_regdom;
- cfg80211_regdomain = NULL;
-}
-
-/* Dynamic world regulatory domain requested by the wireless
- * core upon initialization */
-static void update_world_regdomain(struct ieee80211_regdomain *rd)
-{
- BUG_ON(list_empty(®ulatory_requests));
-
- reset_regdomains();
-
- cfg80211_world_regdom = rd;
- cfg80211_regdomain = rd;
-}
-#endif
-
static int __set_regdom(struct ieee80211_regdomain *rd)
{
struct regulatory_request *request = NULL;
@@ -615,7 +730,7 @@
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
/* We ignore the world regdom with the old static regdomains setup
- * as there is no point to it with satic regulatory definitions :(
+ * as there is no point to it with static regulatory definitions :(
* Don't worry this shit will be removed soon... */
if (is_world_regdom(rd->alpha2))
return -EINVAL;
@@ -735,25 +850,58 @@
int regulatory_init(void)
{
+ int err;
+
reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0);
if (IS_ERR(reg_pdev))
return PTR_ERR(reg_pdev);
+
+#ifdef CONFIG_WIRELESS_OLD_REGULATORY
+ cfg80211_regdomain =
+ (struct ieee80211_regdomain *) static_regdom(ieee80211_regdom);
+ /* Used during reset_regdomains_static() */
+ cfg80211_world_regdom = cfg80211_regdomain;
+
+ printk(KERN_INFO "cfg80211: Using old static regulatory domain:\n");
+ print_regdomain_info(cfg80211_regdomain);
+ /* The old code still requests for a new regdomain and if
+ * you have CRDA you get it updated, otherwise you get
+ * stuck with the static values. We ignore "EU" code as
+ * that is not a valid ISO / IEC 3166 alpha2 */
+ if (ieee80211_regdom[0] != 'E' && ieee80211_regdom[1] != 'U')
+ err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE,
+ ieee80211_regdom, NULL);
+#else
+ cfg80211_regdomain =
+ (struct ieee80211_regdomain *) cfg80211_world_regdom;
+
+ err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", NULL);
+ if (err)
+ printk(KERN_ERR "cfg80211: calling CRDA failed - "
+ "unable to update world regulatory domain, "
+ "using static definition\n");
+#endif
+
return 0;
}
void regulatory_exit(void)
{
struct regulatory_request *req, *req_tmp;
+
mutex_lock(&cfg80211_drv_mutex);
+
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
reset_regdomains_static();
#else
reset_regdomains();
#endif
+
list_for_each_entry_safe(req, req_tmp, ®ulatory_requests, list) {
list_del(&req->list);
kfree(req);
}
platform_device_unregister(reg_pdev);
+
mutex_unlock(&cfg80211_drv_mutex);
}