diff options
Diffstat (limited to 'net/wireless/reg.c')
| -rw-r--r-- | net/wireless/reg.c | 668 |
1 files changed, 10 insertions, 658 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 8f0d97dd3109..f180db0de66c 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
| @@ -67,20 +67,12 @@ 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 | DEFINE_MUTEX(reg_mutex); | 75 | static DEFINE_MUTEX(reg_mutex); |
| 84 | #define assert_reg_lock() WARN_ON(!mutex_is_locked(®_mutex)) | 76 | #define assert_reg_lock() WARN_ON(!mutex_is_locked(®_mutex)) |
| 85 | 77 | ||
| 86 | /* Used to queue up regulatory hints */ | 78 | /* Used to queue up regulatory hints */ |
| @@ -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; |
| @@ -1831,6 +1306,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
| 1831 | { | 1306 | { |
| 1832 | int r = 0; | 1307 | int r = 0; |
| 1833 | struct wiphy *wiphy = NULL; | 1308 | struct wiphy *wiphy = NULL; |
| 1309 | enum nl80211_reg_initiator initiator = reg_request->initiator; | ||
| 1834 | 1310 | ||
| 1835 | BUG_ON(!reg_request->alpha2); | 1311 | BUG_ON(!reg_request->alpha2); |
| 1836 | 1312 | ||
| @@ -1850,7 +1326,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
| 1850 | /* This is required so that the orig_* parameters are saved */ | 1326 | /* This is required so that the orig_* parameters are saved */ |
| 1851 | if (r == -EALREADY && wiphy && | 1327 | if (r == -EALREADY && wiphy && |
| 1852 | wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) | 1328 | wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) |
| 1853 | wiphy_update_regulatory(wiphy, reg_request->initiator); | 1329 | wiphy_update_regulatory(wiphy, initiator); |
| 1854 | out: | 1330 | out: |
| 1855 | mutex_unlock(®_mutex); | 1331 | mutex_unlock(®_mutex); |
| 1856 | mutex_unlock(&cfg80211_mutex); | 1332 | mutex_unlock(&cfg80211_mutex); |
| @@ -2008,35 +1484,6 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2) | |||
| 2008 | } | 1484 | } |
| 2009 | EXPORT_SYMBOL(regulatory_hint); | 1485 | EXPORT_SYMBOL(regulatory_hint); |
| 2010 | 1486 | ||
| 2011 | /* Caller must hold reg_mutex */ | ||
| 2012 | static bool reg_same_country_ie_hint(struct wiphy *wiphy, | ||
| 2013 | u32 country_ie_checksum) | ||
| 2014 | { | ||
| 2015 | struct wiphy *request_wiphy; | ||
| 2016 | |||
| 2017 | assert_reg_lock(); | ||
| 2018 | |||
| 2019 | if (unlikely(last_request->initiator != | ||
| 2020 | NL80211_REGDOM_SET_BY_COUNTRY_IE)) | ||
| 2021 | return false; | ||
| 2022 | |||
| 2023 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | ||
| 2024 | |||
| 2025 | if (!request_wiphy) | ||
| 2026 | return false; | ||
| 2027 | |||
| 2028 | if (likely(request_wiphy != wiphy)) | ||
| 2029 | return !country_ie_integrity_changes(country_ie_checksum); | ||
| 2030 | /* | ||
| 2031 | * We should not have let these through at this point, they | ||
| 2032 | * should have been picked up earlier by the first alpha2 check | ||
| 2033 | * on the device | ||
| 2034 | */ | ||
| 2035 | if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum))) | ||
| 2036 | return true; | ||
| 2037 | return false; | ||
| 2038 | } | ||
| 2039 | |||
| 2040 | /* | 1487 | /* |
| 2041 | * We hold wdev_lock() here so we cannot hold cfg80211_mutex() and | 1488 | * We hold wdev_lock() here so we cannot hold cfg80211_mutex() and |
| 2042 | * therefore cannot iterate over the rdev list here. | 1489 | * therefore cannot iterate over the rdev list here. |
| @@ -2046,9 +1493,7 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
| 2046 | u8 *country_ie, | 1493 | u8 *country_ie, |
| 2047 | u8 country_ie_len) | 1494 | u8 country_ie_len) |
| 2048 | { | 1495 | { |
| 2049 | struct ieee80211_regdomain *rd = NULL; | ||
| 2050 | char alpha2[2]; | 1496 | char alpha2[2]; |
| 2051 | u32 checksum = 0; | ||
| 2052 | enum environment_cap env = ENVIRON_ANY; | 1497 | enum environment_cap env = ENVIRON_ANY; |
| 2053 | struct regulatory_request *request; | 1498 | struct regulatory_request *request; |
| 2054 | 1499 | ||
| @@ -2064,14 +1509,6 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
| 2064 | if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) | 1509 | if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) |
| 2065 | goto out; | 1510 | goto out; |
| 2066 | 1511 | ||
| 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]; | 1512 | alpha2[0] = country_ie[0]; |
| 2076 | alpha2[1] = country_ie[1]; | 1513 | alpha2[1] = country_ie[1]; |
| 2077 | 1514 | ||
| @@ -2090,39 +1527,14 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
| 2090 | wiphy_idx_valid(last_request->wiphy_idx))) | 1527 | wiphy_idx_valid(last_request->wiphy_idx))) |
| 2091 | goto out; | 1528 | goto out; |
| 2092 | 1529 | ||
| 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 | /* | ||
| 2100 | * 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 | ||
| 2102 | * the user move to another country after doing so, or having the user | ||
| 2103 | * move to another AP. Right now we just trust the first AP. | ||
| 2104 | * | ||
| 2105 | * 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 | ||
| 2107 | */ | ||
| 2108 | if (WARN_ON(reg_same_country_ie_hint(wiphy, checksum))) | ||
| 2109 | goto free_rd_out; | ||
| 2110 | |||
| 2111 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); | 1530 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); |
| 2112 | if (!request) | 1531 | if (!request) |
| 2113 | goto free_rd_out; | 1532 | goto out; |
| 2114 | |||
| 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 | 1533 | ||
| 2121 | request->wiphy_idx = get_wiphy_idx(wiphy); | 1534 | request->wiphy_idx = get_wiphy_idx(wiphy); |
| 2122 | request->alpha2[0] = rd->alpha2[0]; | 1535 | request->alpha2[0] = alpha2[0]; |
| 2123 | request->alpha2[1] = rd->alpha2[1]; | 1536 | request->alpha2[1] = alpha2[1]; |
| 2124 | request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE; | 1537 | request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE; |
| 2125 | request->country_ie_checksum = checksum; | ||
| 2126 | request->country_ie_env = env; | 1538 | request->country_ie_env = env; |
| 2127 | 1539 | ||
| 2128 | mutex_unlock(®_mutex); | 1540 | mutex_unlock(®_mutex); |
| @@ -2131,8 +1543,6 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
| 2131 | 1543 | ||
| 2132 | return; | 1544 | return; |
| 2133 | 1545 | ||
| 2134 | free_rd_out: | ||
| 2135 | kfree(rd); | ||
| 2136 | out: | 1546 | out: |
| 2137 | mutex_unlock(®_mutex); | 1547 | mutex_unlock(®_mutex); |
| 2138 | } | 1548 | } |
| @@ -2383,33 +1793,6 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd) | |||
| 2383 | print_rd_rules(rd); | 1793 | print_rd_rules(rd); |
| 2384 | } | 1794 | } |
| 2385 | 1795 | ||
| 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 */ | 1796 | /* Takes ownership of rd only if it doesn't fail */ |
| 2414 | static int __set_regdom(const struct ieee80211_regdomain *rd) | 1797 | static int __set_regdom(const struct ieee80211_regdomain *rd) |
| 2415 | { | 1798 | { |
| @@ -2521,34 +1904,6 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
| 2521 | return 0; | 1904 | return 0; |
| 2522 | } | 1905 | } |
| 2523 | 1906 | ||
| 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) | 1907 | if (!intersected_rd) |
| 2553 | return -EINVAL; | 1908 | return -EINVAL; |
| 2554 | 1909 | ||
| @@ -2630,7 +1985,7 @@ out: | |||
| 2630 | mutex_unlock(®_mutex); | 1985 | mutex_unlock(®_mutex); |
| 2631 | } | 1986 | } |
| 2632 | 1987 | ||
| 2633 | int regulatory_init(void) | 1988 | int __init regulatory_init(void) |
| 2634 | { | 1989 | { |
| 2635 | int err = 0; | 1990 | int err = 0; |
| 2636 | 1991 | ||
| @@ -2676,7 +2031,7 @@ int regulatory_init(void) | |||
| 2676 | return 0; | 2031 | return 0; |
| 2677 | } | 2032 | } |
| 2678 | 2033 | ||
| 2679 | void regulatory_exit(void) | 2034 | void /* __init_or_exit */ regulatory_exit(void) |
| 2680 | { | 2035 | { |
| 2681 | struct regulatory_request *reg_request, *tmp; | 2036 | struct regulatory_request *reg_request, *tmp; |
| 2682 | struct reg_beacon *reg_beacon, *btmp; | 2037 | struct reg_beacon *reg_beacon, *btmp; |
| @@ -2688,9 +2043,6 @@ void regulatory_exit(void) | |||
| 2688 | 2043 | ||
| 2689 | reset_regdomains(); | 2044 | reset_regdomains(); |
| 2690 | 2045 | ||
| 2691 | kfree(country_ie_regdomain); | ||
| 2692 | country_ie_regdomain = NULL; | ||
| 2693 | |||
| 2694 | kfree(last_request); | 2046 | kfree(last_request); |
| 2695 | 2047 | ||
| 2696 | platform_device_unregister(reg_pdev); | 2048 | platform_device_unregister(reg_pdev); |
