diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/reg.c | 625 |
1 files changed, 12 insertions, 613 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 1ac2bdd46ecf..678d0bd433f0 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -67,17 +67,9 @@ static struct platform_device *reg_pdev; | |||
67 | const struct ieee80211_regdomain *cfg80211_regdomain; | 67 | const struct ieee80211_regdomain *cfg80211_regdomain; |
68 | 68 | ||
69 | /* | 69 | /* |
70 | * We use this as a place for the rd structure built from the | ||
71 | * last parsed country IE to rest until CRDA gets back to us with | ||
72 | * what it thinks should apply for the same country | ||
73 | */ | ||
74 | static const struct ieee80211_regdomain *country_ie_regdomain; | ||
75 | |||
76 | /* | ||
77 | * Protects static reg.c components: | 70 | * Protects static reg.c components: |
78 | * - cfg80211_world_regdom | 71 | * - cfg80211_world_regdom |
79 | * - cfg80211_regdom | 72 | * - cfg80211_regdom |
80 | * - country_ie_regdomain | ||
81 | * - last_request | 73 | * - last_request |
82 | */ | 74 | */ |
83 | static DEFINE_MUTEX(reg_mutex); | 75 | static DEFINE_MUTEX(reg_mutex); |
@@ -275,25 +267,6 @@ static bool is_user_regdom_saved(void) | |||
275 | return true; | 267 | return true; |
276 | } | 268 | } |
277 | 269 | ||
278 | /** | ||
279 | * country_ie_integrity_changes - tells us if the country IE has changed | ||
280 | * @checksum: checksum of country IE of fields we are interested in | ||
281 | * | ||
282 | * If the country IE has not changed you can ignore it safely. This is | ||
283 | * useful to determine if two devices are seeing two different country IEs | ||
284 | * even on the same alpha2. Note that this will return false if no IE has | ||
285 | * been set on the wireless core yet. | ||
286 | */ | ||
287 | static bool country_ie_integrity_changes(u32 checksum) | ||
288 | { | ||
289 | /* If no IE has been set then the checksum doesn't change */ | ||
290 | if (unlikely(!last_request->country_ie_checksum)) | ||
291 | return false; | ||
292 | if (unlikely(last_request->country_ie_checksum != checksum)) | ||
293 | return true; | ||
294 | return false; | ||
295 | } | ||
296 | |||
297 | static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, | 270 | static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, |
298 | const struct ieee80211_regdomain *src_regd) | 271 | const struct ieee80211_regdomain *src_regd) |
299 | { | 272 | { |
@@ -506,471 +479,6 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, | |||
506 | } | 479 | } |
507 | 480 | ||
508 | /* | 481 | /* |
509 | * This is a work around for sanity checking ieee80211_channel_to_frequency()'s | ||
510 | * work. ieee80211_channel_to_frequency() can for example currently provide a | ||
511 | * 2 GHz channel when in fact a 5 GHz channel was desired. An example would be | ||
512 | * an AP providing channel 8 on a country IE triplet when it sent this on the | ||
513 | * 5 GHz band, that channel is designed to be channel 8 on 5 GHz, not a 2 GHz | ||
514 | * channel. | ||
515 | * | ||
516 | * This can be removed once ieee80211_channel_to_frequency() takes in a band. | ||
517 | */ | ||
518 | static bool chan_in_band(int chan, enum ieee80211_band band) | ||
519 | { | ||
520 | int center_freq = ieee80211_channel_to_frequency(chan); | ||
521 | |||
522 | switch (band) { | ||
523 | case IEEE80211_BAND_2GHZ: | ||
524 | if (center_freq <= 2484) | ||
525 | return true; | ||
526 | return false; | ||
527 | case IEEE80211_BAND_5GHZ: | ||
528 | if (center_freq >= 5005) | ||
529 | return true; | ||
530 | return false; | ||
531 | default: | ||
532 | return false; | ||
533 | } | ||
534 | } | ||
535 | |||
536 | /* | ||
537 | * Some APs may send a country IE triplet for each channel they | ||
538 | * support and while this is completely overkill and silly we still | ||
539 | * need to support it. We avoid making a single rule for each channel | ||
540 | * though and to help us with this we use this helper to find the | ||
541 | * actual subband end channel. These type of country IE triplet | ||
542 | * scenerios are handled then, all yielding two regulaotry rules from | ||
543 | * parsing a country IE: | ||
544 | * | ||
545 | * [1] | ||
546 | * [2] | ||
547 | * [36] | ||
548 | * [40] | ||
549 | * | ||
550 | * [1] | ||
551 | * [2-4] | ||
552 | * [5-12] | ||
553 | * [36] | ||
554 | * [40-44] | ||
555 | * | ||
556 | * [1-4] | ||
557 | * [5-7] | ||
558 | * [36-44] | ||
559 | * [48-64] | ||
560 | * | ||
561 | * [36-36] | ||
562 | * [40-40] | ||
563 | * [44-44] | ||
564 | * [48-48] | ||
565 | * [52-52] | ||
566 | * [56-56] | ||
567 | * [60-60] | ||
568 | * [64-64] | ||
569 | * [100-100] | ||
570 | * [104-104] | ||
571 | * [108-108] | ||
572 | * [112-112] | ||
573 | * [116-116] | ||
574 | * [120-120] | ||
575 | * [124-124] | ||
576 | * [128-128] | ||
577 | * [132-132] | ||
578 | * [136-136] | ||
579 | * [140-140] | ||
580 | * | ||
581 | * Returns 0 if the IE has been found to be invalid in the middle | ||
582 | * somewhere. | ||
583 | */ | ||
584 | static int max_subband_chan(enum ieee80211_band band, | ||
585 | int orig_cur_chan, | ||
586 | int orig_end_channel, | ||
587 | s8 orig_max_power, | ||
588 | u8 **country_ie, | ||
589 | u8 *country_ie_len) | ||
590 | { | ||
591 | u8 *triplets_start = *country_ie; | ||
592 | u8 len_at_triplet = *country_ie_len; | ||
593 | int end_subband_chan = orig_end_channel; | ||
594 | |||
595 | /* | ||
596 | * We'll deal with padding for the caller unless | ||
597 | * its not immediate and we don't process any channels | ||
598 | */ | ||
599 | if (*country_ie_len == 1) { | ||
600 | *country_ie += 1; | ||
601 | *country_ie_len -= 1; | ||
602 | return orig_end_channel; | ||
603 | } | ||
604 | |||
605 | /* Move to the next triplet and then start search */ | ||
606 | *country_ie += 3; | ||
607 | *country_ie_len -= 3; | ||
608 | |||
609 | if (!chan_in_band(orig_cur_chan, band)) | ||
610 | return 0; | ||
611 | |||
612 | while (*country_ie_len >= 3) { | ||
613 | int end_channel = 0; | ||
614 | struct ieee80211_country_ie_triplet *triplet = | ||
615 | (struct ieee80211_country_ie_triplet *) *country_ie; | ||
616 | int cur_channel = 0, next_expected_chan; | ||
617 | |||
618 | /* means last triplet is completely unrelated to this one */ | ||
619 | if (triplet->ext.reg_extension_id >= | ||
620 | IEEE80211_COUNTRY_EXTENSION_ID) { | ||
621 | *country_ie -= 3; | ||
622 | *country_ie_len += 3; | ||
623 | break; | ||
624 | } | ||
625 | |||
626 | if (triplet->chans.first_channel == 0) { | ||
627 | *country_ie += 1; | ||
628 | *country_ie_len -= 1; | ||
629 | if (*country_ie_len != 0) | ||
630 | return 0; | ||
631 | break; | ||
632 | } | ||
633 | |||
634 | if (triplet->chans.num_channels == 0) | ||
635 | return 0; | ||
636 | |||
637 | /* Monitonically increasing channel order */ | ||
638 | if (triplet->chans.first_channel <= end_subband_chan) | ||
639 | return 0; | ||
640 | |||
641 | if (!chan_in_band(triplet->chans.first_channel, band)) | ||
642 | return 0; | ||
643 | |||
644 | /* 2 GHz */ | ||
645 | if (triplet->chans.first_channel <= 14) { | ||
646 | end_channel = triplet->chans.first_channel + | ||
647 | triplet->chans.num_channels - 1; | ||
648 | } | ||
649 | else { | ||
650 | end_channel = triplet->chans.first_channel + | ||
651 | (4 * (triplet->chans.num_channels - 1)); | ||
652 | } | ||
653 | |||
654 | if (!chan_in_band(end_channel, band)) | ||
655 | return 0; | ||
656 | |||
657 | if (orig_max_power != triplet->chans.max_power) { | ||
658 | *country_ie -= 3; | ||
659 | *country_ie_len += 3; | ||
660 | break; | ||
661 | } | ||
662 | |||
663 | cur_channel = triplet->chans.first_channel; | ||
664 | |||
665 | /* The key is finding the right next expected channel */ | ||
666 | if (band == IEEE80211_BAND_2GHZ) | ||
667 | next_expected_chan = end_subband_chan + 1; | ||
668 | else | ||
669 | next_expected_chan = end_subband_chan + 4; | ||
670 | |||
671 | if (cur_channel != next_expected_chan) { | ||
672 | *country_ie -= 3; | ||
673 | *country_ie_len += 3; | ||
674 | break; | ||
675 | } | ||
676 | |||
677 | end_subband_chan = end_channel; | ||
678 | |||
679 | /* Move to the next one */ | ||
680 | *country_ie += 3; | ||
681 | *country_ie_len -= 3; | ||
682 | |||
683 | /* | ||
684 | * Padding needs to be dealt with if we processed | ||
685 | * some channels. | ||
686 | */ | ||
687 | if (*country_ie_len == 1) { | ||
688 | *country_ie += 1; | ||
689 | *country_ie_len -= 1; | ||
690 | break; | ||
691 | } | ||
692 | |||
693 | /* If seen, the IE is invalid */ | ||
694 | if (*country_ie_len == 2) | ||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | if (end_subband_chan == orig_end_channel) { | ||
699 | *country_ie = triplets_start; | ||
700 | *country_ie_len = len_at_triplet; | ||
701 | return orig_end_channel; | ||
702 | } | ||
703 | |||
704 | return end_subband_chan; | ||
705 | } | ||
706 | |||
707 | /* | ||
708 | * Converts a country IE to a regulatory domain. A regulatory domain | ||
709 | * structure has a lot of information which the IE doesn't yet have, | ||
710 | * so for the other values we use upper max values as we will intersect | ||
711 | * with our userspace regulatory agent to get lower bounds. | ||
712 | */ | ||
713 | static struct ieee80211_regdomain *country_ie_2_rd( | ||
714 | enum ieee80211_band band, | ||
715 | u8 *country_ie, | ||
716 | u8 country_ie_len, | ||
717 | u32 *checksum) | ||
718 | { | ||
719 | struct ieee80211_regdomain *rd = NULL; | ||
720 | unsigned int i = 0; | ||
721 | char alpha2[2]; | ||
722 | u32 flags = 0; | ||
723 | u32 num_rules = 0, size_of_regd = 0; | ||
724 | u8 *triplets_start = NULL; | ||
725 | u8 len_at_triplet = 0; | ||
726 | /* the last channel we have registered in a subband (triplet) */ | ||
727 | int last_sub_max_channel = 0; | ||
728 | |||
729 | *checksum = 0xDEADBEEF; | ||
730 | |||
731 | /* Country IE requirements */ | ||
732 | BUG_ON(country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN || | ||
733 | country_ie_len & 0x01); | ||
734 | |||
735 | alpha2[0] = country_ie[0]; | ||
736 | alpha2[1] = country_ie[1]; | ||
737 | |||
738 | /* | ||
739 | * Third octet can be: | ||
740 | * 'I' - Indoor | ||
741 | * 'O' - Outdoor | ||
742 | * | ||
743 | * anything else we assume is no restrictions | ||
744 | */ | ||
745 | if (country_ie[2] == 'I') | ||
746 | flags = NL80211_RRF_NO_OUTDOOR; | ||
747 | else if (country_ie[2] == 'O') | ||
748 | flags = NL80211_RRF_NO_INDOOR; | ||
749 | |||
750 | country_ie += 3; | ||
751 | country_ie_len -= 3; | ||
752 | |||
753 | triplets_start = country_ie; | ||
754 | len_at_triplet = country_ie_len; | ||
755 | |||
756 | *checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8); | ||
757 | |||
758 | /* | ||
759 | * We need to build a reg rule for each triplet, but first we must | ||
760 | * calculate the number of reg rules we will need. We will need one | ||
761 | * for each channel subband | ||
762 | */ | ||
763 | while (country_ie_len >= 3) { | ||
764 | int end_channel = 0; | ||
765 | struct ieee80211_country_ie_triplet *triplet = | ||
766 | (struct ieee80211_country_ie_triplet *) country_ie; | ||
767 | int cur_sub_max_channel = 0, cur_channel = 0; | ||
768 | |||
769 | if (triplet->ext.reg_extension_id >= | ||
770 | IEEE80211_COUNTRY_EXTENSION_ID) { | ||
771 | country_ie += 3; | ||
772 | country_ie_len -= 3; | ||
773 | continue; | ||
774 | } | ||
775 | |||
776 | /* | ||
777 | * APs can add padding to make length divisible | ||
778 | * by two, required by the spec. | ||
779 | */ | ||
780 | if (triplet->chans.first_channel == 0) { | ||
781 | country_ie++; | ||
782 | country_ie_len--; | ||
783 | /* This is expected to be at the very end only */ | ||
784 | if (country_ie_len != 0) | ||
785 | return NULL; | ||
786 | break; | ||
787 | } | ||
788 | |||
789 | if (triplet->chans.num_channels == 0) | ||
790 | return NULL; | ||
791 | |||
792 | if (!chan_in_band(triplet->chans.first_channel, band)) | ||
793 | return NULL; | ||
794 | |||
795 | /* 2 GHz */ | ||
796 | if (band == IEEE80211_BAND_2GHZ) | ||
797 | end_channel = triplet->chans.first_channel + | ||
798 | triplet->chans.num_channels - 1; | ||
799 | else | ||
800 | /* | ||
801 | * 5 GHz -- For example in country IEs if the first | ||
802 | * channel given is 36 and the number of channels is 4 | ||
803 | * then the individual channel numbers defined for the | ||
804 | * 5 GHz PHY by these parameters are: 36, 40, 44, and 48 | ||
805 | * and not 36, 37, 38, 39. | ||
806 | * | ||
807 | * See: http://tinyurl.com/11d-clarification | ||
808 | */ | ||
809 | end_channel = triplet->chans.first_channel + | ||
810 | (4 * (triplet->chans.num_channels - 1)); | ||
811 | |||
812 | cur_channel = triplet->chans.first_channel; | ||
813 | |||
814 | /* | ||
815 | * Enhancement for APs that send a triplet for every channel | ||
816 | * or for whatever reason sends triplets with multiple channels | ||
817 | * separated when in fact they should be together. | ||
818 | */ | ||
819 | end_channel = max_subband_chan(band, | ||
820 | cur_channel, | ||
821 | end_channel, | ||
822 | triplet->chans.max_power, | ||
823 | &country_ie, | ||
824 | &country_ie_len); | ||
825 | if (!end_channel) | ||
826 | return NULL; | ||
827 | |||
828 | if (!chan_in_band(end_channel, band)) | ||
829 | return NULL; | ||
830 | |||
831 | cur_sub_max_channel = end_channel; | ||
832 | |||
833 | /* Basic sanity check */ | ||
834 | if (cur_sub_max_channel < cur_channel) | ||
835 | return NULL; | ||
836 | |||
837 | /* | ||
838 | * Do not allow overlapping channels. Also channels | ||
839 | * passed in each subband must be monotonically | ||
840 | * increasing | ||
841 | */ | ||
842 | if (last_sub_max_channel) { | ||
843 | if (cur_channel <= last_sub_max_channel) | ||
844 | return NULL; | ||
845 | if (cur_sub_max_channel <= last_sub_max_channel) | ||
846 | return NULL; | ||
847 | } | ||
848 | |||
849 | /* | ||
850 | * When dot11RegulatoryClassesRequired is supported | ||
851 | * we can throw ext triplets as part of this soup, | ||
852 | * for now we don't care when those change as we | ||
853 | * don't support them | ||
854 | */ | ||
855 | *checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) | | ||
856 | ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) | | ||
857 | ((triplet->chans.max_power ^ cur_sub_max_channel) << 24); | ||
858 | |||
859 | last_sub_max_channel = cur_sub_max_channel; | ||
860 | |||
861 | num_rules++; | ||
862 | |||
863 | if (country_ie_len >= 3) { | ||
864 | country_ie += 3; | ||
865 | country_ie_len -= 3; | ||
866 | } | ||
867 | |||
868 | /* | ||
869 | * Note: this is not a IEEE requirement but | ||
870 | * simply a memory requirement | ||
871 | */ | ||
872 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) | ||
873 | return NULL; | ||
874 | } | ||
875 | |||
876 | country_ie = triplets_start; | ||
877 | country_ie_len = len_at_triplet; | ||
878 | |||
879 | size_of_regd = sizeof(struct ieee80211_regdomain) + | ||
880 | (num_rules * sizeof(struct ieee80211_reg_rule)); | ||
881 | |||
882 | rd = kzalloc(size_of_regd, GFP_KERNEL); | ||
883 | if (!rd) | ||
884 | return NULL; | ||
885 | |||
886 | rd->n_reg_rules = num_rules; | ||
887 | rd->alpha2[0] = alpha2[0]; | ||
888 | rd->alpha2[1] = alpha2[1]; | ||
889 | |||
890 | /* This time around we fill in the rd */ | ||
891 | while (country_ie_len >= 3) { | ||
892 | int end_channel = 0; | ||
893 | struct ieee80211_country_ie_triplet *triplet = | ||
894 | (struct ieee80211_country_ie_triplet *) country_ie; | ||
895 | struct ieee80211_reg_rule *reg_rule = NULL; | ||
896 | struct ieee80211_freq_range *freq_range = NULL; | ||
897 | struct ieee80211_power_rule *power_rule = NULL; | ||
898 | |||
899 | /* | ||
900 | * Must parse if dot11RegulatoryClassesRequired is true, | ||
901 | * we don't support this yet | ||
902 | */ | ||
903 | if (triplet->ext.reg_extension_id >= | ||
904 | IEEE80211_COUNTRY_EXTENSION_ID) { | ||
905 | country_ie += 3; | ||
906 | country_ie_len -= 3; | ||
907 | continue; | ||
908 | } | ||
909 | |||
910 | if (triplet->chans.first_channel == 0) { | ||
911 | country_ie++; | ||
912 | country_ie_len--; | ||
913 | break; | ||
914 | } | ||
915 | |||
916 | reg_rule = &rd->reg_rules[i]; | ||
917 | freq_range = ®_rule->freq_range; | ||
918 | power_rule = ®_rule->power_rule; | ||
919 | |||
920 | reg_rule->flags = flags; | ||
921 | |||
922 | /* 2 GHz */ | ||
923 | if (band == IEEE80211_BAND_2GHZ) | ||
924 | end_channel = triplet->chans.first_channel + | ||
925 | triplet->chans.num_channels -1; | ||
926 | else | ||
927 | end_channel = triplet->chans.first_channel + | ||
928 | (4 * (triplet->chans.num_channels - 1)); | ||
929 | |||
930 | end_channel = max_subband_chan(band, | ||
931 | triplet->chans.first_channel, | ||
932 | end_channel, | ||
933 | triplet->chans.max_power, | ||
934 | &country_ie, | ||
935 | &country_ie_len); | ||
936 | |||
937 | /* | ||
938 | * The +10 is since the regulatory domain expects | ||
939 | * the actual band edge, not the center of freq for | ||
940 | * its start and end freqs, assuming 20 MHz bandwidth on | ||
941 | * the channels passed | ||
942 | */ | ||
943 | freq_range->start_freq_khz = | ||
944 | MHZ_TO_KHZ(ieee80211_channel_to_frequency( | ||
945 | triplet->chans.first_channel) - 10); | ||
946 | freq_range->end_freq_khz = | ||
947 | MHZ_TO_KHZ(ieee80211_channel_to_frequency( | ||
948 | end_channel) + 10); | ||
949 | |||
950 | /* | ||
951 | * These are large arbitrary values we use to intersect later. | ||
952 | * Increment this if we ever support >= 40 MHz channels | ||
953 | * in IEEE 802.11 | ||
954 | */ | ||
955 | freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); | ||
956 | power_rule->max_antenna_gain = DBI_TO_MBI(100); | ||
957 | power_rule->max_eirp = DBM_TO_MBM(triplet->chans.max_power); | ||
958 | |||
959 | i++; | ||
960 | |||
961 | if (country_ie_len >= 3) { | ||
962 | country_ie += 3; | ||
963 | country_ie_len -= 3; | ||
964 | } | ||
965 | |||
966 | BUG_ON(i > NL80211_MAX_SUPP_REG_RULES); | ||
967 | } | ||
968 | |||
969 | return rd; | ||
970 | } | ||
971 | |||
972 | |||
973 | /* | ||
974 | * Helper for regdom_intersect(), this does the real | 482 | * Helper for regdom_intersect(), this does the real |
975 | * mathematical intersection fun | 483 | * mathematical intersection fun |
976 | */ | 484 | */ |
@@ -1191,7 +699,6 @@ static int freq_reg_info_regd(struct wiphy *wiphy, | |||
1191 | 699 | ||
1192 | return -EINVAL; | 700 | return -EINVAL; |
1193 | } | 701 | } |
1194 | EXPORT_SYMBOL(freq_reg_info); | ||
1195 | 702 | ||
1196 | int freq_reg_info(struct wiphy *wiphy, | 703 | int freq_reg_info(struct wiphy *wiphy, |
1197 | u32 center_freq, | 704 | u32 center_freq, |
@@ -1205,6 +712,7 @@ int freq_reg_info(struct wiphy *wiphy, | |||
1205 | reg_rule, | 712 | reg_rule, |
1206 | NULL); | 713 | NULL); |
1207 | } | 714 | } |
715 | EXPORT_SYMBOL(freq_reg_info); | ||
1208 | 716 | ||
1209 | /* | 717 | /* |
1210 | * Note that right now we assume the desired channel bandwidth | 718 | * Note that right now we assume the desired channel bandwidth |
@@ -1243,41 +751,8 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
1243 | desired_bw_khz, | 751 | desired_bw_khz, |
1244 | ®_rule); | 752 | ®_rule); |
1245 | 753 | ||
1246 | if (r) { | 754 | if (r) |
1247 | /* | ||
1248 | * This means no regulatory rule was found in the country IE | ||
1249 | * with a frequency range on the center_freq's band, since | ||
1250 | * IEEE-802.11 allows for a country IE to have a subset of the | ||
1251 | * regulatory information provided in a country we ignore | ||
1252 | * disabling the channel unless at least one reg rule was | ||
1253 | * found on the center_freq's band. For details see this | ||
1254 | * clarification: | ||
1255 | * | ||
1256 | * http://tinyurl.com/11d-clarification | ||
1257 | */ | ||
1258 | if (r == -ERANGE && | ||
1259 | last_request->initiator == | ||
1260 | NL80211_REGDOM_SET_BY_COUNTRY_IE) { | ||
1261 | REG_DBG_PRINT("cfg80211: Leaving channel %d MHz " | ||
1262 | "intact on %s - no rule found in band on " | ||
1263 | "Country IE\n", | ||
1264 | chan->center_freq, wiphy_name(wiphy)); | ||
1265 | } else { | ||
1266 | /* | ||
1267 | * In this case we know the country IE has at least one reg rule | ||
1268 | * for the band so we respect its band definitions | ||
1269 | */ | ||
1270 | if (last_request->initiator == | ||
1271 | NL80211_REGDOM_SET_BY_COUNTRY_IE) | ||
1272 | REG_DBG_PRINT("cfg80211: Disabling " | ||
1273 | "channel %d MHz on %s due to " | ||
1274 | "Country IE\n", | ||
1275 | chan->center_freq, wiphy_name(wiphy)); | ||
1276 | flags |= IEEE80211_CHAN_DISABLED; | ||
1277 | chan->flags = flags; | ||
1278 | } | ||
1279 | return; | 755 | return; |
1280 | } | ||
1281 | 756 | ||
1282 | power_rule = ®_rule->power_rule; | 757 | power_rule = ®_rule->power_rule; |
1283 | freq_range = ®_rule->freq_range; | 758 | freq_range = ®_rule->freq_range; |
@@ -2010,7 +1485,7 @@ EXPORT_SYMBOL(regulatory_hint); | |||
2010 | 1485 | ||
2011 | /* Caller must hold reg_mutex */ | 1486 | /* Caller must hold reg_mutex */ |
2012 | static bool reg_same_country_ie_hint(struct wiphy *wiphy, | 1487 | static bool reg_same_country_ie_hint(struct wiphy *wiphy, |
2013 | u32 country_ie_checksum) | 1488 | char *alpha2, enum environment_cap env) |
2014 | { | 1489 | { |
2015 | struct wiphy *request_wiphy; | 1490 | struct wiphy *request_wiphy; |
2016 | 1491 | ||
@@ -2026,13 +1501,17 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy, | |||
2026 | return false; | 1501 | return false; |
2027 | 1502 | ||
2028 | if (likely(request_wiphy != wiphy)) | 1503 | if (likely(request_wiphy != wiphy)) |
2029 | return !country_ie_integrity_changes(country_ie_checksum); | 1504 | return (last_request->alpha2[0] == alpha2[0] && |
1505 | last_request->alpha2[1] == alpha2[1] && | ||
1506 | last_request->country_ie_env == env); | ||
2030 | /* | 1507 | /* |
2031 | * We should not have let these through at this point, they | 1508 | * We should not have let these through at this point, they |
2032 | * should have been picked up earlier by the first alpha2 check | 1509 | * should have been picked up earlier by the first alpha2 check |
2033 | * on the device | 1510 | * on the device |
2034 | */ | 1511 | */ |
2035 | if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum))) | 1512 | if (WARN_ON((last_request->alpha2[0] == alpha2[0] && |
1513 | last_request->alpha2[1] == alpha2[1] && | ||
1514 | last_request->country_ie_env == env ))) | ||
2036 | return true; | 1515 | return true; |
2037 | return false; | 1516 | return false; |
2038 | } | 1517 | } |
@@ -2048,7 +1527,6 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
2048 | { | 1527 | { |
2049 | struct ieee80211_regdomain *rd = NULL; | 1528 | struct ieee80211_regdomain *rd = NULL; |
2050 | char alpha2[2]; | 1529 | char alpha2[2]; |
2051 | u32 checksum = 0; | ||
2052 | enum environment_cap env = ENVIRON_ANY; | 1530 | enum environment_cap env = ENVIRON_ANY; |
2053 | struct regulatory_request *request; | 1531 | struct regulatory_request *request; |
2054 | 1532 | ||
@@ -2064,14 +1542,6 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
2064 | if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) | 1542 | if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) |
2065 | goto out; | 1543 | goto out; |
2066 | 1544 | ||
2067 | /* | ||
2068 | * Pending country IE processing, this can happen after we | ||
2069 | * call CRDA and wait for a response if a beacon was received before | ||
2070 | * we were able to process the last regulatory_hint_11d() call | ||
2071 | */ | ||
2072 | if (country_ie_regdomain) | ||
2073 | goto out; | ||
2074 | |||
2075 | alpha2[0] = country_ie[0]; | 1545 | alpha2[0] = country_ie[0]; |
2076 | alpha2[1] = country_ie[1]; | 1546 | alpha2[1] = country_ie[1]; |
2077 | 1547 | ||
@@ -2090,12 +1560,6 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
2090 | wiphy_idx_valid(last_request->wiphy_idx))) | 1560 | wiphy_idx_valid(last_request->wiphy_idx))) |
2091 | goto out; | 1561 | goto out; |
2092 | 1562 | ||
2093 | rd = country_ie_2_rd(band, country_ie, country_ie_len, &checksum); | ||
2094 | if (!rd) { | ||
2095 | REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n"); | ||
2096 | goto out; | ||
2097 | } | ||
2098 | |||
2099 | /* | 1563 | /* |
2100 | * This will not happen right now but we leave it here for the | 1564 | * This will not happen right now but we leave it here for the |
2101 | * the future when we want to add suspend/resume support and having | 1565 | * the future when we want to add suspend/resume support and having |
@@ -2105,24 +1569,17 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
2105 | * If we hit this before we add this support we want to be informed of | 1569 | * If we hit this before we add this support we want to be informed of |
2106 | * it as it would indicate a mistake in the current design | 1570 | * it as it would indicate a mistake in the current design |
2107 | */ | 1571 | */ |
2108 | if (WARN_ON(reg_same_country_ie_hint(wiphy, checksum))) | 1572 | if (WARN_ON(reg_same_country_ie_hint(wiphy, alpha2, env))) |
2109 | goto free_rd_out; | 1573 | goto free_rd_out; |
2110 | 1574 | ||
2111 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); | 1575 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); |
2112 | if (!request) | 1576 | if (!request) |
2113 | goto free_rd_out; | 1577 | goto free_rd_out; |
2114 | 1578 | ||
2115 | /* | ||
2116 | * We keep this around for when CRDA comes back with a response so | ||
2117 | * we can intersect with that | ||
2118 | */ | ||
2119 | country_ie_regdomain = rd; | ||
2120 | |||
2121 | request->wiphy_idx = get_wiphy_idx(wiphy); | 1579 | request->wiphy_idx = get_wiphy_idx(wiphy); |
2122 | request->alpha2[0] = rd->alpha2[0]; | 1580 | request->alpha2[0] = alpha2[0]; |
2123 | request->alpha2[1] = rd->alpha2[1]; | 1581 | request->alpha2[1] = alpha2[1]; |
2124 | request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE; | 1582 | request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE; |
2125 | request->country_ie_checksum = checksum; | ||
2126 | request->country_ie_env = env; | 1583 | request->country_ie_env = env; |
2127 | 1584 | ||
2128 | mutex_unlock(®_mutex); | 1585 | mutex_unlock(®_mutex); |
@@ -2383,33 +1840,6 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd) | |||
2383 | print_rd_rules(rd); | 1840 | print_rd_rules(rd); |
2384 | } | 1841 | } |
2385 | 1842 | ||
2386 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
2387 | static void reg_country_ie_process_debug( | ||
2388 | const struct ieee80211_regdomain *rd, | ||
2389 | const struct ieee80211_regdomain *country_ie_regdomain, | ||
2390 | const struct ieee80211_regdomain *intersected_rd) | ||
2391 | { | ||
2392 | printk(KERN_DEBUG "cfg80211: Received country IE:\n"); | ||
2393 | print_regdomain_info(country_ie_regdomain); | ||
2394 | printk(KERN_DEBUG "cfg80211: CRDA thinks this should applied:\n"); | ||
2395 | print_regdomain_info(rd); | ||
2396 | if (intersected_rd) { | ||
2397 | printk(KERN_DEBUG "cfg80211: We intersect both of these " | ||
2398 | "and get:\n"); | ||
2399 | print_regdomain_info(intersected_rd); | ||
2400 | return; | ||
2401 | } | ||
2402 | printk(KERN_DEBUG "cfg80211: Intersection between both failed\n"); | ||
2403 | } | ||
2404 | #else | ||
2405 | static inline void reg_country_ie_process_debug( | ||
2406 | const struct ieee80211_regdomain *rd, | ||
2407 | const struct ieee80211_regdomain *country_ie_regdomain, | ||
2408 | const struct ieee80211_regdomain *intersected_rd) | ||
2409 | { | ||
2410 | } | ||
2411 | #endif | ||
2412 | |||
2413 | /* Takes ownership of rd only if it doesn't fail */ | 1843 | /* Takes ownership of rd only if it doesn't fail */ |
2414 | static int __set_regdom(const struct ieee80211_regdomain *rd) | 1844 | static int __set_regdom(const struct ieee80211_regdomain *rd) |
2415 | { | 1845 | { |
@@ -2521,34 +1951,6 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2521 | return 0; | 1951 | return 0; |
2522 | } | 1952 | } |
2523 | 1953 | ||
2524 | /* | ||
2525 | * Country IE requests are handled a bit differently, we intersect | ||
2526 | * the country IE rd with what CRDA believes that country should have | ||
2527 | */ | ||
2528 | |||
2529 | /* | ||
2530 | * Userspace could have sent two replies with only | ||
2531 | * one kernel request. By the second reply we would have | ||
2532 | * already processed and consumed the country_ie_regdomain. | ||
2533 | */ | ||
2534 | if (!country_ie_regdomain) | ||
2535 | return -EALREADY; | ||
2536 | BUG_ON(rd == country_ie_regdomain); | ||
2537 | |||
2538 | /* | ||
2539 | * Intersect what CRDA returned and our what we | ||
2540 | * had built from the Country IE received | ||
2541 | */ | ||
2542 | |||
2543 | intersected_rd = regdom_intersect(rd, country_ie_regdomain); | ||
2544 | |||
2545 | reg_country_ie_process_debug(rd, | ||
2546 | country_ie_regdomain, | ||
2547 | intersected_rd); | ||
2548 | |||
2549 | kfree(country_ie_regdomain); | ||
2550 | country_ie_regdomain = NULL; | ||
2551 | |||
2552 | if (!intersected_rd) | 1954 | if (!intersected_rd) |
2553 | return -EINVAL; | 1955 | return -EINVAL; |
2554 | 1956 | ||
@@ -2688,9 +2090,6 @@ void /* __init_or_exit */ regulatory_exit(void) | |||
2688 | 2090 | ||
2689 | reset_regdomains(); | 2091 | reset_regdomains(); |
2690 | 2092 | ||
2691 | kfree(country_ie_regdomain); | ||
2692 | country_ie_regdomain = NULL; | ||
2693 | |||
2694 | kfree(last_request); | 2093 | kfree(last_request); |
2695 | 2094 | ||
2696 | platform_device_unregister(reg_pdev); | 2095 | platform_device_unregister(reg_pdev); |