]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - net/wireless/reg.c
cfg80211: reg: search built-in database directly
[mirror_ubuntu-bionic-kernel.git] / net / wireless / reg.c
index b144485946f2e5ce2ec6411cd52462fa278b185e..bc29c9a754a557b05d604a90b841a8eebe3b3394 100644 (file)
@@ -262,7 +262,7 @@ static const struct ieee80211_regdomain world_regdom = {
                REG_RULE(5745-10, 5825+10, 80, 6, 20,
                        NL80211_RRF_NO_IR),
 
-               /* IEEE 802.11ad (60gHz), channels 1..3 */
+               /* IEEE 802.11ad (60GHz), channels 1..3 */
                REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0),
        }
 };
@@ -453,68 +453,70 @@ reg_copy_regd(const struct ieee80211_regdomain *src_regd)
 }
 
 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
-struct reg_regdb_search_request {
-       char alpha2[2];
+struct reg_regdb_apply_request {
        struct list_head list;
+       const struct ieee80211_regdomain *regdom;
 };
 
-static LIST_HEAD(reg_regdb_search_list);
-static DEFINE_MUTEX(reg_regdb_search_mutex);
+static LIST_HEAD(reg_regdb_apply_list);
+static DEFINE_MUTEX(reg_regdb_apply_mutex);
 
-static void reg_regdb_search(struct work_struct *work)
+static void reg_regdb_apply(struct work_struct *work)
 {
-       struct reg_regdb_search_request *request;
-       const struct ieee80211_regdomain *curdom, *regdom = NULL;
-       int i;
+       struct reg_regdb_apply_request *request;
 
        rtnl_lock();
 
-       mutex_lock(&reg_regdb_search_mutex);
-       while (!list_empty(&reg_regdb_search_list)) {
-               request = list_first_entry(&reg_regdb_search_list,
-                                          struct reg_regdb_search_request,
+       mutex_lock(&reg_regdb_apply_mutex);
+       while (!list_empty(&reg_regdb_apply_list)) {
+               request = list_first_entry(&reg_regdb_apply_list,
+                                          struct reg_regdb_apply_request,
                                           list);
                list_del(&request->list);
 
-               for (i = 0; i < reg_regdb_size; i++) {
-                       curdom = reg_regdb[i];
-
-                       if (alpha2_equal(request->alpha2, curdom->alpha2)) {
-                               regdom = reg_copy_regd(curdom);
-                               break;
-                       }
-               }
-
+               set_regdom(request->regdom, REGD_SOURCE_INTERNAL_DB);
                kfree(request);
        }
-       mutex_unlock(&reg_regdb_search_mutex);
-
-       if (!IS_ERR_OR_NULL(regdom))
-               set_regdom(regdom, REGD_SOURCE_INTERNAL_DB);
+       mutex_unlock(&reg_regdb_apply_mutex);
 
        rtnl_unlock();
 }
 
-static DECLARE_WORK(reg_regdb_work, reg_regdb_search);
+static DECLARE_WORK(reg_regdb_work, reg_regdb_apply);
 
-static void reg_regdb_query(const char *alpha2)
+static int reg_regdb_query(const char *alpha2)
 {
-       struct reg_regdb_search_request *request;
+       const struct ieee80211_regdomain *regdom = NULL;
+       struct reg_regdb_apply_request *request;
+       unsigned int i;
 
-       if (!alpha2)
-               return;
+       for (i = 0; i < reg_regdb_size; i++) {
+               if (alpha2_equal(alpha2, reg_regdb[i]->alpha2)) {
+                       regdom = reg_regdb[i];
+                       break;
+               }
+       }
 
-       request = kzalloc(sizeof(struct reg_regdb_search_request), GFP_KERNEL);
+       if (!regdom)
+               return -ENODATA;
+
+       request = kzalloc(sizeof(struct reg_regdb_apply_request), GFP_KERNEL);
        if (!request)
-               return;
+               return -ENOMEM;
 
-       memcpy(request->alpha2, alpha2, 2);
+       request->regdom = reg_copy_regd(regdom);
+       if (IS_ERR_OR_NULL(request->regdom)) {
+               kfree(request);
+               return -ENOMEM;
+       }
 
-       mutex_lock(&reg_regdb_search_mutex);
-       list_add_tail(&request->list, &reg_regdb_search_list);
-       mutex_unlock(&reg_regdb_search_mutex);
+       mutex_lock(&reg_regdb_apply_mutex);
+       list_add_tail(&request->list, &reg_regdb_apply_list);
+       mutex_unlock(&reg_regdb_apply_mutex);
 
        schedule_work(&reg_regdb_work);
+
+       return 0;
 }
 
 /* Feel free to add any other sanity checks here */
@@ -525,7 +527,10 @@ static void reg_regdb_size_check(void)
 }
 #else
 static inline void reg_regdb_size_check(void) {}
-static inline void reg_regdb_query(const char *alpha2) {}
+static inline int reg_regdb_query(const char *alpha2)
+{
+       return -ENODATA;
+}
 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
 
 /*
@@ -536,13 +541,11 @@ static int call_crda(const char *alpha2)
 {
        char country[12];
        char *env[] = { country, NULL };
+       int ret;
 
        snprintf(country, sizeof(country), "COUNTRY=%c%c",
                 alpha2[0], alpha2[1]);
 
-       /* query internal regulatory database (if it exists) */
-       reg_regdb_query(alpha2);
-
        if (reg_crda_timeouts > REG_MAX_CRDA_TIMEOUTS) {
                pr_debug("Exceeded CRDA call max attempts. Not calling CRDA\n");
                return -EINVAL;
@@ -554,18 +557,25 @@ static int call_crda(const char *alpha2)
        else
                pr_debug("Calling CRDA to update world regulatory domain\n");
 
-       return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env);
+       ret = kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env);
+       if (ret)
+               return ret;
+
+       queue_delayed_work(system_power_efficient_wq,
+                          &reg_timeout, msecs_to_jiffies(3142));
+       return 0;
 }
 
-static enum reg_request_treatment
-reg_call_crda(struct regulatory_request *request)
+static bool reg_query_database(struct regulatory_request *request)
 {
-       if (call_crda(request->alpha2))
-               return REG_REQ_IGNORE;
+       /* query internal regulatory database (if it exists) */
+       if (reg_regdb_query(request->alpha2) == 0)
+               return true;
 
-       queue_delayed_work(system_power_efficient_wq,
-                          &reg_timeout, msecs_to_jiffies(3142));
-       return REG_REQ_OK;
+       if (call_crda(request->alpha2) == 0)
+               return true;
+
+       return false;
 }
 
 bool reg_is_valid_request(const char *alpha2)
@@ -1040,8 +1050,8 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
        return ERR_PTR(-EINVAL);
 }
 
-const struct ieee80211_reg_rule *__freq_reg_info(struct wiphy *wiphy,
-                                                u32 center_freq, u32 min_bw)
+static const struct ieee80211_reg_rule *
+__freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
 {
        const struct ieee80211_regdomain *regd = reg_get_regdomain(wiphy);
        const struct ieee80211_reg_rule *reg_rule = NULL;
@@ -1858,19 +1868,14 @@ static void reg_set_request_processed(void)
  *
  * The wireless subsystem can use this function to process
  * a regulatory request issued by the regulatory core.
- *
- * Returns one of the different reg request treatment values.
  */
-static enum reg_request_treatment
-reg_process_hint_core(struct regulatory_request *core_request)
+static void reg_process_hint_core(struct regulatory_request *core_request)
 {
-
-       core_request->intersect = false;
-       core_request->processed = false;
-
-       reg_update_last_request(core_request);
-
-       return reg_call_crda(core_request);
+       if (reg_query_database(core_request)) {
+               core_request->intersect = false;
+               core_request->processed = false;
+               reg_update_last_request(core_request);
+       }
 }
 
 static enum reg_request_treatment
@@ -1915,11 +1920,8 @@ __reg_process_hint_user(struct regulatory_request *user_request)
  *
  * The wireless subsystem can use this function to process
  * a regulatory request initiated by userspace.
- *
- * Returns one of the different reg request treatment values.
  */
-static enum reg_request_treatment
-reg_process_hint_user(struct regulatory_request *user_request)
+static void reg_process_hint_user(struct regulatory_request *user_request)
 {
        enum reg_request_treatment treatment;
 
@@ -1927,18 +1929,19 @@ reg_process_hint_user(struct regulatory_request *user_request)
        if (treatment == REG_REQ_IGNORE ||
            treatment == REG_REQ_ALREADY_SET) {
                reg_free_request(user_request);
-               return treatment;
+               return;
        }
 
        user_request->intersect = treatment == REG_REQ_INTERSECT;
        user_request->processed = false;
 
-       reg_update_last_request(user_request);
-
-       user_alpha2[0] = user_request->alpha2[0];
-       user_alpha2[1] = user_request->alpha2[1];
-
-       return reg_call_crda(user_request);
+       if (reg_query_database(user_request)) {
+               reg_update_last_request(user_request);
+               user_alpha2[0] = user_request->alpha2[0];
+               user_alpha2[1] = user_request->alpha2[1];
+       } else {
+               reg_free_request(user_request);
+       }
 }
 
 static enum reg_request_treatment
@@ -2006,8 +2009,6 @@ reg_process_hint_driver(struct wiphy *wiphy,
        driver_request->intersect = treatment == REG_REQ_INTERSECT;
        driver_request->processed = false;
 
-       reg_update_last_request(driver_request);
-
        /*
         * Since CRDA will not be called in this case as we already
         * have applied the requested regulatory domain before we just
@@ -2015,11 +2016,17 @@ reg_process_hint_driver(struct wiphy *wiphy,
         */
        if (treatment == REG_REQ_ALREADY_SET) {
                nl80211_send_reg_change_event(driver_request);
+               reg_update_last_request(driver_request);
                reg_set_request_processed();
                return treatment;
        }
 
-       return reg_call_crda(driver_request);
+       if (reg_query_database(driver_request))
+               reg_update_last_request(driver_request);
+       else
+               reg_free_request(driver_request);
+
+       return REG_REQ_OK;
 }
 
 static enum reg_request_treatment
@@ -2102,9 +2109,12 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
        country_ie_request->intersect = false;
        country_ie_request->processed = false;
 
-       reg_update_last_request(country_ie_request);
+       if (reg_query_database(country_ie_request))
+               reg_update_last_request(country_ie_request);
+       else
+               reg_free_request(country_ie_request);
 
-       return reg_call_crda(country_ie_request);
+       return REG_REQ_OK;
 }
 
 /* This processes *all* regulatory hints */
@@ -2625,7 +2635,7 @@ static void restore_regulatory_settings(bool reset_user)
         * settings, user regulatory settings takes precedence.
         */
        if (is_an_alpha2(alpha2))
-               regulatory_hint_user(user_alpha2, NL80211_USER_REG_HINT_USER);
+               regulatory_hint_user(alpha2, NL80211_USER_REG_HINT_USER);
 
        spin_lock(&reg_requests_lock);
        list_splice_tail_init(&tmp_reg_req_list, &reg_requests_list);