diff options
-rw-r--r-- | net/wireless/reg.c | 90 |
1 files changed, 21 insertions, 69 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 581273d86844..a78902d0d6c9 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -44,14 +44,13 @@ | |||
44 | 44 | ||
45 | /* wiphy is set if this request's initiator is REGDOM_SET_BY_DRIVER */ | 45 | /* wiphy is set if this request's initiator is REGDOM_SET_BY_DRIVER */ |
46 | struct regulatory_request { | 46 | struct regulatory_request { |
47 | struct list_head list; | ||
48 | struct wiphy *wiphy; | 47 | struct wiphy *wiphy; |
49 | int granted; | 48 | int granted; |
50 | enum reg_set_by initiator; | 49 | enum reg_set_by initiator; |
51 | char alpha2[2]; | 50 | char alpha2[2]; |
52 | }; | 51 | }; |
53 | 52 | ||
54 | static LIST_HEAD(regulatory_requests); | 53 | static struct regulatory_request *last_request; |
55 | 54 | ||
56 | /* To trigger userspace events */ | 55 | /* To trigger userspace events */ |
57 | static struct platform_device *reg_pdev; | 56 | static struct platform_device *reg_pdev; |
@@ -201,7 +200,7 @@ static void reset_regdomains(void) | |||
201 | * core upon initialization */ | 200 | * core upon initialization */ |
202 | static void update_world_regdomain(const struct ieee80211_regdomain *rd) | 201 | static void update_world_regdomain(const struct ieee80211_regdomain *rd) |
203 | { | 202 | { |
204 | BUG_ON(list_empty(®ulatory_requests)); | 203 | BUG_ON(!last_request); |
205 | 204 | ||
206 | reset_regdomains(); | 205 | reset_regdomains(); |
207 | 206 | ||
@@ -302,15 +301,10 @@ static int call_crda(const char *alpha2) | |||
302 | static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, | 301 | static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, |
303 | char *alpha2, struct ieee80211_regdomain *rd) | 302 | char *alpha2, struct ieee80211_regdomain *rd) |
304 | { | 303 | { |
305 | struct regulatory_request *last_request = NULL; | ||
306 | |||
307 | /* All initial requests are respected */ | 304 | /* All initial requests are respected */ |
308 | if (list_empty(®ulatory_requests)) | 305 | if (!last_request) |
309 | return 0; | 306 | return 0; |
310 | 307 | ||
311 | last_request = list_first_entry(®ulatory_requests, | ||
312 | struct regulatory_request, list); | ||
313 | |||
314 | switch (set_by) { | 308 | switch (set_by) { |
315 | case REGDOM_SET_BY_INIT: | 309 | case REGDOM_SET_BY_INIT: |
316 | return -EINVAL; | 310 | return -EINVAL; |
@@ -320,7 +314,7 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, | |||
320 | * anyway */ | 314 | * anyway */ |
321 | return 0; | 315 | return 0; |
322 | case REGDOM_SET_BY_COUNTRY_IE: | 316 | case REGDOM_SET_BY_COUNTRY_IE: |
323 | if (last_request->initiator == set_by) { | 317 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) { |
324 | if (last_request->wiphy != wiphy) { | 318 | if (last_request->wiphy != wiphy) { |
325 | /* Two cards with two APs claiming different | 319 | /* Two cards with two APs claiming different |
326 | * different Country IE alpha2s! | 320 | * different Country IE alpha2s! |
@@ -350,7 +344,7 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, | |||
350 | return 1; | 344 | return 1; |
351 | case REGDOM_SET_BY_DRIVER: | 345 | case REGDOM_SET_BY_DRIVER: |
352 | BUG_ON(!wiphy); | 346 | BUG_ON(!wiphy); |
353 | if (last_request->initiator == set_by) { | 347 | if (last_request->initiator == REGDOM_SET_BY_DRIVER) { |
354 | /* Two separate drivers hinting different things, | 348 | /* Two separate drivers hinting different things, |
355 | * this is possible if you have two devices present | 349 | * this is possible if you have two devices present |
356 | * on a system with different EEPROM regulatory | 350 | * on a system with different EEPROM regulatory |
@@ -376,8 +370,8 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, | |||
376 | return 0; | 370 | return 0; |
377 | return 0; | 371 | return 0; |
378 | case REGDOM_SET_BY_USER: | 372 | case REGDOM_SET_BY_USER: |
379 | if (last_request->initiator == set_by || | 373 | if (last_request->initiator == REGDOM_SET_BY_USER || |
380 | last_request->initiator == REGDOM_SET_BY_CORE) | 374 | last_request->initiator == REGDOM_SET_BY_CORE) |
381 | return 0; | 375 | return 0; |
382 | /* Drivers can use their wiphy's reg_notifier() | 376 | /* Drivers can use their wiphy's reg_notifier() |
383 | * to override any information */ | 377 | * to override any information */ |
@@ -392,26 +386,13 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, | |||
392 | } | 386 | } |
393 | } | 387 | } |
394 | 388 | ||
395 | static bool __reg_is_valid_request(const char *alpha2, | ||
396 | struct regulatory_request **request) | ||
397 | { | ||
398 | struct regulatory_request *req; | ||
399 | if (list_empty(®ulatory_requests)) | ||
400 | return false; | ||
401 | list_for_each_entry(req, ®ulatory_requests, list) { | ||
402 | if (alpha2_equal(req->alpha2, alpha2)) { | ||
403 | *request = req; | ||
404 | return true; | ||
405 | } | ||
406 | } | ||
407 | return false; | ||
408 | } | ||
409 | |||
410 | /* Used by nl80211 before kmalloc'ing our regulatory domain */ | 389 | /* Used by nl80211 before kmalloc'ing our regulatory domain */ |
411 | bool reg_is_valid_request(const char *alpha2) | 390 | bool reg_is_valid_request(const char *alpha2) |
412 | { | 391 | { |
413 | struct regulatory_request *request = NULL; | 392 | if (!last_request) |
414 | return __reg_is_valid_request(alpha2, &request); | 393 | return false; |
394 | |||
395 | return alpha2_equal(last_request->alpha2, alpha2); | ||
415 | } | 396 | } |
416 | 397 | ||
417 | /* Sanity check on a regulatory rule */ | 398 | /* Sanity check on a regulatory rule */ |
@@ -607,7 +588,8 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, | |||
607 | request->initiator = set_by; | 588 | request->initiator = set_by; |
608 | request->wiphy = wiphy; | 589 | request->wiphy = wiphy; |
609 | 590 | ||
610 | list_add_tail(&request->list, ®ulatory_requests); | 591 | kfree(last_request); |
592 | last_request = request; | ||
611 | if (rd) | 593 | if (rd) |
612 | break; | 594 | break; |
613 | r = call_crda(alpha2); | 595 | r = call_crda(alpha2); |
@@ -711,12 +693,10 @@ void print_regdomain_info(const struct ieee80211_regdomain *rd) | |||
711 | 693 | ||
712 | static int __set_regdom(const struct ieee80211_regdomain *rd) | 694 | static int __set_regdom(const struct ieee80211_regdomain *rd) |
713 | { | 695 | { |
714 | struct regulatory_request *request = NULL; | ||
715 | |||
716 | /* Some basic sanity checks first */ | 696 | /* Some basic sanity checks first */ |
717 | 697 | ||
718 | if (is_world_regdom(rd->alpha2)) { | 698 | if (is_world_regdom(rd->alpha2)) { |
719 | if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request))) | 699 | if (WARN_ON(!reg_is_valid_request(rd->alpha2))) |
720 | return -EINVAL; | 700 | return -EINVAL; |
721 | update_world_regdomain(rd); | 701 | update_world_regdomain(rd); |
722 | return 0; | 702 | return 0; |
@@ -726,7 +706,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
726 | !is_unknown_alpha2(rd->alpha2)) | 706 | !is_unknown_alpha2(rd->alpha2)) |
727 | return -EINVAL; | 707 | return -EINVAL; |
728 | 708 | ||
729 | if (list_empty(®ulatory_requests)) | 709 | if (!last_request) |
730 | return -EINVAL; | 710 | return -EINVAL; |
731 | 711 | ||
732 | /* allow overriding the static definitions if CRDA is present */ | 712 | /* allow overriding the static definitions if CRDA is present */ |
@@ -739,13 +719,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
739 | * to review or adjust their own settings based on their own | 719 | * to review or adjust their own settings based on their own |
740 | * internal EEPROM data */ | 720 | * internal EEPROM data */ |
741 | 721 | ||
742 | if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request))) | 722 | if (WARN_ON(!reg_is_valid_request(rd->alpha2))) |
743 | return -EINVAL; | 723 | return -EINVAL; |
744 | 724 | ||
745 | reset_regdomains(); | 725 | reset_regdomains(); |
746 | 726 | ||
747 | /* Country IE parsing coming soon */ | 727 | /* Country IE parsing coming soon */ |
748 | switch (request->initiator) { | 728 | switch (last_request->initiator) { |
749 | case REGDOM_SET_BY_CORE: | 729 | case REGDOM_SET_BY_CORE: |
750 | case REGDOM_SET_BY_DRIVER: | 730 | case REGDOM_SET_BY_DRIVER: |
751 | case REGDOM_SET_BY_USER: | 731 | case REGDOM_SET_BY_USER: |
@@ -764,7 +744,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
764 | 744 | ||
765 | /* Tada! */ | 745 | /* Tada! */ |
766 | cfg80211_regdomain = rd; | 746 | cfg80211_regdomain = rd; |
767 | request->granted = 1; | 747 | last_request->granted = 1; |
768 | 748 | ||
769 | return 0; | 749 | return 0; |
770 | } | 750 | } |
@@ -776,42 +756,18 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
776 | * the passed rd. Caller must hold cfg80211_drv_mutex */ | 756 | * the passed rd. Caller must hold cfg80211_drv_mutex */ |
777 | int set_regdom(const struct ieee80211_regdomain *rd) | 757 | int set_regdom(const struct ieee80211_regdomain *rd) |
778 | { | 758 | { |
779 | struct regulatory_request *this_request = NULL, *prev_request = NULL; | ||
780 | int r; | 759 | int r; |
781 | 760 | ||
782 | if (!list_empty(®ulatory_requests)) | ||
783 | prev_request = list_first_entry(®ulatory_requests, | ||
784 | struct regulatory_request, list); | ||
785 | |||
786 | /* Note that this doesn't update the wiphys, this is done below */ | 761 | /* Note that this doesn't update the wiphys, this is done below */ |
787 | r = __set_regdom(rd); | 762 | r = __set_regdom(rd); |
788 | if (r) | 763 | if (r) |
789 | return r; | 764 | return r; |
790 | 765 | ||
791 | BUG_ON((!__reg_is_valid_request(rd->alpha2, &this_request))); | ||
792 | |||
793 | /* The initial standard core update of the world regulatory domain, no | ||
794 | * need to keep that request info around if it didn't fail. */ | ||
795 | if (is_world_regdom(rd->alpha2) && | ||
796 | this_request->initiator == REGDOM_SET_BY_CORE && | ||
797 | this_request->granted) { | ||
798 | list_del(&this_request->list); | ||
799 | kfree(this_request); | ||
800 | this_request = NULL; | ||
801 | } | ||
802 | |||
803 | /* Remove old requests, we only leave behind the last one */ | ||
804 | if (prev_request) { | ||
805 | list_del(&prev_request->list); | ||
806 | kfree(prev_request); | ||
807 | prev_request = NULL; | ||
808 | } | ||
809 | |||
810 | /* This would make this whole thing pointless */ | 766 | /* This would make this whole thing pointless */ |
811 | BUG_ON(rd != cfg80211_regdomain); | 767 | BUG_ON(rd != cfg80211_regdomain); |
812 | 768 | ||
813 | /* update all wiphys now with the new established regulatory domain */ | 769 | /* update all wiphys now with the new established regulatory domain */ |
814 | update_all_wiphy_regulatory(this_request->initiator); | 770 | update_all_wiphy_regulatory(last_request->initiator); |
815 | 771 | ||
816 | print_regdomain(rd); | 772 | print_regdomain(rd); |
817 | 773 | ||
@@ -853,16 +809,12 @@ int regulatory_init(void) | |||
853 | 809 | ||
854 | void regulatory_exit(void) | 810 | void regulatory_exit(void) |
855 | { | 811 | { |
856 | struct regulatory_request *req, *req_tmp; | ||
857 | |||
858 | mutex_lock(&cfg80211_drv_mutex); | 812 | mutex_lock(&cfg80211_drv_mutex); |
859 | 813 | ||
860 | reset_regdomains(); | 814 | reset_regdomains(); |
861 | 815 | ||
862 | list_for_each_entry_safe(req, req_tmp, ®ulatory_requests, list) { | 816 | kfree(last_request); |
863 | list_del(&req->list); | 817 | |
864 | kfree(req); | ||
865 | } | ||
866 | platform_device_unregister(reg_pdev); | 818 | platform_device_unregister(reg_pdev); |
867 | 819 | ||
868 | mutex_unlock(&cfg80211_drv_mutex); | 820 | mutex_unlock(&cfg80211_drv_mutex); |