diff options
author | Janusz Dziedzic <janusz.dziedzic@tieto.com> | 2014-01-30 03:52:20 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2014-02-05 08:03:19 -0500 |
commit | 9752482083066af7ac18a5ca376ff35d72418b29 (patch) | |
tree | 729d143ac4c3de4eba5a84945a78058209df814a /net/wireless/reg.c | |
parent | 9e0e29615a2077be852b1245b57c5b00fa609522 (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.c | 130 |
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 | ||
541 | unsigned 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 */ |
542 | static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) | 597 | static 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 | */ |
649 | static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1, | 704 | static 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 = ®_rule->power_rule; | 1027 | power_rule = ®_rule->power_rule; |
951 | freq_range = ®_rule->freq_range; | 1028 | freq_range = ®_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 = ®_rule->power_rule; | 1442 | power_rule = ®_rule->power_rule; |
1358 | freq_range = ®_rule->freq_range; | 1443 | freq_range = ®_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 = ®_rule->freq_range; | 2254 | freq_range = ®_rule->freq_range; |
2164 | power_rule = ®_rule->power_rule; | 2255 | power_rule = ®_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 | } |