Merge git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6
[safe/jmp/linux-2.6] / net / wireless / reg.c
index f256dff..87ea60d 100644 (file)
@@ -40,6 +40,7 @@
 #include <net/cfg80211.h>
 #include "core.h"
 #include "reg.h"
+#include "regdb.h"
 #include "nl80211.h"
 
 /* Receipt of information from last regulatory request */
@@ -128,103 +129,6 @@ static char *ieee80211_regdom = "00";
 module_param(ieee80211_regdom, charp, 0444);
 MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
 
-#ifdef CONFIG_WIRELESS_OLD_REGULATORY
-/*
- * 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(const struct ieee80211_regdomain *rd)
-{
-       if (rd == &us_regdom || rd == &jp_regdom || rd == &eu_regdom)
-               return true;
-       return false;
-}
-#else
-static inline bool is_old_static_regdom(const struct ieee80211_regdomain *rd)
-{
-       return false;
-}
-#endif
-
 static void reset_regdomains(void)
 {
        /* avoid freeing static information or freeing something twice */
@@ -234,8 +138,6 @@ static void reset_regdomains(void)
                cfg80211_world_regdom = NULL;
        if (cfg80211_regdomain == &world_regdom)
                cfg80211_regdomain = NULL;
-       if (is_old_static_regdom(cfg80211_regdomain))
-               cfg80211_regdomain = NULL;
 
        kfree(cfg80211_regdomain);
        kfree(cfg80211_world_regdom);
@@ -360,6 +262,98 @@ static bool country_ie_integrity_changes(u32 checksum)
        return false;
 }
 
+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;
+}
+
+#ifdef CONFIG_CFG80211_INTERNAL_REGDB
+struct reg_regdb_search_request {
+       char alpha2[2];
+       struct list_head list;
+};
+
+static LIST_HEAD(reg_regdb_search_list);
+static DEFINE_SPINLOCK(reg_regdb_search_lock);
+
+static void reg_regdb_search(struct work_struct *work)
+{
+       struct reg_regdb_search_request *request;
+       const struct ieee80211_regdomain *curdom, *regdom;
+       int i, r;
+
+       spin_lock(&reg_regdb_search_lock);
+       while (!list_empty(&reg_regdb_search_list)) {
+               request = list_first_entry(&reg_regdb_search_list,
+                                          struct reg_regdb_search_request,
+                                          list);
+               list_del(&request->list);
+
+               for (i=0; i<reg_regdb_size; i++) {
+                       curdom = reg_regdb[i];
+
+                       if (!memcmp(request->alpha2, curdom->alpha2, 2)) {
+                               r = reg_copy_regd(&regdom, curdom);
+                               if (r)
+                                       break;
+                               spin_unlock(&reg_regdb_search_lock);
+                               mutex_lock(&cfg80211_mutex);
+                               set_regdom(regdom);
+                               mutex_unlock(&cfg80211_mutex);
+                               spin_lock(&reg_regdb_search_lock);
+                               break;
+                       }
+               }
+
+               kfree(request);
+       }
+       spin_unlock(&reg_regdb_search_lock);
+}
+
+static DECLARE_WORK(reg_regdb_work, reg_regdb_search);
+
+static void reg_regdb_query(const char *alpha2)
+{
+       struct reg_regdb_search_request *request;
+
+       if (!alpha2)
+               return;
+
+       request = kzalloc(sizeof(struct reg_regdb_search_request), GFP_KERNEL);
+       if (!request)
+               return;
+
+       memcpy(request->alpha2, alpha2, 2);
+
+       spin_lock(&reg_regdb_search_lock);
+       list_add_tail(&request->list, &reg_regdb_search_list);
+       spin_unlock(&reg_regdb_search_lock);
+
+       schedule_work(&reg_regdb_work);
+}
+#else
+static inline void reg_regdb_query(const char *alpha2) {}
+#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
+
 /*
  * This lets us keep regulatory code which is updated on a regulatory
  * basis in userspace.
@@ -379,6 +373,9 @@ static int call_crda(const char *alpha2)
                printk(KERN_INFO "cfg80211: Calling CRDA to update world "
                        "regulatory domain\n");
 
+       /* query internal regulatory database (if it exists) */
+       reg_regdb_query(alpha2);
+
        country_env[8] = alpha2[0];
        country_env[9] = alpha2[1];
 
@@ -1008,7 +1005,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
 
        if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
            request_wiphy && request_wiphy == wiphy &&
-           request_wiphy->strict_regulatory) {
+           request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
                /*
                 * This gaurantees the driver's requested regulatory domain
                 * will always be used as a base for further regulatory
@@ -1051,13 +1048,13 @@ static bool ignore_reg_update(struct wiphy *wiphy,
        if (!last_request)
                return true;
        if (initiator == NL80211_REGDOM_SET_BY_CORE &&
-                 wiphy->custom_regulatory)
+           wiphy->flags & WIPHY_FLAG_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 &&
+       if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd &&
            !is_world_regdom(last_request->alpha2))
                return true;
        return false;
@@ -1093,7 +1090,7 @@ static void handle_reg_beacon(struct wiphy *wiphy,
 
        chan->beacon_found = true;
 
-       if (wiphy->disable_beacon_hints)
+       if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS)
                return;
 
        chan_before.center_freq = chan->center_freq;
@@ -1164,7 +1161,7 @@ static bool reg_is_world_roaming(struct wiphy *wiphy)
                return true;
        if (last_request &&
            last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-           wiphy->custom_regulatory)
+           wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)
                return true;
        return false;
 }
@@ -1367,30 +1364,6 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
 }
 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
@@ -1443,8 +1416,6 @@ static int ignore_request(struct wiphy *wiphy,
                return REG_INTERSECT;
        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))
                                return 0;
                        return -EALREADY;
@@ -1481,8 +1452,7 @@ static int ignore_request(struct wiphy *wiphy,
                                return -EAGAIN;
                }
 
-               if (!is_old_static_regdom(cfg80211_regdomain) &&
-                   !regdom_changes(pending_request->alpha2))
+               if (!regdom_changes(pending_request->alpha2))
                        return -EALREADY;
 
                return 0;
@@ -1591,7 +1561,8 @@ static void reg_process_hint(struct regulatory_request *reg_request)
 
        r = __regulatory_hint(wiphy, reg_request);
        /* This is required so that the orig_* parameters are saved */
-       if (r == -EALREADY && wiphy && wiphy->strict_regulatory)
+       if (r == -EALREADY && wiphy &&
+           wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
                wiphy_update_regulatory(wiphy, reg_request->initiator);
 out:
        mutex_unlock(&reg_mutex);
@@ -1930,7 +1901,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
        const struct ieee80211_freq_range *freq_range = NULL;
        const struct ieee80211_power_rule *power_rule = NULL;
 
-       printk(KERN_INFO "\t(start_freq - end_freq @ bandwidth), "
+       printk(KERN_INFO "    (start_freq - end_freq @ bandwidth), "
                "(max_antenna_gain, max_eirp)\n");
 
        for (i = 0; i < rd->n_reg_rules; i++) {
@@ -1943,7 +1914,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
                 * in certain regions
                 */
                if (power_rule->max_antenna_gain)
-                       printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), "
+                       printk(KERN_INFO "    (%d KHz - %d KHz @ %d KHz), "
                                "(%d mBi, %d mBm)\n",
                                freq_range->start_freq_khz,
                                freq_range->end_freq_khz,
@@ -1951,7 +1922,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
                                power_rule->max_antenna_gain,
                                power_rule->max_eirp);
                else
-                       printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), "
+                       printk(KERN_INFO "    (%d KHz - %d KHz @ %d KHz), "
                                "(N/A, %d mBm)\n",
                                freq_range->start_freq_khz,
                                freq_range->end_freq_khz,
@@ -2063,8 +2034,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
                 * If someone else asked us to change the rd lets only bother
                 * checking if the alpha2 changes if CRDA was already called
                 */
-               if (!is_old_static_regdom(cfg80211_regdomain) &&
-                   !regdom_changes(rd->alpha2))
+               if (!regdom_changes(rd->alpha2))
                        return -EINVAL;
        }
 
@@ -2263,15 +2233,8 @@ int regulatory_init(void)
        spin_lock_init(&reg_requests_lock);
        spin_lock_init(&reg_pending_beacons_lock);
 
-#ifdef CONFIG_WIRELESS_OLD_REGULATORY
-       cfg80211_regdomain = static_regdom(ieee80211_regdom);
-
-       printk(KERN_INFO "cfg80211: Using static regulatory domain info\n");
-       print_regdomain_info(cfg80211_regdomain);
-#else
        cfg80211_regdomain = cfg80211_world_regdom;
 
-#endif
        /* We always try to get an update for the static regdomain */
        err = regulatory_hint_core(cfg80211_regdomain->alpha2);
        if (err) {