aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJanusz Dziedzic <janusz.dziedzic@tieto.com>2014-02-20 07:52:16 -0500
committerJohannes Berg <johannes.berg@intel.com>2014-02-21 03:27:28 -0500
commitb0dfd2ea12d92b49639ad84f24ddd00c7ac144b5 (patch)
tree7b71486a29271d772919d7e1d71f384b519b46cd
parent37e3308cb2b6933019d9d9c2045877d6d68d9c5a (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.h9
-rw-r--r--net/wireless/genregdb.awk2
-rw-r--r--net/wireless/nl80211.c7
-rw-r--r--net/wireless/reg.c83
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 */
2521enum nl80211_reg_rule_flags { 2521enum 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)
938EXPORT_SYMBOL(reg_initiator_name); 938EXPORT_SYMBOL(reg_initiator_name);
939 939
940#ifdef CONFIG_CFG80211_REG_DEBUG 940#ifdef CONFIG_CFG80211_REG_DEBUG
941static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, 941static 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 = &reg_rule->power_rule; 949 power_rule = &reg_rule->power_rule;
949 freq_range = &reg_rule->freq_range; 950 freq_range = &reg_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
965static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, 975static 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 = &reg_rule->power_rule; 1039 power_rule = &reg_rule->power_rule;
1028 freq_range = &reg_rule->freq_range; 1040 freq_range = &reg_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 = &reg_rule->power_rule; 1452 power_rule = &reg_rule->power_rule;
1443 freq_range = &reg_rule->freq_range; 1453 freq_range = &reg_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 = &reg_rule->freq_range; 2264 freq_range = &reg_rule->freq_range;
2255 power_rule = &reg_rule->power_rule; 2265 power_rule = &reg_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 /*