diff options
author | Janusz Dziedzic <janusz.dziedzic@tieto.com> | 2014-02-20 07:52:16 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2014-02-21 03:27:28 -0500 |
commit | b0dfd2ea12d92b49639ad84f24ddd00c7ac144b5 (patch) | |
tree | 7b71486a29271d772919d7e1d71f384b519b46cd | |
parent | 37e3308cb2b6933019d9d9c2045877d6d68d9c5a (diff) |
cfg80211: regulatory: introduce NL80211_RRF_AUTO_BW rule flag
Introduce NL80211_RRF_AUTO_BW rule flag. If this flag set
maximum available bandwidth should be calculated base on
contiguous rules and wider channels will be allowed to cross
multiple contiguous/overlapping frequency ranges.
In case of old kernels maximum bandwidth from regulatory
rule will be used, while there is no NL80211_RRF_AUTO_BW flag.
This fixes the previous commit 9752482083066af7ac18a5ca376f
("cfg80211: regulatory introduce maximum bandwidth calculation")
which was found to be a problem for userspace API compatibility.
Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
[edit commit log, use sizeof()]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | include/uapi/linux/nl80211.h | 9 | ||||
-rw-r--r-- | net/wireless/genregdb.awk | 2 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 7 | ||||
-rw-r--r-- | net/wireless/reg.c | 83 |
4 files changed, 58 insertions, 43 deletions
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 81481cff1dc1..ff72cab3cd3a 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -2443,10 +2443,7 @@ enum nl80211_reg_type { | |||
2443 | * in KHz. This is not a center a frequency but an actual regulatory | 2443 | * in KHz. This is not a center a frequency but an actual regulatory |
2444 | * band edge. | 2444 | * band edge. |
2445 | * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this | 2445 | * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this |
2446 | * frequency range, in KHz. If not present or 0, maximum available | 2446 | * frequency range, in KHz. |
2447 | * bandwidth should be calculated base on contiguous rules and wider | ||
2448 | * channels will be allowed to cross multiple contiguous/overlapping | ||
2449 | * frequency ranges. | ||
2450 | * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain | 2447 | * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain |
2451 | * for a given frequency range. The value is in mBi (100 * dBi). | 2448 | * for a given frequency range. The value is in mBi (100 * dBi). |
2452 | * If you don't have one then don't send this. | 2449 | * If you don't have one then don't send this. |
@@ -2517,6 +2514,9 @@ enum nl80211_sched_scan_match_attr { | |||
2517 | * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed, | 2514 | * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed, |
2518 | * this includes probe requests or modes of operation that require | 2515 | * this includes probe requests or modes of operation that require |
2519 | * beaconing. | 2516 | * beaconing. |
2517 | * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated | ||
2518 | * base on contiguous rules and wider channels will be allowed to cross | ||
2519 | * multiple contiguous/overlapping frequency ranges. | ||
2520 | */ | 2520 | */ |
2521 | enum nl80211_reg_rule_flags { | 2521 | enum nl80211_reg_rule_flags { |
2522 | NL80211_RRF_NO_OFDM = 1<<0, | 2522 | NL80211_RRF_NO_OFDM = 1<<0, |
@@ -2528,6 +2528,7 @@ enum nl80211_reg_rule_flags { | |||
2528 | NL80211_RRF_PTMP_ONLY = 1<<6, | 2528 | NL80211_RRF_PTMP_ONLY = 1<<6, |
2529 | NL80211_RRF_NO_IR = 1<<7, | 2529 | NL80211_RRF_NO_IR = 1<<7, |
2530 | __NL80211_RRF_NO_IBSS = 1<<8, | 2530 | __NL80211_RRF_NO_IBSS = 1<<8, |
2531 | NL80211_RRF_AUTO_BW = 1<<11, | ||
2531 | }; | 2532 | }; |
2532 | 2533 | ||
2533 | #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR | 2534 | #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR |
diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index 9a8217d2a908..fdfd3f063a9b 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk | |||
@@ -105,6 +105,8 @@ function parse_reg_rule() | |||
105 | flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " | 105 | flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " |
106 | } else if (flagarray[arg] == "NO-IR") { | 106 | } else if (flagarray[arg] == "NO-IR") { |
107 | flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " | 107 | flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " |
108 | } else if (flagarray[arg] == "AUTO-BW") { | ||
109 | flags = flags "\n\t\t\tNL80211_RRF_AUTO_BW | " | ||
108 | } | 110 | } |
109 | 111 | ||
110 | } | 112 | } |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index be836098d342..1e5a434e4224 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -4628,6 +4628,8 @@ static int parse_reg_rule(struct nlattr *tb[], | |||
4628 | return -EINVAL; | 4628 | return -EINVAL; |
4629 | if (!tb[NL80211_ATTR_FREQ_RANGE_END]) | 4629 | if (!tb[NL80211_ATTR_FREQ_RANGE_END]) |
4630 | return -EINVAL; | 4630 | return -EINVAL; |
4631 | if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) | ||
4632 | return -EINVAL; | ||
4631 | if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) | 4633 | if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) |
4632 | return -EINVAL; | 4634 | return -EINVAL; |
4633 | 4635 | ||
@@ -4637,9 +4639,8 @@ static int parse_reg_rule(struct nlattr *tb[], | |||
4637 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); | 4639 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); |
4638 | freq_range->end_freq_khz = | 4640 | freq_range->end_freq_khz = |
4639 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); | 4641 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); |
4640 | if (tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) | 4642 | freq_range->max_bandwidth_khz = |
4641 | freq_range->max_bandwidth_khz = | 4643 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); |
4642 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); | ||
4643 | 4644 | ||
4644 | power_rule->max_eirp = | 4645 | power_rule->max_eirp = |
4645 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); | 4646 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 27c5253e7a61..6b6f33ad78f2 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -563,9 +563,6 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | |||
563 | if (freq_range_tmp->end_freq_khz < freq_range->start_freq_khz) | 563 | if (freq_range_tmp->end_freq_khz < freq_range->start_freq_khz) |
564 | break; | 564 | break; |
565 | 565 | ||
566 | if (freq_range_tmp->max_bandwidth_khz) | ||
567 | break; | ||
568 | |||
569 | freq_range = freq_range_tmp; | 566 | freq_range = freq_range_tmp; |
570 | } | 567 | } |
571 | 568 | ||
@@ -582,9 +579,6 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | |||
582 | if (freq_range_tmp->start_freq_khz > freq_range->end_freq_khz) | 579 | if (freq_range_tmp->start_freq_khz > freq_range->end_freq_khz) |
583 | break; | 580 | break; |
584 | 581 | ||
585 | if (freq_range_tmp->max_bandwidth_khz) | ||
586 | break; | ||
587 | |||
588 | freq_range = freq_range_tmp; | 582 | freq_range = freq_range_tmp; |
589 | } | 583 | } |
590 | 584 | ||
@@ -729,21 +723,29 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1, | |||
729 | max_bandwidth1 = freq_range1->max_bandwidth_khz; | 723 | max_bandwidth1 = freq_range1->max_bandwidth_khz; |
730 | max_bandwidth2 = freq_range2->max_bandwidth_khz; | 724 | max_bandwidth2 = freq_range2->max_bandwidth_khz; |
731 | 725 | ||
732 | /* | 726 | if (rule1->flags & NL80211_RRF_AUTO_BW) |
733 | * In case max_bandwidth1 == 0 and max_bandwith2 == 0 set | 727 | max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1); |
734 | * output bandwidth as 0 (auto calculation). Next we will | 728 | if (rule2->flags & NL80211_RRF_AUTO_BW) |
735 | * calculate this correctly in handle_channel function. | 729 | max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2); |
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 | 730 | ||
745 | freq_range->max_bandwidth_khz = min(max_bandwidth1, max_bandwidth2); | 731 | freq_range->max_bandwidth_khz = min(max_bandwidth1, max_bandwidth2); |
746 | 732 | ||
733 | intersected_rule->flags = rule1->flags | rule2->flags; | ||
734 | |||
735 | /* | ||
736 | * In case NL80211_RRF_AUTO_BW requested for both rules | ||
737 | * set AUTO_BW in intersected rule also. Next we will | ||
738 | * calculate BW correctly in handle_channel function. | ||
739 | * In other case remove AUTO_BW flag while we calculate | ||
740 | * maximum bandwidth correctly and auto calculation is | ||
741 | * not required. | ||
742 | */ | ||
743 | if ((rule1->flags & NL80211_RRF_AUTO_BW) && | ||
744 | (rule2->flags & NL80211_RRF_AUTO_BW)) | ||
745 | intersected_rule->flags |= NL80211_RRF_AUTO_BW; | ||
746 | else | ||
747 | intersected_rule->flags &= ~NL80211_RRF_AUTO_BW; | ||
748 | |||
747 | freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; | 749 | freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; |
748 | if (freq_range->max_bandwidth_khz > freq_diff) | 750 | if (freq_range->max_bandwidth_khz > freq_diff) |
749 | freq_range->max_bandwidth_khz = freq_diff; | 751 | freq_range->max_bandwidth_khz = freq_diff; |
@@ -753,8 +755,6 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1, | |||
753 | power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain, | 755 | power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain, |
754 | power_rule2->max_antenna_gain); | 756 | power_rule2->max_antenna_gain); |
755 | 757 | ||
756 | intersected_rule->flags = rule1->flags | rule2->flags; | ||
757 | |||
758 | if (!is_valid_reg_rule(intersected_rule)) | 758 | if (!is_valid_reg_rule(intersected_rule)) |
759 | return -EINVAL; | 759 | return -EINVAL; |
760 | 760 | ||
@@ -938,31 +938,42 @@ const char *reg_initiator_name(enum nl80211_reg_initiator initiator) | |||
938 | EXPORT_SYMBOL(reg_initiator_name); | 938 | EXPORT_SYMBOL(reg_initiator_name); |
939 | 939 | ||
940 | #ifdef CONFIG_CFG80211_REG_DEBUG | 940 | #ifdef CONFIG_CFG80211_REG_DEBUG |
941 | static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, | 941 | static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd, |
942 | struct ieee80211_channel *chan, | ||
942 | const struct ieee80211_reg_rule *reg_rule) | 943 | const struct ieee80211_reg_rule *reg_rule) |
943 | { | 944 | { |
944 | const struct ieee80211_power_rule *power_rule; | 945 | const struct ieee80211_power_rule *power_rule; |
945 | const struct ieee80211_freq_range *freq_range; | 946 | const struct ieee80211_freq_range *freq_range; |
946 | char max_antenna_gain[32]; | 947 | char max_antenna_gain[32], bw[32]; |
947 | 948 | ||
948 | power_rule = ®_rule->power_rule; | 949 | power_rule = ®_rule->power_rule; |
949 | freq_range = ®_rule->freq_range; | 950 | freq_range = ®_rule->freq_range; |
950 | 951 | ||
951 | if (!power_rule->max_antenna_gain) | 952 | if (!power_rule->max_antenna_gain) |
952 | snprintf(max_antenna_gain, 32, "N/A"); | 953 | snprintf(max_antenna_gain, sizeof(max_antenna_gain), "N/A"); |
953 | else | 954 | else |
954 | snprintf(max_antenna_gain, 32, "%d", power_rule->max_antenna_gain); | 955 | snprintf(max_antenna_gain, sizeof(max_antenna_gain), "%d", |
956 | power_rule->max_antenna_gain); | ||
957 | |||
958 | if (reg_rule->flags & NL80211_RRF_AUTO_BW) | ||
959 | snprintf(bw, sizeof(bw), "%d KHz, %d KHz AUTO", | ||
960 | freq_range->max_bandwidth_khz, | ||
961 | reg_get_max_bandwidth(regd, reg_rule)); | ||
962 | else | ||
963 | snprintf(bw, sizeof(bw), "%d KHz", | ||
964 | freq_range->max_bandwidth_khz); | ||
955 | 965 | ||
956 | REG_DBG_PRINT("Updating information on frequency %d MHz with regulatory rule:\n", | 966 | REG_DBG_PRINT("Updating information on frequency %d MHz with regulatory rule:\n", |
957 | chan->center_freq); | 967 | chan->center_freq); |
958 | 968 | ||
959 | REG_DBG_PRINT("%d KHz - %d KHz @ %d KHz), (%s mBi, %d mBm)\n", | 969 | REG_DBG_PRINT("%d KHz - %d KHz @ %s), (%s mBi, %d mBm)\n", |
960 | freq_range->start_freq_khz, freq_range->end_freq_khz, | 970 | freq_range->start_freq_khz, freq_range->end_freq_khz, |
961 | freq_range->max_bandwidth_khz, max_antenna_gain, | 971 | bw, max_antenna_gain, |
962 | power_rule->max_eirp); | 972 | power_rule->max_eirp); |
963 | } | 973 | } |
964 | #else | 974 | #else |
965 | static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, | 975 | static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd, |
976 | struct ieee80211_channel *chan, | ||
966 | const struct ieee80211_reg_rule *reg_rule) | 977 | const struct ieee80211_reg_rule *reg_rule) |
967 | { | 978 | { |
968 | return; | 979 | return; |
@@ -1022,17 +1033,16 @@ static void handle_channel(struct wiphy *wiphy, | |||
1022 | return; | 1033 | return; |
1023 | } | 1034 | } |
1024 | 1035 | ||
1025 | chan_reg_rule_print_dbg(chan, reg_rule); | 1036 | regd = reg_get_regdomain(wiphy); |
1037 | chan_reg_rule_print_dbg(regd, chan, reg_rule); | ||
1026 | 1038 | ||
1027 | power_rule = ®_rule->power_rule; | 1039 | power_rule = ®_rule->power_rule; |
1028 | freq_range = ®_rule->freq_range; | 1040 | freq_range = ®_rule->freq_range; |
1029 | 1041 | ||
1030 | max_bandwidth_khz = freq_range->max_bandwidth_khz; | 1042 | max_bandwidth_khz = freq_range->max_bandwidth_khz; |
1031 | /* Check if auto calculation requested */ | 1043 | /* Check if auto calculation requested */ |
1032 | if (!max_bandwidth_khz) { | 1044 | if (reg_rule->flags & NL80211_RRF_AUTO_BW) |
1033 | regd = reg_get_regdomain(wiphy); | ||
1034 | max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); | 1045 | max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); |
1035 | } | ||
1036 | 1046 | ||
1037 | if (max_bandwidth_khz < MHZ_TO_KHZ(40)) | 1047 | if (max_bandwidth_khz < MHZ_TO_KHZ(40)) |
1038 | bw_flags = IEEE80211_CHAN_NO_HT40; | 1048 | bw_flags = IEEE80211_CHAN_NO_HT40; |
@@ -1437,14 +1447,14 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1437 | return; | 1447 | return; |
1438 | } | 1448 | } |
1439 | 1449 | ||
1440 | chan_reg_rule_print_dbg(chan, reg_rule); | 1450 | chan_reg_rule_print_dbg(regd, chan, reg_rule); |
1441 | 1451 | ||
1442 | power_rule = ®_rule->power_rule; | 1452 | power_rule = ®_rule->power_rule; |
1443 | freq_range = ®_rule->freq_range; | 1453 | freq_range = ®_rule->freq_range; |
1444 | 1454 | ||
1445 | max_bandwidth_khz = freq_range->max_bandwidth_khz; | 1455 | max_bandwidth_khz = freq_range->max_bandwidth_khz; |
1446 | /* Check if auto calculation requested */ | 1456 | /* Check if auto calculation requested */ |
1447 | if (!max_bandwidth_khz) | 1457 | if (reg_rule->flags & NL80211_RRF_AUTO_BW) |
1448 | max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); | 1458 | max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); |
1449 | 1459 | ||
1450 | if (max_bandwidth_khz < MHZ_TO_KHZ(40)) | 1460 | if (max_bandwidth_khz < MHZ_TO_KHZ(40)) |
@@ -2254,11 +2264,12 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) | |||
2254 | freq_range = ®_rule->freq_range; | 2264 | freq_range = ®_rule->freq_range; |
2255 | power_rule = ®_rule->power_rule; | 2265 | power_rule = ®_rule->power_rule; |
2256 | 2266 | ||
2257 | if (!freq_range->max_bandwidth_khz) | 2267 | if (reg_rule->flags & NL80211_RRF_AUTO_BW) |
2258 | snprintf(bw, 32, "%d KHz, AUTO", | 2268 | snprintf(bw, sizeof(bw), "%d KHz, %d KHz AUTO", |
2269 | freq_range->max_bandwidth_khz, | ||
2259 | reg_get_max_bandwidth(rd, reg_rule)); | 2270 | reg_get_max_bandwidth(rd, reg_rule)); |
2260 | else | 2271 | else |
2261 | snprintf(bw, 32, "%d KHz", | 2272 | snprintf(bw, sizeof(bw), "%d KHz", |
2262 | freq_range->max_bandwidth_khz); | 2273 | freq_range->max_bandwidth_khz); |
2263 | 2274 | ||
2264 | /* | 2275 | /* |