Commit 68dbad8c authored by Thomas Pedersen's avatar Thomas Pedersen Committed by Johannes Berg
Browse files

cfg80211: regulatory: handle S1G channels



S1G channels have a minimum bandwidth of 1Mhz, and there
is a 1:1 mapping of allowed bandwidth to channel number.

Signed-off-by: default avatarThomas Pedersen <thomas@adapt-ip.com>
Link: https://lore.kernel.org/r/20200908190323.15814-4-thomas@adapt-ip.com


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent d65a9770
Loading
Loading
Loading
Loading
+58 −12
Original line number Diff line number Diff line
@@ -1617,9 +1617,11 @@ __freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
{
	const struct ieee80211_regdomain *regd = reg_get_regdomain(wiphy);
	const struct ieee80211_reg_rule *reg_rule = NULL;
	const u32 bws[] = {0, 1, 2, 4, 5, 8, 10, 16, 20};
	int i = ARRAY_SIZE(bws) - 1;
	u32 bw;

	for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) {
	for (bw = MHZ_TO_KHZ(bws[i]); bw >= min_bw; bw = MHZ_TO_KHZ(bws[i--])) {
		reg_rule = freq_reg_info_regd(center_freq, regd, bw);
		if (!IS_ERR(reg_rule))
			return reg_rule;
@@ -1631,7 +1633,9 @@ __freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
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));
	u32 min_bw = center_freq < MHZ_TO_KHZ(1000) ? 1 : 20;

	return __freq_reg_info(wiphy, center_freq, MHZ_TO_KHZ(min_bw));
}
EXPORT_SYMBOL(freq_reg_info);

@@ -1659,6 +1663,7 @@ static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd
{
	const struct ieee80211_freq_range *freq_range = NULL;
	u32 max_bandwidth_khz, center_freq_khz, bw_flags = 0;
	bool is_s1g = chan->band == NL80211_BAND_S1GHZ;

	freq_range = &reg_rule->freq_range;

@@ -1678,6 +1683,46 @@ static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd
					MHZ_TO_KHZ(20)))
		bw_flags |= IEEE80211_CHAN_NO_20MHZ;

	if (is_s1g) {
		/* S1G is strict about non overlapping channels. We can
		 * calculate which bandwidth is allowed per channel by finding
		 * the largest bandwidth which cleanly divides the freq_range.
		 */
		int edge_offset;
		int ch_bw = max_bandwidth_khz;

		while (ch_bw) {
			edge_offset = (center_freq_khz - ch_bw / 2) -
				      freq_range->start_freq_khz;
			if (edge_offset % ch_bw == 0) {
				switch (KHZ_TO_MHZ(ch_bw)) {
				case 1:
					bw_flags |= IEEE80211_CHAN_1MHZ;
					break;
				case 2:
					bw_flags |= IEEE80211_CHAN_2MHZ;
					break;
				case 4:
					bw_flags |= IEEE80211_CHAN_4MHZ;
					break;
				case 8:
					bw_flags |= IEEE80211_CHAN_8MHZ;
					break;
				case 16:
					bw_flags |= IEEE80211_CHAN_16MHZ;
					break;
				default:
					/* If we got here, no bandwidths fit on
					 * this frequency, ie. band edge.
					 */
					bw_flags |= IEEE80211_CHAN_DISABLED;
					break;
				}
				break;
			}
			ch_bw /= 2;
		}
	} else {
		if (max_bandwidth_khz < MHZ_TO_KHZ(10))
			bw_flags |= IEEE80211_CHAN_NO_10MHZ;
		if (max_bandwidth_khz < MHZ_TO_KHZ(20))
@@ -1688,6 +1733,7 @@ static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd
			bw_flags |= IEEE80211_CHAN_NO_80MHZ;
		if (max_bandwidth_khz < MHZ_TO_KHZ(160))
			bw_flags |= IEEE80211_CHAN_NO_160MHZ;
	}
	return bw_flags;
}