aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/wireless/reg.c225
1 files changed, 221 insertions, 4 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 77d0bb6f6e7a..a5c2d3a6cbb2 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -485,6 +485,178 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
485} 485}
486 486
487/* 487/*
488 * Some APs may send a country IE triplet for each channel they
489 * 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
491 * though and to help us with this we use this helper to find the
492 * actual subband end channel. These type of country IE triplet
493 * scenerios are handled then, all yielding two regulaotry rules from
494 * parsing a country IE:
495 *
496 * [1]
497 * [2]
498 * [36]
499 * [40]
500 *
501 * [1]
502 * [2-4]
503 * [5-12]
504 * [36]
505 * [40-44]
506 *
507 * [1-4]
508 * [5-7]
509 * [36-44]
510 * [48-64]
511 *
512 * [36-36]
513 * [40-40]
514 * [44-44]
515 * [48-48]
516 * [52-52]
517 * [56-56]
518 * [60-60]
519 * [64-64]
520 * [100-100]
521 * [104-104]
522 * [108-108]
523 * [112-112]
524 * [116-116]
525 * [120-120]
526 * [124-124]
527 * [128-128]
528 * [132-132]
529 * [136-136]
530 * [140-140]
531 *
532 * Returns 0 if the IE has been found to be invalid in the middle
533 * somewhere.
534 */
535static int max_subband_chan(int orig_cur_chan,
536 int orig_end_channel,
537 s8 orig_max_power,
538 u8 **country_ie,
539 u8 *country_ie_len)
540{
541 u8 *triplets_start = *country_ie;
542 u8 len_at_triplet = *country_ie_len;
543 int end_subband_chan = orig_end_channel;
544 enum ieee80211_band band;
545
546 /*
547 * We'll deal with padding for the caller unless
548 * its not immediate and we don't process any channels
549 */
550 if (*country_ie_len == 1) {
551 *country_ie += 1;
552 *country_ie_len -= 1;
553 return orig_end_channel;
554 }
555
556 /* Move to the next triplet and then start search */
557 *country_ie += 3;
558 *country_ie_len -= 3;
559
560 if (orig_cur_chan <= 14)
561 band = IEEE80211_BAND_2GHZ;
562 else
563 band = IEEE80211_BAND_5GHZ;
564
565 while (*country_ie_len >= 3) {
566 int end_channel = 0;
567 struct ieee80211_country_ie_triplet *triplet =
568 (struct ieee80211_country_ie_triplet *) *country_ie;
569 int cur_channel = 0, next_expected_chan;
570 enum ieee80211_band next_band = IEEE80211_BAND_2GHZ;
571
572 /* means last triplet is completely unrelated to this one */
573 if (triplet->ext.reg_extension_id >=
574 IEEE80211_COUNTRY_EXTENSION_ID) {
575 *country_ie -= 3;
576 *country_ie_len += 3;
577 break;
578 }
579
580 if (triplet->chans.first_channel == 0) {
581 *country_ie += 1;
582 *country_ie_len -= 1;
583 if (*country_ie_len != 0)
584 return 0;
585 break;
586 }
587
588 /* Monitonically increasing channel order */
589 if (triplet->chans.first_channel <= end_subband_chan)
590 return 0;
591
592 /* 2 GHz */
593 if (triplet->chans.first_channel <= 14) {
594 end_channel = triplet->chans.first_channel +
595 triplet->chans.num_channels - 1;
596 }
597 else {
598 end_channel = triplet->chans.first_channel +
599 (4 * (triplet->chans.num_channels - 1));
600 next_band = IEEE80211_BAND_5GHZ;
601 }
602
603 if (band != next_band) {
604 *country_ie -= 3;
605 *country_ie_len += 3;
606 break;
607 }
608
609 if (orig_max_power != triplet->chans.max_power) {
610 *country_ie -= 3;
611 *country_ie_len += 3;
612 break;
613 }
614
615 cur_channel = triplet->chans.first_channel;
616
617 /* The key is finding the right next expected channel */
618 if (band == IEEE80211_BAND_2GHZ)
619 next_expected_chan = end_subband_chan + 1;
620 else
621 next_expected_chan = end_subband_chan + 4;
622
623 if (cur_channel != next_expected_chan) {
624 *country_ie -= 3;
625 *country_ie_len += 3;
626 break;
627 }
628
629 end_subband_chan = end_channel;
630
631 /* Move to the next one */
632 *country_ie += 3;
633 *country_ie_len -= 3;
634
635 /*
636 * Padding needs to be dealt with if we processed
637 * some channels.
638 */
639 if (*country_ie_len == 1) {
640 *country_ie += 1;
641 *country_ie_len -= 1;
642 break;
643 }
644
645 /* If seen, the IE is invalid */
646 if (*country_ie_len == 2)
647 return 0;
648 }
649
650 if (end_subband_chan == orig_end_channel) {
651 *country_ie = triplets_start;
652 *country_ie_len = len_at_triplet;
653 return orig_end_channel;
654 }
655
656 return end_subband_chan;
657}
658
659/*
488 * Converts a country IE to a regulatory domain. A regulatory domain 660 * Converts a country IE to a regulatory domain. A regulatory domain
489 * structure has a lot of information which the IE doesn't yet have, 661 * structure has a lot of information which the IE doesn't yet have,
490 * so for the other values we use upper max values as we will intersect 662 * so for the other values we use upper max values as we will intersect
@@ -552,6 +724,19 @@ static struct ieee80211_regdomain *country_ie_2_rd(
552 continue; 724 continue;
553 } 725 }
554 726
727 /*
728 * APs can add padding to make length divisible
729 * by two, required by the spec.
730 */
731 if (triplet->chans.first_channel == 0) {
732 country_ie++;
733 country_ie_len--;
734 /* This is expected to be at the very end only */
735 if (country_ie_len != 0)
736 return NULL;
737 break;
738 }
739
555 /* 2 GHz */ 740 /* 2 GHz */
556 if (triplet->chans.first_channel <= 14) 741 if (triplet->chans.first_channel <= 14)
557 end_channel = triplet->chans.first_channel + 742 end_channel = triplet->chans.first_channel +
@@ -570,6 +755,20 @@ static struct ieee80211_regdomain *country_ie_2_rd(
570 (4 * (triplet->chans.num_channels - 1)); 755 (4 * (triplet->chans.num_channels - 1));
571 756
572 cur_channel = triplet->chans.first_channel; 757 cur_channel = triplet->chans.first_channel;
758
759 /*
760 * Enhancement for APs that send a triplet for every channel
761 * or for whatever reason sends triplets with multiple channels
762 * separated when in fact they should be together.
763 */
764 end_channel = max_subband_chan(cur_channel,
765 end_channel,
766 triplet->chans.max_power,
767 &country_ie,
768 &country_ie_len);
769 if (!end_channel)
770 return NULL;
771
573 cur_sub_max_channel = end_channel; 772 cur_sub_max_channel = end_channel;
574 773
575 /* Basic sanity check */ 774 /* Basic sanity check */
@@ -600,10 +799,13 @@ static struct ieee80211_regdomain *country_ie_2_rd(
600 799
601 last_sub_max_channel = cur_sub_max_channel; 800 last_sub_max_channel = cur_sub_max_channel;
602 801
603 country_ie += 3;
604 country_ie_len -= 3;
605 num_rules++; 802 num_rules++;
606 803
804 if (country_ie_len >= 3) {
805 country_ie += 3;
806 country_ie_len -= 3;
807 }
808
607 /* 809 /*
608 * Note: this is not a IEEE requirement but 810 * Note: this is not a IEEE requirement but
609 * simply a memory requirement 811 * simply a memory requirement
@@ -646,6 +848,12 @@ static struct ieee80211_regdomain *country_ie_2_rd(
646 continue; 848 continue;
647 } 849 }
648 850
851 if (triplet->chans.first_channel == 0) {
852 country_ie++;
853 country_ie_len--;
854 break;
855 }
856
649 reg_rule = &rd->reg_rules[i]; 857 reg_rule = &rd->reg_rules[i];
650 freq_range = &reg_rule->freq_range; 858 freq_range = &reg_rule->freq_range;
651 power_rule = &reg_rule->power_rule; 859 power_rule = &reg_rule->power_rule;
@@ -660,6 +868,12 @@ static struct ieee80211_regdomain *country_ie_2_rd(
660 end_channel = triplet->chans.first_channel + 868 end_channel = triplet->chans.first_channel +
661 (4 * (triplet->chans.num_channels - 1)); 869 (4 * (triplet->chans.num_channels - 1));
662 870
871 end_channel = max_subband_chan(triplet->chans.first_channel,
872 end_channel,
873 triplet->chans.max_power,
874 &country_ie,
875 &country_ie_len);
876
663 /* 877 /*
664 * The +10 is since the regulatory domain expects 878 * The +10 is since the regulatory domain expects
665 * the actual band edge, not the center of freq for 879 * the actual band edge, not the center of freq for
@@ -682,10 +896,13 @@ static struct ieee80211_regdomain *country_ie_2_rd(
682 power_rule->max_antenna_gain = DBI_TO_MBI(100); 896 power_rule->max_antenna_gain = DBI_TO_MBI(100);
683 power_rule->max_eirp = DBM_TO_MBM(triplet->chans.max_power); 897 power_rule->max_eirp = DBM_TO_MBM(triplet->chans.max_power);
684 898
685 country_ie += 3;
686 country_ie_len -= 3;
687 i++; 899 i++;
688 900
901 if (country_ie_len >= 3) {
902 country_ie += 3;
903 country_ie_len -= 3;
904 }
905
689 BUG_ON(i > NL80211_MAX_SUPP_REG_RULES); 906 BUG_ON(i > NL80211_MAX_SUPP_REG_RULES);
690 } 907 }
691 908