diff options
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r-- | net/wireless/reg.c | 74 |
1 files changed, 54 insertions, 20 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f3b77f7b8e3d..5f8071de7950 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -485,6 +485,34 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, | |||
485 | } | 485 | } |
486 | 486 | ||
487 | /* | 487 | /* |
488 | * This is a work around for sanity checking ieee80211_channel_to_frequency()'s | ||
489 | * work. ieee80211_channel_to_frequency() can for example currently provide a | ||
490 | * 2 GHz channel when in fact a 5 GHz channel was desired. An example would be | ||
491 | * an AP providing channel 8 on a country IE triplet when it sent this on the | ||
492 | * 5 GHz band, that channel is designed to be channel 8 on 5 GHz, not a 2 GHz | ||
493 | * channel. | ||
494 | * | ||
495 | * This can be removed once ieee80211_channel_to_frequency() takes in a band. | ||
496 | */ | ||
497 | static bool chan_in_band(int chan, enum ieee80211_band band) | ||
498 | { | ||
499 | int center_freq = ieee80211_channel_to_frequency(chan); | ||
500 | |||
501 | switch (band) { | ||
502 | case IEEE80211_BAND_2GHZ: | ||
503 | if (center_freq <= 2484) | ||
504 | return true; | ||
505 | return false; | ||
506 | case IEEE80211_BAND_5GHZ: | ||
507 | if (center_freq >= 5005) | ||
508 | return true; | ||
509 | return false; | ||
510 | default: | ||
511 | return false; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | /* | ||
488 | * Some APs may send a country IE triplet for each channel they | 516 | * Some APs may send a country IE triplet for each channel they |
489 | * support and while this is completely overkill and silly we still | 517 | * support and while this is completely overkill and silly we still |
490 | * need to support it. We avoid making a single rule for each channel | 518 | * need to support it. We avoid making a single rule for each channel |
@@ -532,7 +560,8 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, | |||
532 | * Returns 0 if the IE has been found to be invalid in the middle | 560 | * Returns 0 if the IE has been found to be invalid in the middle |
533 | * somewhere. | 561 | * somewhere. |
534 | */ | 562 | */ |
535 | static int max_subband_chan(int orig_cur_chan, | 563 | static int max_subband_chan(enum ieee80211_band band, |
564 | int orig_cur_chan, | ||
536 | int orig_end_channel, | 565 | int orig_end_channel, |
537 | s8 orig_max_power, | 566 | s8 orig_max_power, |
538 | u8 **country_ie, | 567 | u8 **country_ie, |
@@ -541,7 +570,6 @@ static int max_subband_chan(int orig_cur_chan, | |||
541 | u8 *triplets_start = *country_ie; | 570 | u8 *triplets_start = *country_ie; |
542 | u8 len_at_triplet = *country_ie_len; | 571 | u8 len_at_triplet = *country_ie_len; |
543 | int end_subband_chan = orig_end_channel; | 572 | int end_subband_chan = orig_end_channel; |
544 | enum ieee80211_band band; | ||
545 | 573 | ||
546 | /* | 574 | /* |
547 | * We'll deal with padding for the caller unless | 575 | * We'll deal with padding for the caller unless |
@@ -557,17 +585,14 @@ static int max_subband_chan(int orig_cur_chan, | |||
557 | *country_ie += 3; | 585 | *country_ie += 3; |
558 | *country_ie_len -= 3; | 586 | *country_ie_len -= 3; |
559 | 587 | ||
560 | if (orig_cur_chan <= 14) | 588 | if (!chan_in_band(orig_cur_chan, band)) |
561 | band = IEEE80211_BAND_2GHZ; | 589 | return 0; |
562 | else | ||
563 | band = IEEE80211_BAND_5GHZ; | ||
564 | 590 | ||
565 | while (*country_ie_len >= 3) { | 591 | while (*country_ie_len >= 3) { |
566 | int end_channel = 0; | 592 | int end_channel = 0; |
567 | struct ieee80211_country_ie_triplet *triplet = | 593 | struct ieee80211_country_ie_triplet *triplet = |
568 | (struct ieee80211_country_ie_triplet *) *country_ie; | 594 | (struct ieee80211_country_ie_triplet *) *country_ie; |
569 | int cur_channel = 0, next_expected_chan; | 595 | int cur_channel = 0, next_expected_chan; |
570 | enum ieee80211_band next_band = IEEE80211_BAND_2GHZ; | ||
571 | 596 | ||
572 | /* means last triplet is completely unrelated to this one */ | 597 | /* means last triplet is completely unrelated to this one */ |
573 | if (triplet->ext.reg_extension_id >= | 598 | if (triplet->ext.reg_extension_id >= |
@@ -592,6 +617,9 @@ static int max_subband_chan(int orig_cur_chan, | |||
592 | if (triplet->chans.first_channel <= end_subband_chan) | 617 | if (triplet->chans.first_channel <= end_subband_chan) |
593 | return 0; | 618 | return 0; |
594 | 619 | ||
620 | if (!chan_in_band(triplet->chans.first_channel, band)) | ||
621 | return 0; | ||
622 | |||
595 | /* 2 GHz */ | 623 | /* 2 GHz */ |
596 | if (triplet->chans.first_channel <= 14) { | 624 | if (triplet->chans.first_channel <= 14) { |
597 | end_channel = triplet->chans.first_channel + | 625 | end_channel = triplet->chans.first_channel + |
@@ -600,14 +628,10 @@ static int max_subband_chan(int orig_cur_chan, | |||
600 | else { | 628 | else { |
601 | end_channel = triplet->chans.first_channel + | 629 | end_channel = triplet->chans.first_channel + |
602 | (4 * (triplet->chans.num_channels - 1)); | 630 | (4 * (triplet->chans.num_channels - 1)); |
603 | next_band = IEEE80211_BAND_5GHZ; | ||
604 | } | 631 | } |
605 | 632 | ||
606 | if (band != next_band) { | 633 | if (!chan_in_band(end_channel, band)) |
607 | *country_ie -= 3; | 634 | return 0; |
608 | *country_ie_len += 3; | ||
609 | break; | ||
610 | } | ||
611 | 635 | ||
612 | if (orig_max_power != triplet->chans.max_power) { | 636 | if (orig_max_power != triplet->chans.max_power) { |
613 | *country_ie -= 3; | 637 | *country_ie -= 3; |
@@ -666,6 +690,7 @@ static int max_subband_chan(int orig_cur_chan, | |||
666 | * with our userspace regulatory agent to get lower bounds. | 690 | * with our userspace regulatory agent to get lower bounds. |
667 | */ | 691 | */ |
668 | static struct ieee80211_regdomain *country_ie_2_rd( | 692 | static struct ieee80211_regdomain *country_ie_2_rd( |
693 | enum ieee80211_band band, | ||
669 | u8 *country_ie, | 694 | u8 *country_ie, |
670 | u8 country_ie_len, | 695 | u8 country_ie_len, |
671 | u32 *checksum) | 696 | u32 *checksum) |
@@ -743,8 +768,11 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
743 | if (triplet->chans.num_channels == 0) | 768 | if (triplet->chans.num_channels == 0) |
744 | return NULL; | 769 | return NULL; |
745 | 770 | ||
771 | if (!chan_in_band(triplet->chans.first_channel, band)) | ||
772 | return NULL; | ||
773 | |||
746 | /* 2 GHz */ | 774 | /* 2 GHz */ |
747 | if (triplet->chans.first_channel <= 14) | 775 | if (band == IEEE80211_BAND_2GHZ) |
748 | end_channel = triplet->chans.first_channel + | 776 | end_channel = triplet->chans.first_channel + |
749 | triplet->chans.num_channels - 1; | 777 | triplet->chans.num_channels - 1; |
750 | else | 778 | else |
@@ -767,7 +795,8 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
767 | * or for whatever reason sends triplets with multiple channels | 795 | * or for whatever reason sends triplets with multiple channels |
768 | * separated when in fact they should be together. | 796 | * separated when in fact they should be together. |
769 | */ | 797 | */ |
770 | end_channel = max_subband_chan(cur_channel, | 798 | end_channel = max_subband_chan(band, |
799 | cur_channel, | ||
771 | end_channel, | 800 | end_channel, |
772 | triplet->chans.max_power, | 801 | triplet->chans.max_power, |
773 | &country_ie, | 802 | &country_ie, |
@@ -775,6 +804,9 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
775 | if (!end_channel) | 804 | if (!end_channel) |
776 | return NULL; | 805 | return NULL; |
777 | 806 | ||
807 | if (!chan_in_band(end_channel, band)) | ||
808 | return NULL; | ||
809 | |||
778 | cur_sub_max_channel = end_channel; | 810 | cur_sub_max_channel = end_channel; |
779 | 811 | ||
780 | /* Basic sanity check */ | 812 | /* Basic sanity check */ |
@@ -867,14 +899,15 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
867 | reg_rule->flags = flags; | 899 | reg_rule->flags = flags; |
868 | 900 | ||
869 | /* 2 GHz */ | 901 | /* 2 GHz */ |
870 | if (triplet->chans.first_channel <= 14) | 902 | if (band == IEEE80211_BAND_2GHZ) |
871 | end_channel = triplet->chans.first_channel + | 903 | end_channel = triplet->chans.first_channel + |
872 | triplet->chans.num_channels -1; | 904 | triplet->chans.num_channels -1; |
873 | else | 905 | else |
874 | end_channel = triplet->chans.first_channel + | 906 | end_channel = triplet->chans.first_channel + |
875 | (4 * (triplet->chans.num_channels - 1)); | 907 | (4 * (triplet->chans.num_channels - 1)); |
876 | 908 | ||
877 | end_channel = max_subband_chan(triplet->chans.first_channel, | 909 | end_channel = max_subband_chan(band, |
910 | triplet->chans.first_channel, | ||
878 | end_channel, | 911 | end_channel, |
879 | triplet->chans.max_power, | 912 | triplet->chans.max_power, |
880 | &country_ie, | 913 | &country_ie, |
@@ -1981,8 +2014,9 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy, | |||
1981 | * therefore cannot iterate over the rdev list here. | 2014 | * therefore cannot iterate over the rdev list here. |
1982 | */ | 2015 | */ |
1983 | void regulatory_hint_11d(struct wiphy *wiphy, | 2016 | void regulatory_hint_11d(struct wiphy *wiphy, |
1984 | u8 *country_ie, | 2017 | enum ieee80211_band band, |
1985 | u8 country_ie_len) | 2018 | u8 *country_ie, |
2019 | u8 country_ie_len) | ||
1986 | { | 2020 | { |
1987 | struct ieee80211_regdomain *rd = NULL; | 2021 | struct ieee80211_regdomain *rd = NULL; |
1988 | char alpha2[2]; | 2022 | char alpha2[2]; |
@@ -2028,7 +2062,7 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
2028 | wiphy_idx_valid(last_request->wiphy_idx))) | 2062 | wiphy_idx_valid(last_request->wiphy_idx))) |
2029 | goto out; | 2063 | goto out; |
2030 | 2064 | ||
2031 | rd = country_ie_2_rd(country_ie, country_ie_len, &checksum); | 2065 | rd = country_ie_2_rd(band, country_ie, country_ie_len, &checksum); |
2032 | if (!rd) { | 2066 | if (!rd) { |
2033 | REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n"); | 2067 | REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n"); |
2034 | goto out; | 2068 | goto out; |