Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[pandora-kernel.git] / net / wireless / reg.c
index 77e9267..3302c56 100644 (file)
 #define REG_DBG_PRINT(args...)
 #endif
 
+static struct regulatory_request core_request_world = {
+       .initiator = NL80211_REGDOM_SET_BY_CORE,
+       .alpha2[0] = '0',
+       .alpha2[1] = '0',
+       .intersect = false,
+       .processed = true,
+       .country_ie_env = ENVIRON_ANY,
+};
+
 /* Receipt of information from last regulatory request */
-static struct regulatory_request *last_request;
+static struct regulatory_request *last_request = &core_request_world;
 
 /* To trigger userspace events */
 static struct platform_device *reg_pdev;
@@ -150,7 +159,7 @@ static char user_alpha2[2];
 module_param(ieee80211_regdom, charp, 0444);
 MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
 
-static void reset_regdomains(void)
+static void reset_regdomains(bool full_reset)
 {
        /* avoid freeing static information or freeing something twice */
        if (cfg80211_regdomain == cfg80211_world_regdom)
@@ -165,6 +174,13 @@ static void reset_regdomains(void)
 
        cfg80211_world_regdom = &world_regdom;
        cfg80211_regdomain = NULL;
+
+       if (!full_reset)
+               return;
+
+       if (last_request != &core_request_world)
+               kfree(last_request);
+       last_request = &core_request_world;
 }
 
 /*
@@ -175,7 +191,7 @@ static void update_world_regdomain(const struct ieee80211_regdomain *rd)
 {
        BUG_ON(!last_request);
 
-       reset_regdomains();
+       reset_regdomains(false);
 
        cfg80211_world_regdom = rd;
        cfg80211_regdomain = rd;
@@ -1407,7 +1423,8 @@ static int __regulatory_hint(struct wiphy *wiphy,
        }
 
 new_request:
-       kfree(last_request);
+       if (last_request != &core_request_world)
+               kfree(last_request);
 
        last_request = pending_request;
        last_request->intersect = intersect;
@@ -1577,9 +1594,6 @@ static int regulatory_hint_core(const char *alpha2)
 {
        struct regulatory_request *request;
 
-       kfree(last_request);
-       last_request = NULL;
-
        request = kzalloc(sizeof(struct regulatory_request),
                          GFP_KERNEL);
        if (!request)
@@ -1777,7 +1791,7 @@ static void restore_regulatory_settings(bool reset_user)
        mutex_lock(&cfg80211_mutex);
        mutex_lock(&reg_mutex);
 
-       reset_regdomains();
+       reset_regdomains(true);
        restore_alpha2(alpha2, reset_user);
 
        /*
@@ -2037,8 +2051,10 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
        }
 
        request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
-       if (!request_wiphy) {
-               reg_set_request_processed();
+       if (!request_wiphy &&
+           (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
+            last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
+               schedule_delayed_work(&reg_timeout, 0);
                return -ENODEV;
        }
 
@@ -2046,7 +2062,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
                int r;
 
                if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) {
-                       reset_regdomains();
+                       reset_regdomains(false);
                        cfg80211_regdomain = rd;
                        return 0;
                }
@@ -2067,7 +2083,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
                if (r)
                        return r;
 
-               reset_regdomains();
+               reset_regdomains(false);
                cfg80211_regdomain = rd;
                return 0;
        }
@@ -2092,7 +2108,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 
                rd = NULL;
 
-               reset_regdomains();
+               reset_regdomains(false);
                cfg80211_regdomain = intersected_rd;
 
                return 0;
@@ -2112,7 +2128,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
        kfree(rd);
        rd = NULL;
 
-       reset_regdomains();
+       reset_regdomains(false);
        cfg80211_regdomain = intersected_rd;
 
        return 0;
@@ -2265,11 +2281,8 @@ void /* __init_or_exit */ regulatory_exit(void)
        mutex_lock(&cfg80211_mutex);
        mutex_lock(&reg_mutex);
 
-       reset_regdomains();
-
-       kfree(last_request);
+       reset_regdomains(true);
 
-       last_request = NULL;
        dev_set_uevent_suppress(&reg_pdev->dev, true);
 
        platform_device_unregister(reg_pdev);