aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/wireless/reg.c90
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 */
46struct regulatory_request { 46struct 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
54static LIST_HEAD(regulatory_requests); 53static struct regulatory_request *last_request;
55 54
56/* To trigger userspace events */ 55/* To trigger userspace events */
57static struct platform_device *reg_pdev; 56static struct platform_device *reg_pdev;
@@ -201,7 +200,7 @@ static void reset_regdomains(void)
201 * core upon initialization */ 200 * core upon initialization */
202static void update_world_regdomain(const struct ieee80211_regdomain *rd) 201static void update_world_regdomain(const struct ieee80211_regdomain *rd)
203{ 202{
204 BUG_ON(list_empty(&regulatory_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)
302static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, 301static 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(&regulatory_requests)) 305 if (!last_request)
309 return 0; 306 return 0;
310 307
311 last_request = list_first_entry(&regulatory_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
395static bool __reg_is_valid_request(const char *alpha2,
396 struct regulatory_request **request)
397{
398 struct regulatory_request *req;
399 if (list_empty(&regulatory_requests))
400 return false;
401 list_for_each_entry(req, &regulatory_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 */
411bool reg_is_valid_request(const char *alpha2) 390bool 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, &regulatory_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
712static int __set_regdom(const struct ieee80211_regdomain *rd) 694static 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(&regulatory_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 */
777int set_regdom(const struct ieee80211_regdomain *rd) 757int 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(&regulatory_requests))
783 prev_request = list_first_entry(&regulatory_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
854void regulatory_exit(void) 810void 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, &regulatory_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);