diff options
author | Johannes Berg <johannes.berg@intel.com> | 2015-10-15 03:03:05 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2015-10-15 10:17:09 -0400 |
commit | c7d319e542a3126bca029745735cdef5a5ca55c2 (patch) | |
tree | 5e8fc98483271df35fb413988c22398aa2124a78 | |
parent | cecbb069cce37dac754380d36c31e286a276e4c3 (diff) |
cfg80211: reg: search built-in database directly
Instead of searching the built-in database only in the worker,
search it directly and return an error if the entry cannot be
found (or memory cannot be allocated.) This means that builtin
database queries no longer rely on the timeout.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-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) | |||
453 | } | 453 | } |
454 | 454 | ||
455 | #ifdef CONFIG_CFG80211_INTERNAL_REGDB | 455 | #ifdef CONFIG_CFG80211_INTERNAL_REGDB |
456 | struct reg_regdb_search_request { | 456 | struct reg_regdb_apply_request { |
457 | char alpha2[2]; | ||
458 | struct list_head list; | 457 | struct list_head list; |
458 | const struct ieee80211_regdomain *regdom; | ||
459 | }; | 459 | }; |
460 | 460 | ||
461 | static LIST_HEAD(reg_regdb_search_list); | 461 | static LIST_HEAD(reg_regdb_apply_list); |
462 | static DEFINE_MUTEX(reg_regdb_search_mutex); | 462 | static DEFINE_MUTEX(reg_regdb_apply_mutex); |
463 | 463 | ||
464 | static void reg_regdb_search(struct work_struct *work) | 464 | static void reg_regdb_apply(struct work_struct *work) |
465 | { | 465 | { |
466 | struct reg_regdb_search_request *request; | 466 | struct reg_regdb_apply_request *request; |
467 | const struct ieee80211_regdomain *curdom, *regdom = NULL; | ||
468 | int i; | ||
469 | 467 | ||
470 | rtnl_lock(); | 468 | rtnl_lock(); |
471 | 469 | ||
472 | mutex_lock(®_regdb_search_mutex); | 470 | mutex_lock(®_regdb_apply_mutex); |
473 | while (!list_empty(®_regdb_search_list)) { | 471 | while (!list_empty(®_regdb_apply_list)) { |
474 | request = list_first_entry(®_regdb_search_list, | 472 | request = list_first_entry(®_regdb_apply_list, |
475 | struct reg_regdb_search_request, | 473 | struct reg_regdb_apply_request, |
476 | list); | 474 | list); |
477 | list_del(&request->list); | 475 | list_del(&request->list); |
478 | 476 | ||
479 | for (i = 0; i < reg_regdb_size; i++) { | 477 | set_regdom(request->regdom, REGD_SOURCE_INTERNAL_DB); |
480 | curdom = reg_regdb[i]; | ||
481 | |||
482 | if (alpha2_equal(request->alpha2, curdom->alpha2)) { | ||
483 | regdom = reg_copy_regd(curdom); | ||
484 | break; | ||
485 | } | ||
486 | } | ||
487 | |||
488 | kfree(request); | 478 | kfree(request); |
489 | } | 479 | } |
490 | mutex_unlock(®_regdb_search_mutex); | 480 | mutex_unlock(®_regdb_apply_mutex); |
491 | |||
492 | if (!IS_ERR_OR_NULL(regdom)) | ||
493 | set_regdom(regdom, REGD_SOURCE_INTERNAL_DB); | ||
494 | 481 | ||
495 | rtnl_unlock(); | 482 | rtnl_unlock(); |
496 | } | 483 | } |
497 | 484 | ||
498 | static DECLARE_WORK(reg_regdb_work, reg_regdb_search); | 485 | static DECLARE_WORK(reg_regdb_work, reg_regdb_apply); |
499 | 486 | ||
500 | static void reg_regdb_query(const char *alpha2) | 487 | static int reg_regdb_query(const char *alpha2) |
501 | { | 488 | { |
502 | struct reg_regdb_search_request *request; | 489 | const struct ieee80211_regdomain *regdom = NULL; |
490 | struct reg_regdb_apply_request *request; | ||
491 | unsigned int i; | ||
492 | |||
493 | for (i = 0; i < reg_regdb_size; i++) { | ||
494 | if (alpha2_equal(alpha2, reg_regdb[i]->alpha2)) { | ||
495 | regdom = reg_regdb[i]; | ||
496 | break; | ||
497 | } | ||
498 | } | ||
499 | |||
500 | if (!regdom) | ||
501 | return -ENODATA; | ||
503 | 502 | ||
504 | request = kzalloc(sizeof(struct reg_regdb_search_request), GFP_KERNEL); | 503 | request = kzalloc(sizeof(struct reg_regdb_apply_request), GFP_KERNEL); |
505 | if (!request) | 504 | if (!request) |
506 | return; | 505 | return -ENOMEM; |
507 | 506 | ||
508 | memcpy(request->alpha2, alpha2, 2); | 507 | request->regdom = reg_copy_regd(regdom); |
508 | if (IS_ERR_OR_NULL(request->regdom)) { | ||
509 | kfree(request); | ||
510 | return -ENOMEM; | ||
511 | } | ||
509 | 512 | ||
510 | mutex_lock(®_regdb_search_mutex); | 513 | mutex_lock(®_regdb_apply_mutex); |
511 | list_add_tail(&request->list, ®_regdb_search_list); | 514 | list_add_tail(&request->list, ®_regdb_apply_list); |
512 | mutex_unlock(®_regdb_search_mutex); | 515 | mutex_unlock(®_regdb_apply_mutex); |
513 | 516 | ||
514 | schedule_work(®_regdb_work); | 517 | schedule_work(®_regdb_work); |
518 | |||
519 | return 0; | ||
515 | } | 520 | } |
516 | 521 | ||
517 | /* Feel free to add any other sanity checks here */ | 522 | /* Feel free to add any other sanity checks here */ |
@@ -522,7 +527,10 @@ static void reg_regdb_size_check(void) | |||
522 | } | 527 | } |
523 | #else | 528 | #else |
524 | static inline void reg_regdb_size_check(void) {} | 529 | static inline void reg_regdb_size_check(void) {} |
525 | static inline void reg_regdb_query(const char *alpha2) {} | 530 | static inline int reg_regdb_query(const char *alpha2) |
531 | { | ||
532 | return -ENODATA; | ||
533 | } | ||
526 | #endif /* CONFIG_CFG80211_INTERNAL_REGDB */ | 534 | #endif /* CONFIG_CFG80211_INTERNAL_REGDB */ |
527 | 535 | ||
528 | /* | 536 | /* |
@@ -533,13 +541,11 @@ static int call_crda(const char *alpha2) | |||
533 | { | 541 | { |
534 | char country[12]; | 542 | char country[12]; |
535 | char *env[] = { country, NULL }; | 543 | char *env[] = { country, NULL }; |
544 | int ret; | ||
536 | 545 | ||
537 | snprintf(country, sizeof(country), "COUNTRY=%c%c", | 546 | snprintf(country, sizeof(country), "COUNTRY=%c%c", |
538 | alpha2[0], alpha2[1]); | 547 | alpha2[0], alpha2[1]); |
539 | 548 | ||
540 | /* query internal regulatory database (if it exists) */ | ||
541 | reg_regdb_query(alpha2); | ||
542 | |||
543 | if (reg_crda_timeouts > REG_MAX_CRDA_TIMEOUTS) { | 549 | if (reg_crda_timeouts > REG_MAX_CRDA_TIMEOUTS) { |
544 | pr_debug("Exceeded CRDA call max attempts. Not calling CRDA\n"); | 550 | pr_debug("Exceeded CRDA call max attempts. Not calling CRDA\n"); |
545 | return -EINVAL; | 551 | return -EINVAL; |
@@ -551,17 +557,25 @@ static int call_crda(const char *alpha2) | |||
551 | else | 557 | else |
552 | pr_debug("Calling CRDA to update world regulatory domain\n"); | 558 | pr_debug("Calling CRDA to update world regulatory domain\n"); |
553 | 559 | ||
554 | return kobject_uevent_env(®_pdev->dev.kobj, KOBJ_CHANGE, env); | 560 | ret = kobject_uevent_env(®_pdev->dev.kobj, KOBJ_CHANGE, env); |
561 | if (ret) | ||
562 | return ret; | ||
563 | |||
564 | queue_delayed_work(system_power_efficient_wq, | ||
565 | ®_timeout, msecs_to_jiffies(3142)); | ||
566 | return 0; | ||
555 | } | 567 | } |
556 | 568 | ||
557 | static bool reg_query_database(struct regulatory_request *request) | 569 | static bool reg_query_database(struct regulatory_request *request) |
558 | { | 570 | { |
559 | if (call_crda(request->alpha2)) | 571 | /* query internal regulatory database (if it exists) */ |
560 | return false; | 572 | if (reg_regdb_query(request->alpha2) == 0) |
573 | return true; | ||
561 | 574 | ||
562 | queue_delayed_work(system_power_efficient_wq, | 575 | if (call_crda(request->alpha2) == 0) |
563 | ®_timeout, msecs_to_jiffies(3142)); | 576 | return true; |
564 | return true; | 577 | |
578 | return false; | ||
565 | } | 579 | } |
566 | 580 | ||
567 | bool reg_is_valid_request(const char *alpha2) | 581 | bool reg_is_valid_request(const char *alpha2) |