Commit 4edd5698 authored by Matthias May's avatar Matthias May Committed by Johannes Berg

cfg80211: regulatory: handle 5 and 10 MHz channels properly

The original assumption of 20MHz wide channels hasn't been true since
the addition of support for 5 and 10 MHz channels.
Change the code to no longer disable all channels that don't fit into
the 20MHz grid, but instead set the appropriate flags to disable
operation on specific bandwidths.
Signed-off-by: default avatarMatthias May <matthias.may@neratec.com>
[reword commit message]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 75dbf00b
...@@ -1004,7 +1004,7 @@ static u32 map_regdom_flags(u32 rd_flags) ...@@ -1004,7 +1004,7 @@ static u32 map_regdom_flags(u32 rd_flags)
static const struct ieee80211_reg_rule * static const struct ieee80211_reg_rule *
freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq, freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
const struct ieee80211_regdomain *regd) const struct ieee80211_regdomain *regd, u32 bw)
{ {
int i; int i;
bool band_rule_found = false; bool band_rule_found = false;
...@@ -1028,7 +1028,7 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq, ...@@ -1028,7 +1028,7 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
if (!band_rule_found) if (!band_rule_found)
band_rule_found = freq_in_rule_band(fr, center_freq); band_rule_found = freq_in_rule_band(fr, center_freq);
bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(20)); bw_fits = reg_does_bw_fit(fr, center_freq, bw);
if (band_rule_found && bw_fits) if (band_rule_found && bw_fits)
return rr; return rr;
...@@ -1040,14 +1040,26 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq, ...@@ -1040,14 +1040,26 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy, const struct ieee80211_reg_rule *__freq_reg_info(struct wiphy *wiphy,
u32 center_freq) u32 center_freq, u32 min_bw)
{ {
const struct ieee80211_regdomain *regd; const struct ieee80211_regdomain *regd = reg_get_regdomain(wiphy);
const struct ieee80211_reg_rule *reg_rule = NULL;
u32 bw;
regd = reg_get_regdomain(wiphy); for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) {
reg_rule = freq_reg_info_regd(wiphy, center_freq, regd, bw);
if (!IS_ERR(reg_rule))
return reg_rule;
}
return freq_reg_info_regd(wiphy, center_freq, regd); return reg_rule;
}
const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
u32 center_freq)
{
return __freq_reg_info(wiphy, center_freq, MHZ_TO_KHZ(20));
} }
EXPORT_SYMBOL(freq_reg_info); EXPORT_SYMBOL(freq_reg_info);
...@@ -1176,8 +1188,20 @@ static void handle_channel(struct wiphy *wiphy, ...@@ -1176,8 +1188,20 @@ static void handle_channel(struct wiphy *wiphy,
if (reg_rule->flags & NL80211_RRF_AUTO_BW) 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 we get a reg_rule we can assume that at least 5Mhz fit */
if (!reg_does_bw_fit(freq_range, MHZ_TO_KHZ(chan->center_freq),
MHZ_TO_KHZ(10)))
bw_flags |= IEEE80211_CHAN_NO_10MHZ;
if (!reg_does_bw_fit(freq_range, MHZ_TO_KHZ(chan->center_freq),
MHZ_TO_KHZ(20)))
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(10))
bw_flags |= IEEE80211_CHAN_NO_10MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(20))
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
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;
if (max_bandwidth_khz < MHZ_TO_KHZ(80)) if (max_bandwidth_khz < MHZ_TO_KHZ(80))
bw_flags |= IEEE80211_CHAN_NO_80MHZ; bw_flags |= IEEE80211_CHAN_NO_80MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(160)) if (max_bandwidth_khz < MHZ_TO_KHZ(160))
...@@ -1695,9 +1719,15 @@ static void handle_channel_custom(struct wiphy *wiphy, ...@@ -1695,9 +1719,15 @@ static void handle_channel_custom(struct wiphy *wiphy,
const struct ieee80211_power_rule *power_rule = NULL; const struct ieee80211_power_rule *power_rule = NULL;
const struct ieee80211_freq_range *freq_range = NULL; const struct ieee80211_freq_range *freq_range = NULL;
u32 max_bandwidth_khz; u32 max_bandwidth_khz;
u32 bw;
reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq), for (bw = MHZ_TO_KHZ(20); bw >= MHZ_TO_KHZ(5); bw = bw / 2) {
regd); reg_rule = freq_reg_info_regd(wiphy,
MHZ_TO_KHZ(chan->center_freq),
regd, bw);
if (!IS_ERR(reg_rule))
break;
}
if (IS_ERR(reg_rule)) { if (IS_ERR(reg_rule)) {
REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n", REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n",
...@@ -1721,8 +1751,20 @@ static void handle_channel_custom(struct wiphy *wiphy, ...@@ -1721,8 +1751,20 @@ static void handle_channel_custom(struct wiphy *wiphy,
if (reg_rule->flags & NL80211_RRF_AUTO_BW) 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 we get a reg_rule we can assume that at least 5Mhz fit */
if (!reg_does_bw_fit(freq_range, MHZ_TO_KHZ(chan->center_freq),
MHZ_TO_KHZ(10)))
bw_flags |= IEEE80211_CHAN_NO_10MHZ;
if (!reg_does_bw_fit(freq_range, MHZ_TO_KHZ(chan->center_freq),
MHZ_TO_KHZ(20)))
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(10))
bw_flags |= IEEE80211_CHAN_NO_10MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(20))
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
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;
if (max_bandwidth_khz < MHZ_TO_KHZ(80)) if (max_bandwidth_khz < MHZ_TO_KHZ(80))
bw_flags |= IEEE80211_CHAN_NO_80MHZ; bw_flags |= IEEE80211_CHAN_NO_80MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(160)) if (max_bandwidth_khz < MHZ_TO_KHZ(160))
......
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