aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorLuis R. Rodriguez <lrodriguez@atheros.com>2010-01-14 20:08:20 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-15 17:02:06 -0500
commit84920e3e47f654a22b540606fb8c1ab90b870942 (patch)
tree2df8748b39b9cca53cfd2704487f6183b09d26aa /net/wireless
parent93895757df4ebe22c98b9128b98ebf8cec972c60 (diff)
cfg80211: make regulatory_hint_11d() band specific
In practice APs do not send country IE channel triplets for channels the AP is not operating on and if they were to do so they would have to use the regulatory extension which we currently do not process. No AP has been seen in practice that does this though so just drop those country IEs. Additionally it has been noted the first series of country IE channels triplets are specific to the band the AP sends. Propagate the band on which the country IE was found on reject the country IE then if the triplets are ever oustide of the band. Although we now won't process country IE information with multiple band information we leave the intersection work as is as it is technically possible for someone to want to eventually process these type of country IEs with regulatory extensions. Cc: Jouni Malinen <jouni.malinen@atheros.com> Cc: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/reg.c74
-rw-r--r--net/wireless/reg.h11
-rw-r--r--net/wireless/sme.c1
3 files changed, 66 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 */
497static 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 */
535static int max_subband_chan(int orig_cur_chan, 563static 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 */
668static struct ieee80211_regdomain *country_ie_2_rd( 692static 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 */
1983void regulatory_hint_11d(struct wiphy *wiphy, 2016void 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;
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index 3362c7c069b2..3018508226ab 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -41,14 +41,25 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
41 * regulatory_hint_11d - hints a country IE as a regulatory domain 41 * regulatory_hint_11d - hints a country IE as a regulatory domain
42 * @wiphy: the wireless device giving the hint (used only for reporting 42 * @wiphy: the wireless device giving the hint (used only for reporting
43 * conflicts) 43 * conflicts)
44 * @band: the band on which the country IE was received on. This determines
45 * the band we'll process the country IE channel triplets for.
44 * @country_ie: pointer to the country IE 46 * @country_ie: pointer to the country IE
45 * @country_ie_len: length of the country IE 47 * @country_ie_len: length of the country IE
46 * 48 *
47 * We will intersect the rd with the what CRDA tells us should apply 49 * We will intersect the rd with the what CRDA tells us should apply
48 * for the alpha2 this country IE belongs to, this prevents APs from 50 * for the alpha2 this country IE belongs to, this prevents APs from
49 * sending us incorrect or outdated information against a country. 51 * sending us incorrect or outdated information against a country.
52 *
53 * The AP is expected to provide Country IE channel triplets for the
54 * band it is on. It is technically possible for APs to send channel
55 * country IE triplets even for channels outside of the band they are
56 * in but for that they would have to use the regulatory extension
57 * in combination with a triplet but this behaviour is currently
58 * not observed. For this reason if a triplet is seen with channel
59 * information for a band the BSS is not present in it will be ignored.
50 */ 60 */
51void regulatory_hint_11d(struct wiphy *wiphy, 61void regulatory_hint_11d(struct wiphy *wiphy,
62 enum ieee80211_band band,
52 u8 *country_ie, 63 u8 *country_ie,
53 u8 country_ie_len); 64 u8 country_ie_len);
54 65
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 2333d78187e4..2ce5e1609a3d 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -454,6 +454,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
454 * - and country_ie[1] which is the IE length 454 * - and country_ie[1] which is the IE length
455 */ 455 */
456 regulatory_hint_11d(wdev->wiphy, 456 regulatory_hint_11d(wdev->wiphy,
457 bss->channel->band,
457 country_ie + 2, 458 country_ie + 2,
458 country_ie[1]); 459 country_ie[1]);
459} 460}