diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/reg.c | 102 |
1 files changed, 58 insertions, 44 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index ed3330579dc0..bc29c9a754a5 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -453,65 +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(®_regdb_search_mutex); - while (!list_empty(®_regdb_search_list)) { - request = list_first_entry(®_regdb_search_list, - struct reg_regdb_search_request, + mutex_lock(®_regdb_apply_mutex); + while (!list_empty(®_regdb_apply_list)) { + request = list_first_entry(®_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(®_regdb_search_mutex); - - if (!IS_ERR_OR_NULL(regdom)) - set_regdom(regdom, REGD_SOURCE_INTERNAL_DB); + mutex_unlock(®_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; + + for (i = 0; i < reg_regdb_size; i++) { + if (alpha2_equal(alpha2, reg_regdb[i]->alpha2)) { + regdom = reg_regdb[i]; + break; + } + } + + if (!regdom) + return -ENODATA; - request = kzalloc(sizeof(struct reg_regdb_search_request), GFP_KERNEL); + 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(®_regdb_search_mutex); - list_add_tail(&request->list, ®_regdb_search_list); - mutex_unlock(®_regdb_search_mutex); + mutex_lock(®_regdb_apply_mutex); + list_add_tail(&request->list, ®_regdb_apply_list); + mutex_unlock(®_regdb_apply_mutex); schedule_work(®_regdb_work); + + return 0; } /* Feel free to add any other sanity checks here */ @@ -522,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 */ /* @@ -533,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; @@ -551,17 +557,25 @@ static int call_crda(const char *alpha2) else pr_debug("Calling CRDA to update world regulatory domain\n"); - return kobject_uevent_env(®_pdev->dev.kobj, KOBJ_CHANGE, env); + ret = kobject_uevent_env(®_pdev->dev.kobj, KOBJ_CHANGE, env); + if (ret) + return ret; + + queue_delayed_work(system_power_efficient_wq, + ®_timeout, msecs_to_jiffies(3142)); + return 0; } static bool reg_query_database(struct regulatory_request *request) { - if (call_crda(request->alpha2)) - return false; + /* query internal regulatory database (if it exists) */ + if (reg_regdb_query(request->alpha2) == 0) + return true; - queue_delayed_work(system_power_efficient_wq, - ®_timeout, msecs_to_jiffies(3142)); - return true; + if (call_crda(request->alpha2) == 0) + return true; + + return false; } bool reg_is_valid_request(const char *alpha2) |