aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2009-12-18 17:59:01 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-12-21 18:56:10 -0500
commit3b377ea9d4efc94dc52fe41b4dfdb463635ab298 (patch)
tree76724e77913096c03f6b216573d4a24ce13fe7c3 /net/wireless/reg.c
parent59d9cb071d6209f2e8df2d16228cfdc7bab1f2d1 (diff)
wireless: support internal statically compiled regulatory database
This patch provides infrastructure for machine translation of the regulatory rules database used by CRDA into a C data structure. It includes code for searching that database as an alternative to dynamic regulatory rules updates via CRDA. Most people should use CRDA instead of this infrastructure, but it provides a better alternative than the WIRELESS_OLD_REGULATORY infrastructure (which can now be removed). Signed-off-by: John W. Linville <linville@tuxdriver.com>
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 c01470e7de15..65f86264f7bb 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 */
@@ -360,6 +361,98 @@ static bool country_ie_integrity_changes(u32 checksum)
360 return false; 361 return false;
361} 362}
362 363
364static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
365 const struct ieee80211_regdomain *src_regd)
366{
367 struct ieee80211_regdomain *regd;
368 int size_of_regd = 0;
369 unsigned int i;
370
371 size_of_regd = sizeof(struct ieee80211_regdomain) +
372 ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
373
374 regd = kzalloc(size_of_regd, GFP_KERNEL);
375 if (!regd)
376 return -ENOMEM;
377
378 memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
379
380 for (i = 0; i < src_regd->n_reg_rules; i++)
381 memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i],
382 sizeof(struct ieee80211_reg_rule));
383
384 *dst_regd = regd;
385 return 0;
386}
387
388#ifdef CONFIG_CFG80211_INTERNAL_REGDB
389struct reg_regdb_search_request {
390 char alpha2[2];
391 struct list_head list;
392};
393
394static LIST_HEAD(reg_regdb_search_list);
395static DEFINE_SPINLOCK(reg_regdb_search_lock);
396
397static void reg_regdb_search(struct work_struct *work)
398{
399 struct reg_regdb_search_request *request;
400 const struct ieee80211_regdomain *curdom, *regdom;
401 int i, r;
402
403 spin_lock(&reg_regdb_search_lock);
404 while (!list_empty(&reg_regdb_search_list)) {
405 request = list_first_entry(&reg_regdb_search_list,
406 struct reg_regdb_search_request,
407 list);
408 list_del(&request->list);
409
410 for (i=0; i<reg_regdb_size; i++) {
411 curdom = reg_regdb[i];
412
413 if (!memcmp(request->alpha2, curdom->alpha2, 2)) {
414 r = reg_copy_regd(&regdom, curdom);
415 if (r)
416 break;
417 spin_unlock(&reg_regdb_search_lock);
418 mutex_lock(&cfg80211_mutex);
419 set_regdom(regdom);
420 mutex_unlock(&cfg80211_mutex);
421 spin_lock(&reg_regdb_search_lock);
422 break;
423 }
424 }
425
426 kfree(request);
427 }
428 spin_unlock(&reg_regdb_search_lock);
429}
430
431static DECLARE_WORK(reg_regdb_work, reg_regdb_search);
432
433static void reg_regdb_query(const char *alpha2)
434{
435 struct reg_regdb_search_request *request;
436
437 if (!alpha2)
438 return;
439
440 request = kzalloc(sizeof(struct reg_regdb_search_request), GFP_KERNEL);
441 if (!request)
442 return;
443
444 memcpy(request->alpha2, alpha2, 2);
445
446 spin_lock(&reg_regdb_search_lock);
447 list_add_tail(&request->list, &reg_regdb_search_list);
448 spin_unlock(&reg_regdb_search_lock);
449
450 schedule_work(&reg_regdb_work);
451}
452#else
453static inline void reg_regdb_query(const char *alpha2) {}
454#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
455
363/* 456/*
364 * This lets us keep regulatory code which is updated on a regulatory 457 * This lets us keep regulatory code which is updated on a regulatory
365 * basis in userspace. 458 * basis in userspace.
@@ -379,6 +472,9 @@ static int call_crda(const char *alpha2)
379 printk(KERN_INFO "cfg80211: Calling CRDA to update world " 472 printk(KERN_INFO "cfg80211: Calling CRDA to update world "
380 "regulatory domain\n"); 473 "regulatory domain\n");
381 474
475 /* query internal regulatory database (if it exists) */
476 reg_regdb_query(alpha2);
477
382 country_env[8] = alpha2[0]; 478 country_env[8] = alpha2[0];
383 country_env[9] = alpha2[1]; 479 country_env[9] = alpha2[1];
384 480
@@ -1367,30 +1463,6 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
1367} 1463}
1368EXPORT_SYMBOL(wiphy_apply_custom_regulatory); 1464EXPORT_SYMBOL(wiphy_apply_custom_regulatory);
1369 1465
1370static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
1371 const struct ieee80211_regdomain *src_regd)
1372{
1373 struct ieee80211_regdomain *regd;
1374 int size_of_regd = 0;
1375 unsigned int i;
1376
1377 size_of_regd = sizeof(struct ieee80211_regdomain) +
1378 ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
1379
1380 regd = kzalloc(size_of_regd, GFP_KERNEL);
1381 if (!regd)
1382 return -ENOMEM;
1383
1384 memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
1385
1386 for (i = 0; i < src_regd->n_reg_rules; i++)
1387 memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i],
1388 sizeof(struct ieee80211_reg_rule));
1389
1390 *dst_regd = regd;
1391 return 0;
1392}
1393
1394/* 1466/*
1395 * Return value which can be used by ignore_request() to indicate 1467 * Return value which can be used by ignore_request() to indicate
1396 * it has been determined we should intersect two regulatory domains 1468 * it has been determined we should intersect two regulatory domains