Commit b0dfd2ea authored by Janusz Dziedzic's avatar Janusz Dziedzic Committed by Johannes Berg

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 97524820
("cfg80211: regulatory introduce maximum bandwidth calculation")
which was found to be a problem for userspace API compatibility.
Signed-off-by: default avatarJanusz Dziedzic <janusz.dziedzic@tieto.com>
[edit commit log, use sizeof()]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 37e3308c
...@@ -2443,10 +2443,7 @@ enum nl80211_reg_type { ...@@ -2443,10 +2443,7 @@ enum nl80211_reg_type {
* in KHz. This is not a center a frequency but an actual regulatory * in KHz. This is not a center a frequency but an actual regulatory
* band edge. * band edge.
* @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
* frequency range, in KHz. If not present or 0, maximum available * frequency range, in KHz.
* bandwidth should be calculated base on contiguous rules and wider
* channels will be allowed to cross multiple contiguous/overlapping
* frequency ranges.
* @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
* for a given frequency range. The value is in mBi (100 * dBi). * for a given frequency range. The value is in mBi (100 * dBi).
* If you don't have one then don't send this. * If you don't have one then don't send this.
...@@ -2517,6 +2514,9 @@ enum nl80211_sched_scan_match_attr { ...@@ -2517,6 +2514,9 @@ enum nl80211_sched_scan_match_attr {
* @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed, * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed,
* this includes probe requests or modes of operation that require * this includes probe requests or modes of operation that require
* beaconing. * beaconing.
* @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
* base on contiguous rules and wider channels will be allowed to cross
* multiple contiguous/overlapping frequency ranges.
*/ */
enum nl80211_reg_rule_flags { enum nl80211_reg_rule_flags {
NL80211_RRF_NO_OFDM = 1<<0, NL80211_RRF_NO_OFDM = 1<<0,
...@@ -2528,6 +2528,7 @@ enum nl80211_reg_rule_flags { ...@@ -2528,6 +2528,7 @@ enum nl80211_reg_rule_flags {
NL80211_RRF_PTMP_ONLY = 1<<6, NL80211_RRF_PTMP_ONLY = 1<<6,
NL80211_RRF_NO_IR = 1<<7, NL80211_RRF_NO_IR = 1<<7,
__NL80211_RRF_NO_IBSS = 1<<8, __NL80211_RRF_NO_IBSS = 1<<8,
NL80211_RRF_AUTO_BW = 1<<11,
}; };
#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
......
...@@ -105,6 +105,8 @@ function parse_reg_rule() ...@@ -105,6 +105,8 @@ function parse_reg_rule()
flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
} else if (flagarray[arg] == "NO-IR") { } else if (flagarray[arg] == "NO-IR") {
flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
} else if (flagarray[arg] == "AUTO-BW") {
flags = flags "\n\t\t\tNL80211_RRF_AUTO_BW | "
} }
} }
......
...@@ -4628,6 +4628,8 @@ static int parse_reg_rule(struct nlattr *tb[], ...@@ -4628,6 +4628,8 @@ static int parse_reg_rule(struct nlattr *tb[],
return -EINVAL; return -EINVAL;
if (!tb[NL80211_ATTR_FREQ_RANGE_END]) if (!tb[NL80211_ATTR_FREQ_RANGE_END])
return -EINVAL; return -EINVAL;
if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
return -EINVAL;
if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
return -EINVAL; return -EINVAL;
...@@ -4637,7 +4639,6 @@ static int parse_reg_rule(struct nlattr *tb[], ...@@ -4637,7 +4639,6 @@ static int parse_reg_rule(struct nlattr *tb[],
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
freq_range->end_freq_khz = freq_range->end_freq_khz =
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
if (tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
freq_range->max_bandwidth_khz = freq_range->max_bandwidth_khz =
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
......
...@@ -563,9 +563,6 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, ...@@ -563,9 +563,6 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
if (freq_range_tmp->end_freq_khz < freq_range->start_freq_khz) if (freq_range_tmp->end_freq_khz < freq_range->start_freq_khz)
break; break;
if (freq_range_tmp->max_bandwidth_khz)
break;
freq_range = freq_range_tmp; freq_range = freq_range_tmp;
} }
...@@ -582,9 +579,6 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, ...@@ -582,9 +579,6 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
if (freq_range_tmp->start_freq_khz > freq_range->end_freq_khz) if (freq_range_tmp->start_freq_khz > freq_range->end_freq_khz)
break; break;
if (freq_range_tmp->max_bandwidth_khz)
break;
freq_range = freq_range_tmp; freq_range = freq_range_tmp;
} }
...@@ -729,21 +723,29 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1, ...@@ -729,21 +723,29 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
max_bandwidth1 = freq_range1->max_bandwidth_khz; max_bandwidth1 = freq_range1->max_bandwidth_khz;
max_bandwidth2 = freq_range2->max_bandwidth_khz; max_bandwidth2 = freq_range2->max_bandwidth_khz;
/* if (rule1->flags & NL80211_RRF_AUTO_BW)
* In case max_bandwidth1 == 0 and max_bandwith2 == 0 set
* output bandwidth as 0 (auto calculation). Next we will
* calculate this correctly in handle_channel function.
* In other case calculate output bandwidth here.
*/
if (max_bandwidth1 || max_bandwidth2) {
if (!max_bandwidth1)
max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1); max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1);
if (!max_bandwidth2) if (rule2->flags & NL80211_RRF_AUTO_BW)
max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2); max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2);
}
freq_range->max_bandwidth_khz = min(max_bandwidth1, max_bandwidth2); freq_range->max_bandwidth_khz = min(max_bandwidth1, max_bandwidth2);
intersected_rule->flags = rule1->flags | rule2->flags;
/*
* In case NL80211_RRF_AUTO_BW requested for both rules
* set AUTO_BW in intersected rule also. Next we will
* calculate BW correctly in handle_channel function.
* In other case remove AUTO_BW flag while we calculate
* maximum bandwidth correctly and auto calculation is
* not required.
*/
if ((rule1->flags & NL80211_RRF_AUTO_BW) &&
(rule2->flags & NL80211_RRF_AUTO_BW))
intersected_rule->flags |= NL80211_RRF_AUTO_BW;
else
intersected_rule->flags &= ~NL80211_RRF_AUTO_BW;
freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
if (freq_range->max_bandwidth_khz > freq_diff) if (freq_range->max_bandwidth_khz > freq_diff)
freq_range->max_bandwidth_khz = freq_diff; freq_range->max_bandwidth_khz = freq_diff;
...@@ -753,8 +755,6 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1, ...@@ -753,8 +755,6 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain, power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain,
power_rule2->max_antenna_gain); power_rule2->max_antenna_gain);
intersected_rule->flags = rule1->flags | rule2->flags;
if (!is_valid_reg_rule(intersected_rule)) if (!is_valid_reg_rule(intersected_rule))
return -EINVAL; return -EINVAL;
...@@ -938,31 +938,42 @@ const char *reg_initiator_name(enum nl80211_reg_initiator initiator) ...@@ -938,31 +938,42 @@ const char *reg_initiator_name(enum nl80211_reg_initiator initiator)
EXPORT_SYMBOL(reg_initiator_name); EXPORT_SYMBOL(reg_initiator_name);
#ifdef CONFIG_CFG80211_REG_DEBUG #ifdef CONFIG_CFG80211_REG_DEBUG
static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
struct ieee80211_channel *chan,
const struct ieee80211_reg_rule *reg_rule) const struct ieee80211_reg_rule *reg_rule)
{ {
const struct ieee80211_power_rule *power_rule; const struct ieee80211_power_rule *power_rule;
const struct ieee80211_freq_range *freq_range; const struct ieee80211_freq_range *freq_range;
char max_antenna_gain[32]; char max_antenna_gain[32], bw[32];
power_rule = &reg_rule->power_rule; power_rule = &reg_rule->power_rule;
freq_range = &reg_rule->freq_range; freq_range = &reg_rule->freq_range;
if (!power_rule->max_antenna_gain) if (!power_rule->max_antenna_gain)
snprintf(max_antenna_gain, 32, "N/A"); snprintf(max_antenna_gain, sizeof(max_antenna_gain), "N/A");
else else
snprintf(max_antenna_gain, 32, "%d", power_rule->max_antenna_gain); snprintf(max_antenna_gain, sizeof(max_antenna_gain), "%d",
power_rule->max_antenna_gain);
if (reg_rule->flags & NL80211_RRF_AUTO_BW)
snprintf(bw, sizeof(bw), "%d KHz, %d KHz AUTO",
freq_range->max_bandwidth_khz,
reg_get_max_bandwidth(regd, reg_rule));
else
snprintf(bw, sizeof(bw), "%d KHz",
freq_range->max_bandwidth_khz);
REG_DBG_PRINT("Updating information on frequency %d MHz with regulatory rule:\n", REG_DBG_PRINT("Updating information on frequency %d MHz with regulatory rule:\n",
chan->center_freq); chan->center_freq);
REG_DBG_PRINT("%d KHz - %d KHz @ %d KHz), (%s mBi, %d mBm)\n", REG_DBG_PRINT("%d KHz - %d KHz @ %s), (%s mBi, %d mBm)\n",
freq_range->start_freq_khz, freq_range->end_freq_khz, freq_range->start_freq_khz, freq_range->end_freq_khz,
freq_range->max_bandwidth_khz, max_antenna_gain, bw, max_antenna_gain,
power_rule->max_eirp); power_rule->max_eirp);
} }
#else #else
static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
struct ieee80211_channel *chan,
const struct ieee80211_reg_rule *reg_rule) const struct ieee80211_reg_rule *reg_rule)
{ {
return; return;
...@@ -1022,17 +1033,16 @@ static void handle_channel(struct wiphy *wiphy, ...@@ -1022,17 +1033,16 @@ static void handle_channel(struct wiphy *wiphy,
return; return;
} }
chan_reg_rule_print_dbg(chan, reg_rule); regd = reg_get_regdomain(wiphy);
chan_reg_rule_print_dbg(regd, chan, reg_rule);
power_rule = &reg_rule->power_rule; power_rule = &reg_rule->power_rule;
freq_range = &reg_rule->freq_range; freq_range = &reg_rule->freq_range;
max_bandwidth_khz = freq_range->max_bandwidth_khz; max_bandwidth_khz = freq_range->max_bandwidth_khz;
/* Check if auto calculation requested */ /* Check if auto calculation requested */
if (!max_bandwidth_khz) { if (reg_rule->flags & NL80211_RRF_AUTO_BW)
regd = reg_get_regdomain(wiphy);
max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
}
if (max_bandwidth_khz < MHZ_TO_KHZ(40)) if (max_bandwidth_khz < MHZ_TO_KHZ(40))
bw_flags = IEEE80211_CHAN_NO_HT40; bw_flags = IEEE80211_CHAN_NO_HT40;
...@@ -1437,14 +1447,14 @@ static void handle_channel_custom(struct wiphy *wiphy, ...@@ -1437,14 +1447,14 @@ static void handle_channel_custom(struct wiphy *wiphy,
return; return;
} }
chan_reg_rule_print_dbg(chan, reg_rule); chan_reg_rule_print_dbg(regd, chan, reg_rule);
power_rule = &reg_rule->power_rule; power_rule = &reg_rule->power_rule;
freq_range = &reg_rule->freq_range; freq_range = &reg_rule->freq_range;
max_bandwidth_khz = freq_range->max_bandwidth_khz; max_bandwidth_khz = freq_range->max_bandwidth_khz;
/* Check if auto calculation requested */ /* Check if auto calculation requested */
if (!max_bandwidth_khz) if (reg_rule->flags & NL80211_RRF_AUTO_BW)
max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
if (max_bandwidth_khz < MHZ_TO_KHZ(40)) if (max_bandwidth_khz < MHZ_TO_KHZ(40))
...@@ -2254,11 +2264,12 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) ...@@ -2254,11 +2264,12 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
freq_range = &reg_rule->freq_range; freq_range = &reg_rule->freq_range;
power_rule = &reg_rule->power_rule; power_rule = &reg_rule->power_rule;
if (!freq_range->max_bandwidth_khz) if (reg_rule->flags & NL80211_RRF_AUTO_BW)
snprintf(bw, 32, "%d KHz, AUTO", snprintf(bw, sizeof(bw), "%d KHz, %d KHz AUTO",
freq_range->max_bandwidth_khz,
reg_get_max_bandwidth(rd, reg_rule)); reg_get_max_bandwidth(rd, reg_rule));
else else
snprintf(bw, 32, "%d KHz", snprintf(bw, sizeof(bw), "%d KHz",
freq_range->max_bandwidth_khz); freq_range->max_bandwidth_khz);
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment