Search Linux Wireless

[RFC v3] cfg80211: VHT regulatory

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



VHT (11ac) regulatory new design. VHT channel center freq, bandwidth and primary channel are used to decide if that channel config is permitted in current regulatory domain.

Signed-off-by: Mahesh Palivela <maheshp@xxxxxxxxxxx>
---
Implementation of review comments by Johannes.

 include/net/cfg80211.h |   37 ++++++++++++++++
 net/wireless/reg.c     |  109 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 146 insertions(+), 0 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 60597cf..50180e0 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -83,6 +83,25 @@ enum ieee80211_band {
 };

 /**
+ * enum ieee80211_chan_width - channel bandwidths
+ *
+ * @IEEE80211_CHAN_WIDTH_20MHZ_NOHT: 20 MHz chan bandwidth No HT
+ * @IEEE80211_CHAN_WIDTH_20MHZ: 20 MHz chan bandwidth
+ * @IEEE80211_CHAN_WIDTH_40MHZ: 40 MHz chan bandwidth
+ * @IEEE80211_CHAN_WIDTH_80MHZ: 80 MHz chan bandwidth
+ * @IEEE80211_CHAN_WIDTH_160MHZ: 160 MHz chan bandwidth
+ * @IEEE80211_CHAN_WIDTH_80P80MHZ: 80+80 MHz chan bandwidth
+ */
+enum ieee80211_chan_width {
+	IEEE80211_CHAN_WIDTH_20MHZ_NOHT,
+	IEEE80211_CHAN_WIDTH_20MHZ,
+	IEEE80211_CHAN_WIDTH_40MHZ,
+	IEEE80211_CHAN_WIDTH_80MHZ,
+	IEEE80211_CHAN_WIDTH_160MHZ,
+	IEEE80211_CHAN_WIDTH_80P80MHZ
+};
+
+/**
  * enum ieee80211_channel_flags - channel flags
  *
  * Channel flags set by the regulatory control code.
@@ -144,6 +163,24 @@ struct ieee80211_channel {
 };

 /**
+ * struct ieee80211_channel_config - channel config definition
+ *
+ * This structure describes channel configuration
+ *
+ * @chan_width1: channel bandwidth
+ * @center_freq1: center frequency of 1 st frequency segment
+ * @center_freq2: center frequency of 2 nd frequency segment
+ * 	Used only for 80+80 MHz combination
+ * @prim_chan_freq: primary channel frequency
+ */
+struct ieee80211_channel_config {
+	enum ieee80211_chan_width chan_width;
+	u16 center_freq1;
+	u16 center_freq2;
+	u16 prim_chan_freq;
+};
+
+/**
  * enum ieee80211_rate_flags - rate flags
  *
  * Hardware/specification flags for rates. These are structured
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index c6e0d46..31d6f7a 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1124,6 +1124,115 @@ static void reg_process_beacons(struct wiphy *wiphy)
 	wiphy_update_beacon_reg(wiphy);
 }

+static bool reg_fits_reg_rule_sec_chans(struct wiphy *wiphy,
+					u32 center_freq,
+					u32 bw_khz,
+					const struct ieee80211_regdomain *regd)
+{
+	int r;
+	const struct ieee80211_reg_rule *reg_rule;
+	const struct ieee80211_freq_range *freq_range;
+	struct ieee80211_channel *chan;
+	u32 left_end_freq, right_end_freq;
+
+	WARN_ON(!center_freq);
+	WARN_ON(!bw_khz);
+
+	assert_reg_lock();
+
+	r = freq_reg_info_regd(wiphy,
+			       center_freq,
+			       bw_khz,
+			       &reg_rule,
+			       regd);
+
+	if (r) {
+		REG_DBG_PRINT("Couldn't find reg rule for freq %d KHz"
+			      "and %d MHz wide channel\n",
+			      center_freq,
+			      KHZ_TO_MHZ(bw_khz));
+		return false;
+	}
+
+	freq_range = &reg_rule->freq_range;
+
+	if (freq_range->max_bandwidth_khz < bw_khz)
+		return false;
+
+	/* find left and right arms of center freq */
+	left_end_freq = center_freq - (bw_khz/2);
+	right_end_freq = center_freq + (bw_khz/2);
+
+	/* left_end_freq and right_end_freq are edge of left and right
+	 * channels. Get center freq of left and right channels
+	 * by adding 10MHz to left_end_freq and subtracting 10 MHZ from
+	 * right_end_freq.
+	 */
+	left_end_freq += MHZ_TO_KHZ(10);
+	right_end_freq -= MHZ_TO_KHZ(10);
+
+	/* find out all possible secondary channels */
+	while (left_end_freq < right_end_freq) {
+		chan = ieee80211_get_channel(wiphy, left_end_freq);
+		if (chan == NULL ||
+		    chan->flags & IEEE80211_CHAN_DISABLED) {
+			return false;
+		}
+		left_end_freq -= MHZ_TO_KHZ(20);
+	}
+
+	return true;
+}
+
+bool reg_chan_use_permitted(struct wiphy *wiphy,
+			    struct ieee80211_channel_config *chan_config,
+			    const struct ieee80211_regdomain *regd)
+{
+	u32 desired_bw_khz = MHZ_TO_KHZ(20);
+	bool ret;
+
+	/* get chan BW from config */
+	switch (chan_config->chan_width) {
+	case IEEE80211_CHAN_WIDTH_20MHZ_NOHT:
+	case IEEE80211_CHAN_WIDTH_20MHZ:
+		desired_bw_khz = MHZ_TO_KHZ(20);
+		break;
+
+	case IEEE80211_CHAN_WIDTH_40MHZ:
+		desired_bw_khz = MHZ_TO_KHZ(40);
+		break;
+
+	case IEEE80211_CHAN_WIDTH_80MHZ:
+	case IEEE80211_CHAN_WIDTH_80P80MHZ:
+		desired_bw_khz = MHZ_TO_KHZ(80);
+		break;
+
+	case IEEE80211_CHAN_WIDTH_160MHZ:
+		desired_bw_khz = MHZ_TO_KHZ(160);
+		break;
+	default:
+		REG_DBG_PRINT("Invalid channel width %d\n",
+			      chan_config->chan_width);
+		return false;
+	}
+
+	ret = reg_fits_reg_rule_sec_chans(wiphy,
+					  chan_config->center_freq1,
+					  desired_bw_khz,
+					  regd);
+
+	if (ret == false)
+		return ret;
+
+	if (chan_config->chan_width == IEEE80211_CHAN_WIDTH_80P80MHZ) {
+		ret = reg_fits_reg_rule_sec_chans(wiphy,
+						  chan_config->center_freq2,
+						  desired_bw_khz,
+						  regd);
+	}
+	return ret;
+}
+
 static bool is_ht40_not_allowed(struct ieee80211_channel *chan)
 {
 	if (!chan)
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux