aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
authorJanusz Dziedzic <janusz.dziedzic@tieto.com>2014-01-30 03:52:20 -0500
committerJohannes Berg <johannes.berg@intel.com>2014-02-05 08:03:19 -0500
commit9752482083066af7ac18a5ca376ff35d72418b29 (patch)
tree729d143ac4c3de4eba5a84945a78058209df814a /net/wireless/reg.c
parent9e0e29615a2077be852b1245b57c5b00fa609522 (diff)
cfg80211: regulatory introduce maximum bandwidth calculation
In case we will get regulatory request with rule where max_bandwidth_khz is set to 0 handle this case as a special one. If max_bandwidth_khz == 0 we should calculate maximum available bandwidth base on all frequency contiguous rules. In case we need auto calculation we just have to set: country PL: DFS-ETSI (2402 - 2482 @ 40), (N/A, 20) (5170 - 5250 @ AUTO), (N/A, 20) (5250 - 5330 @ AUTO), (N/A, 20), DFS (5490 - 5710 @ 80), (N/A, 27), DFS This mean we will calculate maximum bw for rules where AUTO (N/A) were set, 160MHz (5330 - 5170) in example above. So we will get: (5170 - 5250 @ 160), (N/A, 20) (5250 - 5330 @ 160), (N/A, 20), DFS In other case: country FR: DFS-ETSI (2402 - 2482 @ 40), (N/A, 20) (5170 - 5250 @ AUTO), (N/A, 20) (5250 - 5330 @ 80), (N/A, 20), DFS (5490 - 5710 @ 80), (N/A, 27), DFS We will get 80MHz (5250 - 5170): (5170 - 5250 @ 80), (N/A, 20) (5250 - 5330 @ 80), (N/A, 20), DFS Base on this calculations we will set correct channel bandwidth flags (eg. IEEE80211_CHAN_NO_80MHZ). We don't need any changes in CRDA or internal regulatory. Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com> [extend nl80211 description a bit, fix typo] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r--net/wireless/reg.c130
1 files changed, 114 insertions, 16 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 27807bf0cdfc..27c5253e7a61 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -538,6 +538,61 @@ static const struct ieee80211_regdomain *reg_get_regdomain(struct wiphy *wiphy)
538 return get_cfg80211_regdom(); 538 return get_cfg80211_regdom();
539} 539}
540 540
541unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
542 const struct ieee80211_reg_rule *rule)
543{
544 const struct ieee80211_freq_range *freq_range = &rule->freq_range;
545 const struct ieee80211_freq_range *freq_range_tmp;
546 const struct ieee80211_reg_rule *tmp;
547 u32 start_freq, end_freq, idx, no;
548
549 for (idx = 0; idx < rd->n_reg_rules; idx++)
550 if (rule == &rd->reg_rules[idx])
551 break;
552
553 if (idx == rd->n_reg_rules)
554 return 0;
555
556 /* get start_freq */
557 no = idx;
558
559 while (no) {
560 tmp = &rd->reg_rules[--no];
561 freq_range_tmp = &tmp->freq_range;
562
563 if (freq_range_tmp->end_freq_khz < freq_range->start_freq_khz)
564 break;
565
566 if (freq_range_tmp->max_bandwidth_khz)
567 break;
568
569 freq_range = freq_range_tmp;
570 }
571
572 start_freq = freq_range->start_freq_khz;
573
574 /* get end_freq */
575 freq_range = &rule->freq_range;
576 no = idx;
577
578 while (no < rd->n_reg_rules - 1) {
579 tmp = &rd->reg_rules[++no];
580 freq_range_tmp = &tmp->freq_range;
581
582 if (freq_range_tmp->start_freq_khz > freq_range->end_freq_khz)
583 break;
584
585 if (freq_range_tmp->max_bandwidth_khz)
586 break;
587
588 freq_range = freq_range_tmp;
589 }
590
591 end_freq = freq_range->end_freq_khz;
592
593 return end_freq - start_freq;
594}
595
541/* Sanity check on a regulatory rule */ 596/* Sanity check on a regulatory rule */
542static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) 597static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
543{ 598{
@@ -646,7 +701,9 @@ reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1,
646 * Helper for regdom_intersect(), this does the real 701 * Helper for regdom_intersect(), this does the real
647 * mathematical intersection fun 702 * mathematical intersection fun
648 */ 703 */
649static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1, 704static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
705 const struct ieee80211_regdomain *rd2,
706 const struct ieee80211_reg_rule *rule1,
650 const struct ieee80211_reg_rule *rule2, 707 const struct ieee80211_reg_rule *rule2,
651 struct ieee80211_reg_rule *intersected_rule) 708 struct ieee80211_reg_rule *intersected_rule)
652{ 709{
@@ -654,7 +711,7 @@ static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1,
654 struct ieee80211_freq_range *freq_range; 711 struct ieee80211_freq_range *freq_range;
655 const struct ieee80211_power_rule *power_rule1, *power_rule2; 712 const struct ieee80211_power_rule *power_rule1, *power_rule2;
656 struct ieee80211_power_rule *power_rule; 713 struct ieee80211_power_rule *power_rule;
657 u32 freq_diff; 714 u32 freq_diff, max_bandwidth1, max_bandwidth2;
658 715
659 freq_range1 = &rule1->freq_range; 716 freq_range1 = &rule1->freq_range;
660 freq_range2 = &rule2->freq_range; 717 freq_range2 = &rule2->freq_range;
@@ -668,8 +725,24 @@ static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1,
668 freq_range2->start_freq_khz); 725 freq_range2->start_freq_khz);
669 freq_range->end_freq_khz = min(freq_range1->end_freq_khz, 726 freq_range->end_freq_khz = min(freq_range1->end_freq_khz,
670 freq_range2->end_freq_khz); 727 freq_range2->end_freq_khz);
671 freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz, 728
672 freq_range2->max_bandwidth_khz); 729 max_bandwidth1 = freq_range1->max_bandwidth_khz;
730 max_bandwidth2 = freq_range2->max_bandwidth_khz;
731
732 /*
733 * In case max_bandwidth1 == 0 and max_bandwith2 == 0 set
734 * output bandwidth as 0 (auto calculation). Next we will
735 * calculate this correctly in handle_channel function.
736 * In other case calculate output bandwidth here.
737 */
738 if (max_bandwidth1 || max_bandwidth2) {
739 if (!max_bandwidth1)
740 max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1);
741 if (!max_bandwidth2)
742 max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2);
743 }
744
745 freq_range->max_bandwidth_khz = min(max_bandwidth1, max_bandwidth2);
673 746
674 freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; 747 freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
675 if (freq_range->max_bandwidth_khz > freq_diff) 748 if (freq_range->max_bandwidth_khz > freq_diff)
@@ -729,7 +802,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
729 rule1 = &rd1->reg_rules[x]; 802 rule1 = &rd1->reg_rules[x];
730 for (y = 0; y < rd2->n_reg_rules; y++) { 803 for (y = 0; y < rd2->n_reg_rules; y++) {
731 rule2 = &rd2->reg_rules[y]; 804 rule2 = &rd2->reg_rules[y];
732 if (!reg_rules_intersect(rule1, rule2, &dummy_rule)) 805 if (!reg_rules_intersect(rd1, rd2, rule1, rule2,
806 &dummy_rule))
733 num_rules++; 807 num_rules++;
734 } 808 }
735 } 809 }
@@ -754,7 +828,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
754 * a memcpy() 828 * a memcpy()
755 */ 829 */
756 intersected_rule = &rd->reg_rules[rule_idx]; 830 intersected_rule = &rd->reg_rules[rule_idx];
757 r = reg_rules_intersect(rule1, rule2, intersected_rule); 831 r = reg_rules_intersect(rd1, rd2, rule1, rule2,
832 intersected_rule);
758 /* 833 /*
759 * No need to memset here the intersected rule here as 834 * No need to memset here the intersected rule here as
760 * we're not using the stack anymore 835 * we're not using the stack anymore
@@ -909,6 +984,8 @@ static void handle_channel(struct wiphy *wiphy,
909 const struct ieee80211_freq_range *freq_range = NULL; 984 const struct ieee80211_freq_range *freq_range = NULL;
910 struct wiphy *request_wiphy = NULL; 985 struct wiphy *request_wiphy = NULL;
911 struct regulatory_request *lr = get_last_request(); 986 struct regulatory_request *lr = get_last_request();
987 const struct ieee80211_regdomain *regd;
988 u32 max_bandwidth_khz;
912 989
913 request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); 990 request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
914 991
@@ -950,11 +1027,18 @@ static void handle_channel(struct wiphy *wiphy,
950 power_rule = &reg_rule->power_rule; 1027 power_rule = &reg_rule->power_rule;
951 freq_range = &reg_rule->freq_range; 1028 freq_range = &reg_rule->freq_range;
952 1029
953 if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) 1030 max_bandwidth_khz = freq_range->max_bandwidth_khz;
1031 /* Check if auto calculation requested */
1032 if (!max_bandwidth_khz) {
1033 regd = reg_get_regdomain(wiphy);
1034 max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
1035 }
1036
1037 if (max_bandwidth_khz < MHZ_TO_KHZ(40))
954 bw_flags = IEEE80211_CHAN_NO_HT40; 1038 bw_flags = IEEE80211_CHAN_NO_HT40;
955 if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80)) 1039 if (max_bandwidth_khz < MHZ_TO_KHZ(80))
956 bw_flags |= IEEE80211_CHAN_NO_80MHZ; 1040 bw_flags |= IEEE80211_CHAN_NO_80MHZ;
957 if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160)) 1041 if (max_bandwidth_khz < MHZ_TO_KHZ(160))
958 bw_flags |= IEEE80211_CHAN_NO_160MHZ; 1042 bw_flags |= IEEE80211_CHAN_NO_160MHZ;
959 1043
960 if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && 1044 if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
@@ -1340,6 +1424,7 @@ static void handle_channel_custom(struct wiphy *wiphy,
1340 const struct ieee80211_reg_rule *reg_rule = NULL; 1424 const struct ieee80211_reg_rule *reg_rule = NULL;
1341 const struct ieee80211_power_rule *power_rule = NULL; 1425 const struct ieee80211_power_rule *power_rule = NULL;
1342 const struct ieee80211_freq_range *freq_range = NULL; 1426 const struct ieee80211_freq_range *freq_range = NULL;
1427 u32 max_bandwidth_khz;
1343 1428
1344 reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq), 1429 reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq),
1345 regd); 1430 regd);
@@ -1357,11 +1442,16 @@ static void handle_channel_custom(struct wiphy *wiphy,
1357 power_rule = &reg_rule->power_rule; 1442 power_rule = &reg_rule->power_rule;
1358 freq_range = &reg_rule->freq_range; 1443 freq_range = &reg_rule->freq_range;
1359 1444
1360 if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) 1445 max_bandwidth_khz = freq_range->max_bandwidth_khz;
1446 /* Check if auto calculation requested */
1447 if (!max_bandwidth_khz)
1448 max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
1449
1450 if (max_bandwidth_khz < MHZ_TO_KHZ(40))
1361 bw_flags = IEEE80211_CHAN_NO_HT40; 1451 bw_flags = IEEE80211_CHAN_NO_HT40;
1362 if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80)) 1452 if (max_bandwidth_khz < MHZ_TO_KHZ(80))
1363 bw_flags |= IEEE80211_CHAN_NO_80MHZ; 1453 bw_flags |= IEEE80211_CHAN_NO_80MHZ;
1364 if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160)) 1454 if (max_bandwidth_khz < MHZ_TO_KHZ(160))
1365 bw_flags |= IEEE80211_CHAN_NO_160MHZ; 1455 bw_flags |= IEEE80211_CHAN_NO_160MHZ;
1366 1456
1367 chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; 1457 chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags;
@@ -2155,6 +2245,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
2155 const struct ieee80211_reg_rule *reg_rule = NULL; 2245 const struct ieee80211_reg_rule *reg_rule = NULL;
2156 const struct ieee80211_freq_range *freq_range = NULL; 2246 const struct ieee80211_freq_range *freq_range = NULL;
2157 const struct ieee80211_power_rule *power_rule = NULL; 2247 const struct ieee80211_power_rule *power_rule = NULL;
2248 char bw[32];
2158 2249
2159 pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n"); 2250 pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n");
2160 2251
@@ -2163,22 +2254,29 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
2163 freq_range = &reg_rule->freq_range; 2254 freq_range = &reg_rule->freq_range;
2164 power_rule = &reg_rule->power_rule; 2255 power_rule = &reg_rule->power_rule;
2165 2256
2257 if (!freq_range->max_bandwidth_khz)
2258 snprintf(bw, 32, "%d KHz, AUTO",
2259 reg_get_max_bandwidth(rd, reg_rule));
2260 else
2261 snprintf(bw, 32, "%d KHz",
2262 freq_range->max_bandwidth_khz);
2263
2166 /* 2264 /*
2167 * There may not be documentation for max antenna gain 2265 * There may not be documentation for max antenna gain
2168 * in certain regions 2266 * in certain regions
2169 */ 2267 */
2170 if (power_rule->max_antenna_gain) 2268 if (power_rule->max_antenna_gain)
2171 pr_info(" (%d KHz - %d KHz @ %d KHz), (%d mBi, %d mBm)\n", 2269 pr_info(" (%d KHz - %d KHz @ %s), (%d mBi, %d mBm)\n",
2172 freq_range->start_freq_khz, 2270 freq_range->start_freq_khz,
2173 freq_range->end_freq_khz, 2271 freq_range->end_freq_khz,
2174 freq_range->max_bandwidth_khz, 2272 bw,
2175 power_rule->max_antenna_gain, 2273 power_rule->max_antenna_gain,
2176 power_rule->max_eirp); 2274 power_rule->max_eirp);
2177 else 2275 else
2178 pr_info(" (%d KHz - %d KHz @ %d KHz), (N/A, %d mBm)\n", 2276 pr_info(" (%d KHz - %d KHz @ %s), (N/A, %d mBm)\n",
2179 freq_range->start_freq_khz, 2277 freq_range->start_freq_khz,
2180 freq_range->end_freq_khz, 2278 freq_range->end_freq_khz,
2181 freq_range->max_bandwidth_khz, 2279 bw,
2182 power_rule->max_eirp); 2280 power_rule->max_eirp);
2183 } 2281 }
2184} 2282}