diff options
author | John W. Linville <linville@tuxdriver.com> | 2009-12-18 17:59:01 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-12-21 18:56:10 -0500 |
commit | 3b377ea9d4efc94dc52fe41b4dfdb463635ab298 (patch) | |
tree | 76724e77913096c03f6b216573d4a24ce13fe7c3 /net/wireless/reg.c | |
parent | 59d9cb071d6209f2e8df2d16228cfdc7bab1f2d1 (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.c | 120 |
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 | ||
364 | static 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(®d->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 | ||
389 | struct reg_regdb_search_request { | ||
390 | char alpha2[2]; | ||
391 | struct list_head list; | ||
392 | }; | ||
393 | |||
394 | static LIST_HEAD(reg_regdb_search_list); | ||
395 | static DEFINE_SPINLOCK(reg_regdb_search_lock); | ||
396 | |||
397 | static 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(®_regdb_search_lock); | ||
404 | while (!list_empty(®_regdb_search_list)) { | ||
405 | request = list_first_entry(®_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(®dom, curdom); | ||
415 | if (r) | ||
416 | break; | ||
417 | spin_unlock(®_regdb_search_lock); | ||
418 | mutex_lock(&cfg80211_mutex); | ||
419 | set_regdom(regdom); | ||
420 | mutex_unlock(&cfg80211_mutex); | ||
421 | spin_lock(®_regdb_search_lock); | ||
422 | break; | ||
423 | } | ||
424 | } | ||
425 | |||
426 | kfree(request); | ||
427 | } | ||
428 | spin_unlock(®_regdb_search_lock); | ||
429 | } | ||
430 | |||
431 | static DECLARE_WORK(reg_regdb_work, reg_regdb_search); | ||
432 | |||
433 | static 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(®_regdb_search_lock); | ||
447 | list_add_tail(&request->list, ®_regdb_search_list); | ||
448 | spin_unlock(®_regdb_search_lock); | ||
449 | |||
450 | schedule_work(®_regdb_work); | ||
451 | } | ||
452 | #else | ||
453 | static 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 | } |
1368 | EXPORT_SYMBOL(wiphy_apply_custom_regulatory); | 1464 | EXPORT_SYMBOL(wiphy_apply_custom_regulatory); |
1369 | 1465 | ||
1370 | static 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(®d->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 |