aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r--net/wireless/reg.c142
1 files changed, 128 insertions, 14 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 4f877535e66..85c9034c59b 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -421,6 +421,31 @@ static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range,
421 return 0; 421 return 0;
422} 422}
423 423
424/**
425 * freq_in_rule_band - tells us if a frequency is in a frequency band
426 * @freq_range: frequency rule we want to query
427 * @freq_khz: frequency we are inquiring about
428 *
429 * This lets us know if a specific frequency rule is or is not relevant to
430 * a specific frequency's band. Bands are device specific and artificial
431 * definitions (the "2.4 GHz band" and the "5 GHz band"), however it is
432 * safe for now to assume that a frequency rule should not be part of a
433 * frequency's band if the start freq or end freq are off by more than 2 GHz.
434 * This resolution can be lowered and should be considered as we add
435 * regulatory rule support for other "bands".
436 **/
437static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
438 u32 freq_khz)
439{
440#define ONE_GHZ_IN_KHZ 1000000
441 if (abs(freq_khz - freq_range->start_freq_khz) <= (2 * ONE_GHZ_IN_KHZ))
442 return true;
443 if (abs(freq_khz - freq_range->end_freq_khz) <= (2 * ONE_GHZ_IN_KHZ))
444 return true;
445 return false;
446#undef ONE_GHZ_IN_KHZ
447}
448
424/* Converts a country IE to a regulatory domain. A regulatory domain 449/* Converts a country IE to a regulatory domain. A regulatory domain
425 * structure has a lot of information which the IE doesn't yet have, 450 * structure has a lot of information which the IE doesn't yet have,
426 * so for the other values we use upper max values as we will intersect 451 * so for the other values we use upper max values as we will intersect
@@ -473,6 +498,7 @@ static struct ieee80211_regdomain *country_ie_2_rd(
473 * calculate the number of reg rules we will need. We will need one 498 * calculate the number of reg rules we will need. We will need one
474 * for each channel subband */ 499 * for each channel subband */
475 while (country_ie_len >= 3) { 500 while (country_ie_len >= 3) {
501 int end_channel = 0;
476 struct ieee80211_country_ie_triplet *triplet = 502 struct ieee80211_country_ie_triplet *triplet =
477 (struct ieee80211_country_ie_triplet *) country_ie; 503 (struct ieee80211_country_ie_triplet *) country_ie;
478 int cur_sub_max_channel = 0, cur_channel = 0; 504 int cur_sub_max_channel = 0, cur_channel = 0;
@@ -484,9 +510,25 @@ static struct ieee80211_regdomain *country_ie_2_rd(
484 continue; 510 continue;
485 } 511 }
486 512
513 /* 2 GHz */
514 if (triplet->chans.first_channel <= 14)
515 end_channel = triplet->chans.first_channel +
516 triplet->chans.num_channels;
517 else
518 /*
519 * 5 GHz -- For example in country IEs if the first
520 * channel given is 36 and the number of channels is 4
521 * then the individual channel numbers defined for the
522 * 5 GHz PHY by these parameters are: 36, 40, 44, and 48
523 * and not 36, 37, 38, 39.
524 *
525 * See: http://tinyurl.com/11d-clarification
526 */
527 end_channel = triplet->chans.first_channel +
528 (4 * (triplet->chans.num_channels - 1));
529
487 cur_channel = triplet->chans.first_channel; 530 cur_channel = triplet->chans.first_channel;
488 cur_sub_max_channel = ieee80211_channel_to_frequency( 531 cur_sub_max_channel = end_channel;
489 cur_channel + triplet->chans.num_channels);
490 532
491 /* Basic sanity check */ 533 /* Basic sanity check */
492 if (cur_sub_max_channel < cur_channel) 534 if (cur_sub_max_channel < cur_channel)
@@ -538,6 +580,7 @@ static struct ieee80211_regdomain *country_ie_2_rd(
538 580
539 /* This time around we fill in the rd */ 581 /* This time around we fill in the rd */
540 while (country_ie_len >= 3) { 582 while (country_ie_len >= 3) {
583 int end_channel = 0;
541 struct ieee80211_country_ie_triplet *triplet = 584 struct ieee80211_country_ie_triplet *triplet =
542 (struct ieee80211_country_ie_triplet *) country_ie; 585 (struct ieee80211_country_ie_triplet *) country_ie;
543 struct ieee80211_reg_rule *reg_rule = NULL; 586 struct ieee80211_reg_rule *reg_rule = NULL;
@@ -559,6 +602,14 @@ static struct ieee80211_regdomain *country_ie_2_rd(
559 602
560 reg_rule->flags = flags; 603 reg_rule->flags = flags;
561 604
605 /* 2 GHz */
606 if (triplet->chans.first_channel <= 14)
607 end_channel = triplet->chans.first_channel +
608 triplet->chans.num_channels;
609 else
610 end_channel = triplet->chans.first_channel +
611 (4 * (triplet->chans.num_channels - 1));
612
562 /* The +10 is since the regulatory domain expects 613 /* The +10 is since the regulatory domain expects
563 * the actual band edge, not the center of freq for 614 * the actual band edge, not the center of freq for
564 * its start and end freqs, assuming 20 MHz bandwidth on 615 * its start and end freqs, assuming 20 MHz bandwidth on
@@ -568,8 +619,7 @@ static struct ieee80211_regdomain *country_ie_2_rd(
568 triplet->chans.first_channel) - 10); 619 triplet->chans.first_channel) - 10);
569 freq_range->end_freq_khz = 620 freq_range->end_freq_khz =
570 MHZ_TO_KHZ(ieee80211_channel_to_frequency( 621 MHZ_TO_KHZ(ieee80211_channel_to_frequency(
571 triplet->chans.first_channel + 622 end_channel) + 10);
572 triplet->chans.num_channels) + 10);
573 623
574 /* Large arbitrary values, we intersect later */ 624 /* Large arbitrary values, we intersect later */
575 /* Increment this if we ever support >= 40 MHz channels 625 /* Increment this if we ever support >= 40 MHz channels
@@ -748,12 +798,23 @@ static u32 map_regdom_flags(u32 rd_flags)
748 * this value to the maximum allowed bandwidth. 798 * this value to the maximum allowed bandwidth.
749 * @reg_rule: the regulatory rule which we have for this frequency 799 * @reg_rule: the regulatory rule which we have for this frequency
750 * 800 *
751 * Use this function to get the regulatory rule for a specific frequency. 801 * Use this function to get the regulatory rule for a specific frequency on
802 * a given wireless device. If the device has a specific regulatory domain
803 * it wants to follow we respect that unless a country IE has been received
804 * and processed already.
805 *
806 * Returns 0 if it was able to find a valid regulatory rule which does
807 * apply to the given center_freq otherwise it returns non-zero. It will
808 * also return -ERANGE if we determine the given center_freq does not even have
809 * a regulatory rule for a frequency range in the center_freq's band. See
810 * freq_in_rule_band() for our current definition of a band -- this is purely
811 * subjective and right now its 802.11 specific.
752 */ 812 */
753static int freq_reg_info(u32 center_freq, u32 *bandwidth, 813static int freq_reg_info(u32 center_freq, u32 *bandwidth,
754 const struct ieee80211_reg_rule **reg_rule) 814 const struct ieee80211_reg_rule **reg_rule)
755{ 815{
756 int i; 816 int i;
817 bool band_rule_found = false;
757 u32 max_bandwidth = 0; 818 u32 max_bandwidth = 0;
758 819
759 if (!cfg80211_regdomain) 820 if (!cfg80211_regdomain)
@@ -767,7 +828,15 @@ static int freq_reg_info(u32 center_freq, u32 *bandwidth,
767 rr = &cfg80211_regdomain->reg_rules[i]; 828 rr = &cfg80211_regdomain->reg_rules[i];
768 fr = &rr->freq_range; 829 fr = &rr->freq_range;
769 pr = &rr->power_rule; 830 pr = &rr->power_rule;
831
832 /* We only need to know if one frequency rule was
833 * was in center_freq's band, that's enough, so lets
834 * not overwrite it once found */
835 if (!band_rule_found)
836 band_rule_found = freq_in_rule_band(fr, center_freq);
837
770 max_bandwidth = freq_max_bandwidth(fr, center_freq); 838 max_bandwidth = freq_max_bandwidth(fr, center_freq);
839
771 if (max_bandwidth && *bandwidth <= max_bandwidth) { 840 if (max_bandwidth && *bandwidth <= max_bandwidth) {
772 *reg_rule = rr; 841 *reg_rule = rr;
773 *bandwidth = max_bandwidth; 842 *bandwidth = max_bandwidth;
@@ -775,23 +844,64 @@ static int freq_reg_info(u32 center_freq, u32 *bandwidth,
775 } 844 }
776 } 845 }
777 846
847 if (!band_rule_found)
848 return -ERANGE;
849
778 return !max_bandwidth; 850 return !max_bandwidth;
779} 851}
780 852
781static void handle_channel(struct ieee80211_channel *chan) 853static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
854 unsigned int chan_idx)
782{ 855{
783 int r; 856 int r;
784 u32 flags = chan->orig_flags; 857 u32 flags;
785 u32 max_bandwidth = 0; 858 u32 max_bandwidth = 0;
786 const struct ieee80211_reg_rule *reg_rule = NULL; 859 const struct ieee80211_reg_rule *reg_rule = NULL;
787 const struct ieee80211_power_rule *power_rule = NULL; 860 const struct ieee80211_power_rule *power_rule = NULL;
861 struct ieee80211_supported_band *sband;
862 struct ieee80211_channel *chan;
863
864 sband = wiphy->bands[band];
865 BUG_ON(chan_idx >= sband->n_channels);
866 chan = &sband->channels[chan_idx];
867
868 flags = chan->orig_flags;
788 869
789 r = freq_reg_info(MHZ_TO_KHZ(chan->center_freq), 870 r = freq_reg_info(MHZ_TO_KHZ(chan->center_freq),
790 &max_bandwidth, &reg_rule); 871 &max_bandwidth, &reg_rule);
791 872
792 if (r) { 873 if (r) {
793 flags |= IEEE80211_CHAN_DISABLED; 874 /* This means no regulatory rule was found in the country IE
794 chan->flags = flags; 875 * with a frequency range on the center_freq's band, since
876 * IEEE-802.11 allows for a country IE to have a subset of the
877 * regulatory information provided in a country we ignore
878 * disabling the channel unless at least one reg rule was
879 * found on the center_freq's band. For details see this
880 * clarification:
881 *
882 * http://tinyurl.com/11d-clarification
883 */
884 if (r == -ERANGE &&
885 last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
886#ifdef CONFIG_CFG80211_REG_DEBUG
887 printk(KERN_DEBUG "cfg80211: Leaving channel %d MHz "
888 "intact on %s - no rule found in band on "
889 "Country IE\n",
890 chan->center_freq, wiphy_name(wiphy));
891#endif
892 } else {
893 /* In this case we know the country IE has at least one reg rule
894 * for the band so we respect its band definitions */
895#ifdef CONFIG_CFG80211_REG_DEBUG
896 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
897 printk(KERN_DEBUG "cfg80211: Disabling "
898 "channel %d MHz on %s due to "
899 "Country IE\n",
900 chan->center_freq, wiphy_name(wiphy));
901#endif
902 flags |= IEEE80211_CHAN_DISABLED;
903 chan->flags = flags;
904 }
795 return; 905 return;
796 } 906 }
797 907
@@ -808,12 +918,16 @@ static void handle_channel(struct ieee80211_channel *chan)
808 chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); 918 chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);
809} 919}
810 920
811static void handle_band(struct ieee80211_supported_band *sband) 921static void handle_band(struct wiphy *wiphy, enum ieee80211_band band)
812{ 922{
813 int i; 923 unsigned int i;
924 struct ieee80211_supported_band *sband;
925
926 BUG_ON(!wiphy->bands[band]);
927 sband = wiphy->bands[band];
814 928
815 for (i = 0; i < sband->n_channels; i++) 929 for (i = 0; i < sband->n_channels; i++)
816 handle_channel(&sband->channels[i]); 930 handle_channel(wiphy, band, i);
817} 931}
818 932
819static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby) 933static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby)
@@ -840,7 +954,7 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
840 enum ieee80211_band band; 954 enum ieee80211_band band;
841 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 955 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
842 if (wiphy->bands[band]) 956 if (wiphy->bands[band])
843 handle_band(wiphy->bands[band]); 957 handle_band(wiphy, band);
844 if (wiphy->reg_notifier) 958 if (wiphy->reg_notifier)
845 wiphy->reg_notifier(wiphy, setby); 959 wiphy->reg_notifier(wiphy, setby);
846 } 960 }
@@ -1170,7 +1284,7 @@ static void reg_country_ie_process_debug(
1170 if (intersected_rd) { 1284 if (intersected_rd) {
1171 printk(KERN_DEBUG "cfg80211: We intersect both of these " 1285 printk(KERN_DEBUG "cfg80211: We intersect both of these "
1172 "and get:\n"); 1286 "and get:\n");
1173 print_regdomain_info(rd); 1287 print_regdomain_info(intersected_rd);
1174 return; 1288 return;
1175 } 1289 }
1176 printk(KERN_DEBUG "cfg80211: Intersection between both failed\n"); 1290 printk(KERN_DEBUG "cfg80211: Intersection between both failed\n");