aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2010-01-19 14:43:42 -0500
committerDavid S. Miller <davem@davemloft.net>2010-01-19 14:43:42 -0500
commit6373464288cab09bc641be301d8d30fc9f64ba71 (patch)
treec1bc92dc630aa15da2e12bc0d09c92169817a702 /net/wireless/reg.c
parent6d955180b2f9ccff444df06265160868cabb289a (diff)
parent730dd70549e0ec755dd55615ba5cfc38a482a947 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Conflicts: drivers/net/wireless/iwlwifi/iwl-core.h
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r--net/wireless/reg.c319
1 files changed, 291 insertions, 28 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 87ea60d84c3c..5f8071de7950 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -43,6 +43,15 @@
43#include "regdb.h" 43#include "regdb.h"
44#include "nl80211.h" 44#include "nl80211.h"
45 45
46#ifdef CONFIG_CFG80211_REG_DEBUG
47#define REG_DBG_PRINT(format, args...) \
48 do { \
49 printk(KERN_DEBUG format , ## args); \
50 } while (0)
51#else
52#define REG_DBG_PRINT(args...)
53#endif
54
46/* Receipt of information from last regulatory request */ 55/* Receipt of information from last regulatory request */
47static struct regulatory_request *last_request; 56static struct regulatory_request *last_request;
48 57
@@ -476,12 +485,212 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
476} 485}
477 486
478/* 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/*
516 * Some APs may send a country IE triplet for each channel they
517 * support and while this is completely overkill and silly we still
518 * need to support it. We avoid making a single rule for each channel
519 * though and to help us with this we use this helper to find the
520 * actual subband end channel. These type of country IE triplet
521 * scenerios are handled then, all yielding two regulaotry rules from
522 * parsing a country IE:
523 *
524 * [1]
525 * [2]
526 * [36]
527 * [40]
528 *
529 * [1]
530 * [2-4]
531 * [5-12]
532 * [36]
533 * [40-44]
534 *
535 * [1-4]
536 * [5-7]
537 * [36-44]
538 * [48-64]
539 *
540 * [36-36]
541 * [40-40]
542 * [44-44]
543 * [48-48]
544 * [52-52]
545 * [56-56]
546 * [60-60]
547 * [64-64]
548 * [100-100]
549 * [104-104]
550 * [108-108]
551 * [112-112]
552 * [116-116]
553 * [120-120]
554 * [124-124]
555 * [128-128]
556 * [132-132]
557 * [136-136]
558 * [140-140]
559 *
560 * Returns 0 if the IE has been found to be invalid in the middle
561 * somewhere.
562 */
563static int max_subband_chan(enum ieee80211_band band,
564 int orig_cur_chan,
565 int orig_end_channel,
566 s8 orig_max_power,
567 u8 **country_ie,
568 u8 *country_ie_len)
569{
570 u8 *triplets_start = *country_ie;
571 u8 len_at_triplet = *country_ie_len;
572 int end_subband_chan = orig_end_channel;
573
574 /*
575 * We'll deal with padding for the caller unless
576 * its not immediate and we don't process any channels
577 */
578 if (*country_ie_len == 1) {
579 *country_ie += 1;
580 *country_ie_len -= 1;
581 return orig_end_channel;
582 }
583
584 /* Move to the next triplet and then start search */
585 *country_ie += 3;
586 *country_ie_len -= 3;
587
588 if (!chan_in_band(orig_cur_chan, band))
589 return 0;
590
591 while (*country_ie_len >= 3) {
592 int end_channel = 0;
593 struct ieee80211_country_ie_triplet *triplet =
594 (struct ieee80211_country_ie_triplet *) *country_ie;
595 int cur_channel = 0, next_expected_chan;
596
597 /* means last triplet is completely unrelated to this one */
598 if (triplet->ext.reg_extension_id >=
599 IEEE80211_COUNTRY_EXTENSION_ID) {
600 *country_ie -= 3;
601 *country_ie_len += 3;
602 break;
603 }
604
605 if (triplet->chans.first_channel == 0) {
606 *country_ie += 1;
607 *country_ie_len -= 1;
608 if (*country_ie_len != 0)
609 return 0;
610 break;
611 }
612
613 if (triplet->chans.num_channels == 0)
614 return 0;
615
616 /* Monitonically increasing channel order */
617 if (triplet->chans.first_channel <= end_subband_chan)
618 return 0;
619
620 if (!chan_in_band(triplet->chans.first_channel, band))
621 return 0;
622
623 /* 2 GHz */
624 if (triplet->chans.first_channel <= 14) {
625 end_channel = triplet->chans.first_channel +
626 triplet->chans.num_channels - 1;
627 }
628 else {
629 end_channel = triplet->chans.first_channel +
630 (4 * (triplet->chans.num_channels - 1));
631 }
632
633 if (!chan_in_band(end_channel, band))
634 return 0;
635
636 if (orig_max_power != triplet->chans.max_power) {
637 *country_ie -= 3;
638 *country_ie_len += 3;
639 break;
640 }
641
642 cur_channel = triplet->chans.first_channel;
643
644 /* The key is finding the right next expected channel */
645 if (band == IEEE80211_BAND_2GHZ)
646 next_expected_chan = end_subband_chan + 1;
647 else
648 next_expected_chan = end_subband_chan + 4;
649
650 if (cur_channel != next_expected_chan) {
651 *country_ie -= 3;
652 *country_ie_len += 3;
653 break;
654 }
655
656 end_subband_chan = end_channel;
657
658 /* Move to the next one */
659 *country_ie += 3;
660 *country_ie_len -= 3;
661
662 /*
663 * Padding needs to be dealt with if we processed
664 * some channels.
665 */
666 if (*country_ie_len == 1) {
667 *country_ie += 1;
668 *country_ie_len -= 1;
669 break;
670 }
671
672 /* If seen, the IE is invalid */
673 if (*country_ie_len == 2)
674 return 0;
675 }
676
677 if (end_subband_chan == orig_end_channel) {
678 *country_ie = triplets_start;
679 *country_ie_len = len_at_triplet;
680 return orig_end_channel;
681 }
682
683 return end_subband_chan;
684}
685
686/*
479 * Converts a country IE to a regulatory domain. A regulatory domain 687 * Converts a country IE to a regulatory domain. A regulatory domain
480 * structure has a lot of information which the IE doesn't yet have, 688 * structure has a lot of information which the IE doesn't yet have,
481 * so for the other values we use upper max values as we will intersect 689 * so for the other values we use upper max values as we will intersect
482 * with our userspace regulatory agent to get lower bounds. 690 * with our userspace regulatory agent to get lower bounds.
483 */ 691 */
484static struct ieee80211_regdomain *country_ie_2_rd( 692static struct ieee80211_regdomain *country_ie_2_rd(
693 enum ieee80211_band band,
485 u8 *country_ie, 694 u8 *country_ie,
486 u8 country_ie_len, 695 u8 country_ie_len,
487 u32 *checksum) 696 u32 *checksum)
@@ -543,10 +752,29 @@ static struct ieee80211_regdomain *country_ie_2_rd(
543 continue; 752 continue;
544 } 753 }
545 754
755 /*
756 * APs can add padding to make length divisible
757 * by two, required by the spec.
758 */
759 if (triplet->chans.first_channel == 0) {
760 country_ie++;
761 country_ie_len--;
762 /* This is expected to be at the very end only */
763 if (country_ie_len != 0)
764 return NULL;
765 break;
766 }
767
768 if (triplet->chans.num_channels == 0)
769 return NULL;
770
771 if (!chan_in_band(triplet->chans.first_channel, band))
772 return NULL;
773
546 /* 2 GHz */ 774 /* 2 GHz */
547 if (triplet->chans.first_channel <= 14) 775 if (band == IEEE80211_BAND_2GHZ)
548 end_channel = triplet->chans.first_channel + 776 end_channel = triplet->chans.first_channel +
549 triplet->chans.num_channels; 777 triplet->chans.num_channels - 1;
550 else 778 else
551 /* 779 /*
552 * 5 GHz -- For example in country IEs if the first 780 * 5 GHz -- For example in country IEs if the first
@@ -561,6 +789,24 @@ static struct ieee80211_regdomain *country_ie_2_rd(
561 (4 * (triplet->chans.num_channels - 1)); 789 (4 * (triplet->chans.num_channels - 1));
562 790
563 cur_channel = triplet->chans.first_channel; 791 cur_channel = triplet->chans.first_channel;
792
793 /*
794 * Enhancement for APs that send a triplet for every channel
795 * or for whatever reason sends triplets with multiple channels
796 * separated when in fact they should be together.
797 */
798 end_channel = max_subband_chan(band,
799 cur_channel,
800 end_channel,
801 triplet->chans.max_power,
802 &country_ie,
803 &country_ie_len);
804 if (!end_channel)
805 return NULL;
806
807 if (!chan_in_band(end_channel, band))
808 return NULL;
809
564 cur_sub_max_channel = end_channel; 810 cur_sub_max_channel = end_channel;
565 811
566 /* Basic sanity check */ 812 /* Basic sanity check */
@@ -591,10 +837,13 @@ static struct ieee80211_regdomain *country_ie_2_rd(
591 837
592 last_sub_max_channel = cur_sub_max_channel; 838 last_sub_max_channel = cur_sub_max_channel;
593 839
594 country_ie += 3;
595 country_ie_len -= 3;
596 num_rules++; 840 num_rules++;
597 841
842 if (country_ie_len >= 3) {
843 country_ie += 3;
844 country_ie_len -= 3;
845 }
846
598 /* 847 /*
599 * Note: this is not a IEEE requirement but 848 * Note: this is not a IEEE requirement but
600 * simply a memory requirement 849 * simply a memory requirement
@@ -637,6 +886,12 @@ static struct ieee80211_regdomain *country_ie_2_rd(
637 continue; 886 continue;
638 } 887 }
639 888
889 if (triplet->chans.first_channel == 0) {
890 country_ie++;
891 country_ie_len--;
892 break;
893 }
894
640 reg_rule = &rd->reg_rules[i]; 895 reg_rule = &rd->reg_rules[i];
641 freq_range = &reg_rule->freq_range; 896 freq_range = &reg_rule->freq_range;
642 power_rule = &reg_rule->power_rule; 897 power_rule = &reg_rule->power_rule;
@@ -644,13 +899,20 @@ static struct ieee80211_regdomain *country_ie_2_rd(
644 reg_rule->flags = flags; 899 reg_rule->flags = flags;
645 900
646 /* 2 GHz */ 901 /* 2 GHz */
647 if (triplet->chans.first_channel <= 14) 902 if (band == IEEE80211_BAND_2GHZ)
648 end_channel = triplet->chans.first_channel + 903 end_channel = triplet->chans.first_channel +
649 triplet->chans.num_channels; 904 triplet->chans.num_channels -1;
650 else 905 else
651 end_channel = triplet->chans.first_channel + 906 end_channel = triplet->chans.first_channel +
652 (4 * (triplet->chans.num_channels - 1)); 907 (4 * (triplet->chans.num_channels - 1));
653 908
909 end_channel = max_subband_chan(band,
910 triplet->chans.first_channel,
911 end_channel,
912 triplet->chans.max_power,
913 &country_ie,
914 &country_ie_len);
915
654 /* 916 /*
655 * The +10 is since the regulatory domain expects 917 * The +10 is since the regulatory domain expects
656 * the actual band edge, not the center of freq for 918 * the actual band edge, not the center of freq for
@@ -671,12 +933,15 @@ static struct ieee80211_regdomain *country_ie_2_rd(
671 */ 933 */
672 freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); 934 freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40);
673 power_rule->max_antenna_gain = DBI_TO_MBI(100); 935 power_rule->max_antenna_gain = DBI_TO_MBI(100);
674 power_rule->max_eirp = DBM_TO_MBM(100); 936 power_rule->max_eirp = DBM_TO_MBM(triplet->chans.max_power);
675 937
676 country_ie += 3;
677 country_ie_len -= 3;
678 i++; 938 i++;
679 939
940 if (country_ie_len >= 3) {
941 country_ie += 3;
942 country_ie_len -= 3;
943 }
944
680 BUG_ON(i > NL80211_MAX_SUPP_REG_RULES); 945 BUG_ON(i > NL80211_MAX_SUPP_REG_RULES);
681 } 946 }
682 947
@@ -972,25 +1237,21 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
972 if (r == -ERANGE && 1237 if (r == -ERANGE &&
973 last_request->initiator == 1238 last_request->initiator ==
974 NL80211_REGDOM_SET_BY_COUNTRY_IE) { 1239 NL80211_REGDOM_SET_BY_COUNTRY_IE) {
975#ifdef CONFIG_CFG80211_REG_DEBUG 1240 REG_DBG_PRINT("cfg80211: Leaving channel %d MHz "
976 printk(KERN_DEBUG "cfg80211: Leaving channel %d MHz "
977 "intact on %s - no rule found in band on " 1241 "intact on %s - no rule found in band on "
978 "Country IE\n", 1242 "Country IE\n",
979 chan->center_freq, wiphy_name(wiphy)); 1243 chan->center_freq, wiphy_name(wiphy));
980#endif
981 } else { 1244 } else {
982 /* 1245 /*
983 * In this case we know the country IE has at least one reg rule 1246 * In this case we know the country IE has at least one reg rule
984 * for the band so we respect its band definitions 1247 * for the band so we respect its band definitions
985 */ 1248 */
986#ifdef CONFIG_CFG80211_REG_DEBUG
987 if (last_request->initiator == 1249 if (last_request->initiator ==
988 NL80211_REGDOM_SET_BY_COUNTRY_IE) 1250 NL80211_REGDOM_SET_BY_COUNTRY_IE)
989 printk(KERN_DEBUG "cfg80211: Disabling " 1251 REG_DBG_PRINT("cfg80211: Disabling "
990 "channel %d MHz on %s due to " 1252 "channel %d MHz on %s due to "
991 "Country IE\n", 1253 "Country IE\n",
992 chan->center_freq, wiphy_name(wiphy)); 1254 chan->center_freq, wiphy_name(wiphy));
993#endif
994 flags |= IEEE80211_CHAN_DISABLED; 1255 flags |= IEEE80211_CHAN_DISABLED;
995 chan->flags = flags; 1256 chan->flags = flags;
996 } 1257 }
@@ -1685,7 +1946,7 @@ int regulatory_hint_user(const char *alpha2)
1685 request->wiphy_idx = WIPHY_IDX_STALE; 1946 request->wiphy_idx = WIPHY_IDX_STALE;
1686 request->alpha2[0] = alpha2[0]; 1947 request->alpha2[0] = alpha2[0];
1687 request->alpha2[1] = alpha2[1]; 1948 request->alpha2[1] = alpha2[1];
1688 request->initiator = NL80211_REGDOM_SET_BY_USER, 1949 request->initiator = NL80211_REGDOM_SET_BY_USER;
1689 1950
1690 queue_regulatory_request(request); 1951 queue_regulatory_request(request);
1691 1952
@@ -1753,8 +2014,9 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy,
1753 * therefore cannot iterate over the rdev list here. 2014 * therefore cannot iterate over the rdev list here.
1754 */ 2015 */
1755void regulatory_hint_11d(struct wiphy *wiphy, 2016void regulatory_hint_11d(struct wiphy *wiphy,
1756 u8 *country_ie, 2017 enum ieee80211_band band,
1757 u8 country_ie_len) 2018 u8 *country_ie,
2019 u8 country_ie_len)
1758{ 2020{
1759 struct ieee80211_regdomain *rd = NULL; 2021 struct ieee80211_regdomain *rd = NULL;
1760 char alpha2[2]; 2022 char alpha2[2];
@@ -1800,9 +2062,11 @@ void regulatory_hint_11d(struct wiphy *wiphy,
1800 wiphy_idx_valid(last_request->wiphy_idx))) 2062 wiphy_idx_valid(last_request->wiphy_idx)))
1801 goto out; 2063 goto out;
1802 2064
1803 rd = country_ie_2_rd(country_ie, country_ie_len, &checksum); 2065 rd = country_ie_2_rd(band, country_ie, country_ie_len, &checksum);
1804 if (!rd) 2066 if (!rd) {
2067 REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n");
1805 goto out; 2068 goto out;
2069 }
1806 2070
1807 /* 2071 /*
1808 * This will not happen right now but we leave it here for the 2072 * This will not happen right now but we leave it here for the
@@ -1870,13 +2134,12 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
1870 if (!reg_beacon) 2134 if (!reg_beacon)
1871 return -ENOMEM; 2135 return -ENOMEM;
1872 2136
1873#ifdef CONFIG_CFG80211_REG_DEBUG 2137 REG_DBG_PRINT("cfg80211: Found new beacon on "
1874 printk(KERN_DEBUG "cfg80211: Found new beacon on " 2138 "frequency: %d MHz (Ch %d) on %s\n",
1875 "frequency: %d MHz (Ch %d) on %s\n", 2139 beacon_chan->center_freq,
1876 beacon_chan->center_freq, 2140 ieee80211_frequency_to_channel(beacon_chan->center_freq),
1877 ieee80211_frequency_to_channel(beacon_chan->center_freq), 2141 wiphy_name(wiphy));
1878 wiphy_name(wiphy)); 2142
1879#endif
1880 memcpy(&reg_beacon->chan, beacon_chan, 2143 memcpy(&reg_beacon->chan, beacon_chan,
1881 sizeof(struct ieee80211_channel)); 2144 sizeof(struct ieee80211_channel));
1882 2145