aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r--net/wireless/reg.c120
1 files changed, 96 insertions, 24 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index baa898add287..dc13c3ffeca6 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -40,6 +40,7 @@
40#include <net/cfg80211.h> 40#include <net/cfg80211.h>
41#include "core.h" 41#include "core.h"
42#include "reg.h" 42#include "reg.h"
43#include "regdb.h"
43#include "nl80211.h" 44#include "nl80211.h"
44 45
45/* Receipt of information from last regulatory request */ 46/* Receipt of information from last regulatory request */
@@ -335,6 +336,98 @@ static bool country_ie_integrity_changes(u32 checksum)
335 return false; 336 return false;
336} 337}
337 338
339static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
340 const struct ieee80211_regdomain *src_regd)
341{
342 struct ieee80211_regdomain *regd;
343 int size_of_regd = 0;
344 unsigned int i;
345
346 size_of_regd = sizeof(struct ieee80211_regdomain) +
347 ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
348
349 regd = kzalloc(size_of_regd, GFP_KERNEL);
350 if (!regd)
351 return -ENOMEM;
352
353 memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
354
355 for (i = 0; i < src_regd->n_reg_rules; i++)
356 memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i],
357 sizeof(struct ieee80211_reg_rule));
358
359 *dst_regd = regd;
360 return 0;
361}
362
363#ifdef CONFIG_CFG80211_INTERNAL_REGDB
364struct reg_regdb_search_request {
365 char alpha2[2];
366 struct list_head list;
367};
368
369static LIST_HEAD(reg_regdb_search_list);
370static DEFINE_SPINLOCK(reg_regdb_search_lock);
371
372static void reg_regdb_search(struct work_struct *work)
373{
374 struct reg_regdb_search_request *request;
375 const struct ieee80211_regdomain *curdom, *regdom;
376 int i, r;
377
378 spin_lock(&reg_regdb_search_lock);
379 while (!list_empty(&reg_regdb_search_list)) {
380 request = list_first_entry(&reg_regdb_search_list,
381 struct reg_regdb_search_request,
382 list);
383 list_del(&request->list);
384
385 for (i=0; i<reg_regdb_size; i++) {
386 curdom = reg_regdb[i];
387
388 if (!memcmp(request->alpha2, curdom->alpha2, 2)) {
389 r = reg_copy_regd(&regdom, curdom);
390 if (r)
391 break;
392 spin_unlock(&reg_regdb_search_lock);
393 mutex_lock(&cfg80211_mutex);
394 set_regdom(regdom);
395 mutex_unlock(&cfg80211_mutex);
396 spin_lock(&reg_regdb_search_lock);
397 break;
398 }
399 }
400
401 kfree(request);
402 }
403 spin_unlock(&reg_regdb_search_lock);
404}
405
406static DECLARE_WORK(reg_regdb_work, reg_regdb_search);
407
408static void reg_regdb_query(const char *alpha2)
409{
410 struct reg_regdb_search_request *request;
411
412 if (!alpha2)
413 return;
414
415 request = kzalloc(sizeof(struct reg_regdb_search_request), GFP_KERNEL);
416 if (!request)
417 return;
418
419 memcpy(request->alpha2, alpha2, 2);
420
421 spin_lock(&reg_regdb_search_lock);
422 list_add_tail(&request->list, &reg_regdb_search_list);
423 spin_unlock(&reg_regdb_search_lock);
424
425 schedule_work(&reg_regdb_work);
426}
427#else
428static inline void reg_regdb_query(const char *alpha2) {}
429#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
430
338/* 431/*
339 * This lets us keep regulatory code which is updated on a regulatory 432 * This lets us keep regulatory code which is updated on a regulatory
340 * basis in userspace. 433 * basis in userspace.
@@ -354,6 +447,9 @@ static int call_crda(const char *alpha2)
354 printk(KERN_INFO "cfg80211: Calling CRDA to update world " 447 printk(KERN_INFO "cfg80211: Calling CRDA to update world "
355 "regulatory domain\n"); 448 "regulatory domain\n");
356 449
450 /* query internal regulatory database (if it exists) */
451 reg_regdb_query(alpha2);
452
357 country_env[8] = alpha2[0]; 453 country_env[8] = alpha2[0];
358 country_env[9] = alpha2[1]; 454 country_env[9] = alpha2[1];
359 455
@@ -1342,30 +1438,6 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
1342} 1438}
1343EXPORT_SYMBOL(wiphy_apply_custom_regulatory); 1439EXPORT_SYMBOL(wiphy_apply_custom_regulatory);
1344 1440
1345static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
1346 const struct ieee80211_regdomain *src_regd)
1347{
1348 struct ieee80211_regdomain *regd;
1349 int size_of_regd = 0;
1350 unsigned int i;
1351
1352 size_of_regd = sizeof(struct ieee80211_regdomain) +
1353 ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
1354
1355 regd = kzalloc(size_of_regd, GFP_KERNEL);
1356 if (!regd)
1357 return -ENOMEM;
1358
1359 memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
1360
1361 for (i = 0; i < src_regd->n_reg_rules; i++)
1362 memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i],
1363 sizeof(struct ieee80211_reg_rule));
1364
1365 *dst_regd = regd;
1366 return 0;
1367}
1368
1369/* 1441/*
1370 * Return value which can be used by ignore_request() to indicate 1442 * Return value which can be used by ignore_request() to indicate
1371 * it has been determined we should intersect two regulatory domains 1443 * it has been determined we should intersect two regulatory domains