|
@@ -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)
|