diff mbox

[RFC] cfg80211: VHT regulatory

Message ID 50457491.9020604@posedge.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Mahesh Palivela Sept. 4, 2012, 3:25 a.m. UTC
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@posedge.com>
---

  include/net/cfg80211.h |   36 ++++++++++++++++
  net/wireless/reg.c     |  104 
++++++++++++++++++++++++++++++++++++++++++++++++
  2 files changed, 140 insertions(+), 0 deletions(-)

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Johannes Berg Sept. 4, 2012, 8:25 a.m. UTC | #1
On Tue, 2012-09-04 at 08:55 +0530, Mahesh Palivela wrote:

>   include/net/cfg80211.h |   36 ++++++++++++++++
>   net/wireless/reg.c     |  104 
> ++++++++++++++++++++++++++++++++++++++++++++++++

Even for an RFC patch it'd be nice to not mangle it :)

>   /**
> + * 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

I'd add a note here that the 2nd is only used for 80+80

> + * @prim_chan_freq: primary channel frequency

You said you wanted to change it to be like the standard, that's not how
it works though, the standard says (copying from your email)

dot11CurrentPrimaryChannel
       Denotes the location of the primary 20 MHz channel.
       Valid range is 1 to 200.


> +static bool reg_sec_chans_permitted(struct wiphy *wiphy,
> +				    u32 center_freq,
> +				    u32 bw_khz)
> +{
> +	struct ieee80211_channel *chan;
> +	u32 left_end_freq, right_end_freq;
> +
> +	if (center_freq == 0 || bw_khz == 0)
> +		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 subtracting 10 MHZ from each of them.
> +	 */
> +	left_end_freq -= MHZ_TO_KHZ(10);
> +	right_end_freq -= MHZ_TO_KHZ(10);

Hmm? Shouldn't you add 10 MHz to the lower end, if anything?

> +	/* 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;
> +}

Overall I'm not sure I'd go to the channel structs for this function at
all though, I'd rather go to the regulatory definition, I think that
would make more sense.

OTOH, this may be needed to keep the ability for the driver to disable
certain channels etc.

> +bool reg_chan_use_permitted(struct wiphy *wiphy,
> +			    struct ieee80211_channel_config *chan_config,
> +			    const struct ieee80211_regdomain *regd)
> +{
> +	int r;
> +	u32 desired_bw_khz = MHZ_TO_KHZ(20);
> +	const struct ieee80211_reg_rule *reg_rule = NULL;
> +	const struct ieee80211_freq_range *freq_range = NULL;

Don't initialize to values you don't need.

> +	bool ret;
> +
> +	assert_reg_lock();
> +
> +	// get chan BW from config
> +	switch (chan_config->chan_width) {
> +	case IEEE80211_CHAN_WIDTH_20MHZ_NOHT:
> +	case IEEE80211_CHAN_WIDTH_20MHZ:
> ...

> +	case IEEE80211_CHAN_WIDTH_80P80MHZ:
> +		desired_bw_khz = MHZ_TO_KHZ(160);

This is not true at all.

> +		break;
> +	}

Missing a default case with a warning/error return?

> +	r = freq_reg_info_regd(wiphy,
> +			       chan_config->prim_chan_freq,
> +			       desired_bw_khz,
> +			       &reg_rule,
> +			       regd);
> +
> +	if (r) {
> +		REG_DBG_PRINT("Disabling freq %d MHz as custom "
> +			      "regd has no rule that fits a %d MHz "
> +			      "wide channel\n",
> +			      chan_config->prim_chan_freq,
> +			      KHZ_TO_MHZ(desired_bw_khz));

That's not a good message in this context now. Clearly it came from the
channel flag settings, but now we don't do that so ...

johannes

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mahesh Palivela Sept. 5, 2012, 4:45 a.m. UTC | #2
On 09/04/2012 01:55 PM, Johannes Berg wrote:
> On Tue, 2012-09-04 at 08:55 +0530, Mahesh Palivela wrote:
>>    net/wireless/reg.c     |  104
>> ++++++++++++++++++++++++++++++++++++++++++++++++
>
> Even for an RFC patch it'd be nice to not mangle it :)
>

My email text editor issue. wrapping more than 80 char.

>> + * @center_freq2: center frequency of 2 nd frequency segment
>
> I'd add a note here that the 2nd is only used for 80+80
>

Sure

>> + * @prim_chan_freq: primary channel frequency
>
> You said you wanted to change it to be like the standard, that's not how
> it works though, the standard says (copying from your email)
>
> dot11CurrentPrimaryChannel
>         Denotes the location of the primary 20 MHz channel.
>         Valid range is 1 to 200.
>

 From that number we derive freq in kHZ. Even center freq also mentioned 
as number only. we need to use formula to derive freq in kHZ. Thought 
better hostapd convert numbers to freq value.

>> +	left_end_freq -= MHZ_TO_KHZ(10);
>> +	right_end_freq -= MHZ_TO_KHZ(10);
>
> Hmm? Shouldn't you add 10 MHz to the lower end, if anything?
>

Nope. For example 80 MHz BW, take channel 36, 40, 44 and 48. Center freq 
value is chan 42. so left end will be chan 34 and right end will be chan 
50. so I am subtracting 10MHz on both ends to get chan 36 and 48
Hope I made it clear.

>> +	/* find out all possible secondary channels */
>> +	while (left_end_freq < right_end_freq) {
>> +		chan = ieee80211_get_channel(wiphy, left_end_freq);
>
> Overall I'm not sure I'd go to the channel structs for this function at
> all though, I'd rather go to the regulatory definition, I think that
> would make more sense.
>
> OTOH, this may be needed to keep the ability for the driver to disable
> certain channels etc.
>
>> +	const struct ieee80211_reg_rule *reg_rule = NULL;
>> +	const struct ieee80211_freq_range *freq_range = NULL;
>
> Don't initialize to values you don't need.
>

Sure, will remove inits.

>> +	case IEEE80211_CHAN_WIDTH_80P80MHZ:
>> +		desired_bw_khz = MHZ_TO_KHZ(160);
>
> This is not true at all.
>

ok, will change to 80 MHz

>> +		break;
>> +	}
>
> Missing a default case with a warning/error return?
>

ok, will add default.

>> +	r = freq_reg_info_regd(wiphy,
>> +			       chan_config->prim_chan_freq,
>> +			       desired_bw_khz,
>> +			       &reg_rule,
>> +			       regd);
>> +
>> +	if (r) {
>> +		REG_DBG_PRINT("Disabling freq %d MHz as custom "
>> +			      "regd has no rule that fits a %d MHz "
>> +			      "wide channel\n",
>> +			      chan_config->prim_chan_freq,
>> +			      KHZ_TO_MHZ(desired_bw_khz));
>
> That's not a good message in this context now. Clearly it came from the
> channel flag settings, but now we don't do that so ...

OK. I will modify REG_DBG_PRINT()

>
> johannes
>
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Julian Calaby Sept. 5, 2012, 4:49 a.m. UTC | #3
Hi Mahesh,

On Wed, Sep 5, 2012 at 2:45 PM, Mahesh Palivela <maheshp@posedge.com> wrote:
> On 09/04/2012 01:55 PM, Johannes Berg wrote:
>>
>> On Tue, 2012-09-04 at 08:55 +0530, Mahesh Palivela wrote:
>>> +       left_end_freq -= MHZ_TO_KHZ(10);
>>> +       right_end_freq -= MHZ_TO_KHZ(10);
>>
>>
>> Hmm? Shouldn't you add 10 MHz to the lower end, if anything?
>>
>
> Nope. For example 80 MHz BW, take channel 36, 40, 44 and 48. Center freq
> value is chan 42. so left end will be chan 34 and right end will be chan 50.
> so I am subtracting 10MHz on both ends to get chan 36 and 48

Surely if you subtract 10MHz from chan 34, you'd end up with chan 32, right?

Thanks,
Mahesh Palivela Sept. 5, 2012, 4:54 a.m. UTC | #4
On 09/05/2012 10:19 AM, Julian Calaby wrote:
> Hi Mahesh,
>
>>>
>>>
>>> Hmm? Shouldn't you add 10 MHz to the lower end, if anything?
>>>
>>
>> Nope. For example 80 MHz BW, take channel 36, 40, 44 and 48. Center freq
>> value is chan 42. so left end will be chan 34 and right end will be chan 50.
>> so I am subtracting 10MHz on both ends to get chan 36 and 48
>
> Surely if you subtract 10MHz from chan 34, you'd end up with chan 32, right?

Very bad. I am wrong. It should be + 10 MHz. Thanks for quick response 
Julian.

>
> Thanks,
>
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 4c518f1..9a17e3d 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,23 @@  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
+ * @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 2303ee7..5a4bbe9 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1124,6 +1124,110 @@  static void reg_process_beacons(struct wiphy *wiphy)
  	wiphy_update_beacon_reg(wiphy);
  }

+static bool reg_sec_chans_permitted(struct wiphy *wiphy,
+				    u32 center_freq,
+				    u32 bw_khz)
+{
+	struct ieee80211_channel *chan;
+	u32 left_end_freq, right_end_freq;
+
+	if (center_freq == 0 || bw_khz == 0)
+		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 subtracting 10 MHZ from each of them.
+	 */
+	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)
+{
+	int r;
+	u32 desired_bw_khz = MHZ_TO_KHZ(20);
+	const struct ieee80211_reg_rule *reg_rule = NULL;
+	const struct ieee80211_freq_range *freq_range = NULL;
+	bool ret;
+
+	assert_reg_lock();
+
+	// 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:
+		desired_bw_khz = MHZ_TO_KHZ(80);
+		break;
+
+	case IEEE80211_CHAN_WIDTH_160MHZ:
+	case IEEE80211_CHAN_WIDTH_80P80MHZ:
+		desired_bw_khz = MHZ_TO_KHZ(160);
+		break;
+	}
+
+	r = freq_reg_info_regd(wiphy,
+			       chan_config->prim_chan_freq,
+			       desired_bw_khz,
+			       &reg_rule,
+			       regd);
+
+	if (r) {
+		REG_DBG_PRINT("Disabling freq %d MHz as custom "
+			      "regd has no rule that fits a %d MHz "
+			      "wide channel\n",
+			      chan_config->prim_chan_freq,
+			      KHZ_TO_MHZ(desired_bw_khz));
+		return false;
+	}
+
+	freq_range = &reg_rule->freq_range;
+
+	if (freq_range->max_bandwidth_khz < desired_bw_khz)
+		return false;
+
+	if (chan_config->chan_width == IEEE80211_CHAN_WIDTH_80P80MHZ) {
+		ret = reg_sec_chans_permitted(wiphy,
+					      chan_config->center_freq1,
+					      desired_bw_khz/2);
+		if (ret == false)
+			return ret;
+		ret = reg_sec_chans_permitted(wiphy,
+					      chan_config->center_freq2,
+					      desired_bw_khz/2);
+	} else {
+		ret = reg_sec_chans_permitted(wiphy,
+					      chan_config->center_freq1,
+					      desired_bw_khz);
+	}
+	return ret;
+}
+
  static bool is_ht40_not_allowed(struct ieee80211_channel *chan)
  {
  	if (!chan)