2014-01-25 10:24:23

by Janusz Dziedzic

[permalink] [raw]
Subject: [PATCH v3 1/2] cfg80211: add helper reg_get_regdomain() function

Add helper function that will return regdomain.
Follow the driver's regulatory domain, if present,
unless a country IE has been processed or a user
wants to help complaince further.

Signed-off-by: Janusz Dziedzic <[email protected]>
---
net/wireless/reg.c | 31 ++++++++++++++++++++-----------
1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 9b897fc..d58a09c 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -522,6 +522,25 @@ bool reg_is_valid_request(const char *alpha2)
return alpha2_equal(lr->alpha2, alpha2);
}

+static const struct ieee80211_regdomain *reg_get_regdomain(struct wiphy *wiphy)
+{
+ const struct ieee80211_regdomain *regd;
+ struct regulatory_request *lr = get_last_request();
+
+ /*
+ * Follow the driver's regulatory domain, if present, unless a country
+ * IE has been processed or a user wants to help complaince further
+ */
+ if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+ lr->initiator != NL80211_REGDOM_SET_BY_USER &&
+ wiphy->regd)
+ regd = get_wiphy_regdom(wiphy);
+ else
+ regd = get_cfg80211_regdom();
+
+ return regd;
+}
+
/* Sanity check on a regulatory rule */
static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
{
@@ -821,18 +840,8 @@ const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
u32 center_freq)
{
const struct ieee80211_regdomain *regd;
- struct regulatory_request *lr = get_last_request();

- /*
- * Follow the driver's regulatory domain, if present, unless a country
- * IE has been processed or a user wants to help complaince further
- */
- if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
- lr->initiator != NL80211_REGDOM_SET_BY_USER &&
- wiphy->regd)
- regd = get_wiphy_regdom(wiphy);
- else
- regd = get_cfg80211_regdom();
+ regd = reg_get_regdomain(wiphy);

return freq_reg_info_regd(wiphy, center_freq, regd);
}
--
1.7.9.5



2014-01-25 10:24:25

by Janusz Dziedzic

[permalink] [raw]
Subject: [PATCH v3 2/2] cfg80211: regulatory introduce maximum bandwidth calculation

In case we will get regulatory request with rule
where max_bandwidth_khz is set to 0, handle this case
as a special one.
Generally
max_bandwidth_khz == 0 mean we should calculate maximum
available bandwidth base on all frequency contiguous rules.
We don't need any chanes in CRDA or internal regulatory.
In case we need auto calculation we just have to set:

country PL: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ AUTO), (N/A, 20)
(5250 - 5330 @ AUTO), (N/A, 20), DFS
(5490 - 5710 @ 80), (N/A, 27), DFS

This mean we will calculate maximum bw for rules where
AUTO (N/A) was set, 160MHz in example above. So we will
get:

(5170 - 5250 @ 160), (N/A, 20)
(5250 - 5330 @ 160), (N/A, 20), DFS

In other case:
country FR: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ AUTO), (N/A, 20)
(5250 - 5330 @ 80), (N/A, 20), DFS
(5490 - 5710 @ 80), (N/A, 27), DFS

We will get:
(5170 - 5250 @ 80), (N/A, 20)
(5250 - 5330 @ 80), (N/A, 20), DFS

Base on this calculations we will set correct channel
bandwidth flags.
I decided to don't change freq_range->max_bandwidth_khz
because they are const.

Signed-off-by: Janusz Dziedzic <[email protected]>
---
*V3 - don't introduce any new flag, base only on freq_range->max_bandwidth_khz
if == 0 handle as a AUTO calculation request.

net/wireless/reg.c | 120 +++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 104 insertions(+), 16 deletions(-)

diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index d58a09c..7fbaade 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -541,6 +541,61 @@ static const struct ieee80211_regdomain *reg_get_regdomain(struct wiphy *wiphy)
return regd;
}

+static unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
+ const struct ieee80211_reg_rule *rule)
+{
+ const struct ieee80211_freq_range *freq_range = &rule->freq_range;
+ const struct ieee80211_freq_range *freq_range_tmp;
+ const struct ieee80211_reg_rule *tmp;
+ u32 start_freq, end_freq, idx, no;
+
+ for (idx = 0; idx < rd->n_reg_rules; idx++)
+ if (rule == &rd->reg_rules[idx])
+ break;
+
+ if (idx == rd->n_reg_rules)
+ return 0;
+
+ /* get start_freq */
+ no = idx;
+
+ while (no) {
+ tmp = &rd->reg_rules[--no];
+ freq_range_tmp = &tmp->freq_range;
+
+ if (freq_range_tmp->end_freq_khz < freq_range->start_freq_khz)
+ break;
+
+ if (freq_range_tmp->max_bandwidth_khz)
+ break;
+
+ freq_range = freq_range_tmp;
+ };
+
+ start_freq = freq_range->start_freq_khz;
+
+ /* get end_freq */
+ freq_range = &rule->freq_range;
+ no = idx;
+
+ while (no < rd->n_reg_rules - 1) {
+ tmp = &rd->reg_rules[++no];
+ freq_range_tmp = &tmp->freq_range;
+
+ if (freq_range_tmp->start_freq_khz > freq_range->end_freq_khz)
+ break;
+
+ if (freq_range_tmp->max_bandwidth_khz)
+ break;
+
+ freq_range = freq_range_tmp;
+ }
+
+ end_freq = freq_range->end_freq_khz;
+
+ return end_freq - start_freq;
+}
+
/* Sanity check on a regulatory rule */
static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
{
@@ -649,7 +704,9 @@ reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1,
* Helper for regdom_intersect(), this does the real
* mathematical intersection fun
*/
-static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1,
+static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
+ const struct ieee80211_regdomain *rd2,
+ const struct ieee80211_reg_rule *rule1,
const struct ieee80211_reg_rule *rule2,
struct ieee80211_reg_rule *intersected_rule)
{
@@ -657,7 +714,7 @@ static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1,
struct ieee80211_freq_range *freq_range;
const struct ieee80211_power_rule *power_rule1, *power_rule2;
struct ieee80211_power_rule *power_rule;
- u32 freq_diff;
+ u32 freq_diff, max_bandwidth1, max_bandwidth2;

freq_range1 = &rule1->freq_range;
freq_range2 = &rule2->freq_range;
@@ -671,8 +728,16 @@ static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1,
freq_range2->start_freq_khz);
freq_range->end_freq_khz = min(freq_range1->end_freq_khz,
freq_range2->end_freq_khz);
- freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz,
- freq_range2->max_bandwidth_khz);
+
+ max_bandwidth1 = freq_range1->max_bandwidth_khz;
+ if (!max_bandwidth1)
+ max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1);
+
+ max_bandwidth2 = freq_range1->max_bandwidth_khz;
+ if (!max_bandwidth1)
+ max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2);
+
+ freq_range->max_bandwidth_khz = min(max_bandwidth1, max_bandwidth2);

freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
if (freq_range->max_bandwidth_khz > freq_diff)
@@ -732,7 +797,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
rule1 = &rd1->reg_rules[x];
for (y = 0; y < rd2->n_reg_rules; y++) {
rule2 = &rd2->reg_rules[y];
- if (!reg_rules_intersect(rule1, rule2, &dummy_rule))
+ if (!reg_rules_intersect(rd1, rd2, rule1, rule2,
+ &dummy_rule))
num_rules++;
}
}
@@ -757,7 +823,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
* a memcpy()
*/
intersected_rule = &rd->reg_rules[rule_idx];
- r = reg_rules_intersect(rule1, rule2, intersected_rule);
+ r = reg_rules_intersect(rd1, rd2, rule1, rule2,
+ intersected_rule);
/*
* No need to memset here the intersected rule here as
* we're not using the stack anymore
@@ -912,6 +979,8 @@ static void handle_channel(struct wiphy *wiphy,
const struct ieee80211_freq_range *freq_range = NULL;
struct wiphy *request_wiphy = NULL;
struct regulatory_request *lr = get_last_request();
+ const struct ieee80211_regdomain *regd;
+ u32 max_bandwidth_khz;

request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);

@@ -953,11 +1022,18 @@ static void handle_channel(struct wiphy *wiphy,
power_rule = &reg_rule->power_rule;
freq_range = &reg_rule->freq_range;

- if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40))
+ max_bandwidth_khz = freq_range->max_bandwidth_khz;
+ /* Check if auto calculation requested */
+ if (!max_bandwidth_khz) {
+ regd = reg_get_regdomain(wiphy);
+ max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
+ }
+
+ if (max_bandwidth_khz < MHZ_TO_KHZ(40))
bw_flags = IEEE80211_CHAN_NO_HT40;
- if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80))
+ if (max_bandwidth_khz < MHZ_TO_KHZ(80))
bw_flags |= IEEE80211_CHAN_NO_80MHZ;
- if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160))
+ if (max_bandwidth_khz < MHZ_TO_KHZ(160))
bw_flags |= IEEE80211_CHAN_NO_160MHZ;

if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
@@ -1343,6 +1419,7 @@ static void handle_channel_custom(struct wiphy *wiphy,
const struct ieee80211_reg_rule *reg_rule = NULL;
const struct ieee80211_power_rule *power_rule = NULL;
const struct ieee80211_freq_range *freq_range = NULL;
+ u32 max_bandwidth_khz;

reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq),
regd);
@@ -1360,11 +1437,16 @@ static void handle_channel_custom(struct wiphy *wiphy,
power_rule = &reg_rule->power_rule;
freq_range = &reg_rule->freq_range;

- if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40))
+ max_bandwidth_khz = freq_range->max_bandwidth_khz;
+ /* Check if auto calculation requested */
+ if (!max_bandwidth_khz)
+ max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
+
+ if (max_bandwidth_khz < MHZ_TO_KHZ(40))
bw_flags = IEEE80211_CHAN_NO_HT40;
- if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80))
+ if (max_bandwidth_khz < MHZ_TO_KHZ(80))
bw_flags |= IEEE80211_CHAN_NO_80MHZ;
- if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160))
+ if (max_bandwidth_khz < MHZ_TO_KHZ(160))
bw_flags |= IEEE80211_CHAN_NO_160MHZ;

chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags;
@@ -2156,6 +2238,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
const struct ieee80211_reg_rule *reg_rule = NULL;
const struct ieee80211_freq_range *freq_range = NULL;
const struct ieee80211_power_rule *power_rule = NULL;
+ char bw[32];

pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n");

@@ -2164,22 +2247,27 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
freq_range = &reg_rule->freq_range;
power_rule = &reg_rule->power_rule;

+ if (!freq_range->max_bandwidth_khz)
+ snprintf(bw, 32, "%d KHz, AUTO", reg_get_max_bandwidth(rd, reg_rule));
+ else
+ snprintf(bw, 32, "%d KHz", freq_range->max_bandwidth_khz);
+
/*
* There may not be documentation for max antenna gain
* in certain regions
*/
if (power_rule->max_antenna_gain)
- pr_info(" (%d KHz - %d KHz @ %d KHz), (%d mBi, %d mBm)\n",
+ pr_info(" (%d KHz - %d KHz @ %s), (%d mBi, %d mBm)\n",
freq_range->start_freq_khz,
freq_range->end_freq_khz,
- freq_range->max_bandwidth_khz,
+ bw,
power_rule->max_antenna_gain,
power_rule->max_eirp);
else
- pr_info(" (%d KHz - %d KHz @ %d KHz), (N/A, %d mBm)\n",
+ pr_info(" (%d KHz - %d KHz @ %s), (N/A, %d mBm)\n",
freq_range->start_freq_khz,
freq_range->end_freq_khz,
- freq_range->max_bandwidth_khz,
+ bw,
power_rule->max_eirp);
}
}
--
1.7.9.5


2014-01-25 16:16:14

by Jonas Gorski

[permalink] [raw]
Subject: Re: [PATCH v3 2/2] cfg80211: regulatory introduce maximum bandwidth calculation

Hi,

On Sat, Jan 25, 2014 at 11:24 AM, Janusz Dziedzic
<[email protected]> wrote:
> In case we will get regulatory request with rule
> where max_bandwidth_khz is set to 0, handle this case
> as a special one.
> Generally
> max_bandwidth_khz == 0 mean we should calculate maximum
> available bandwidth base on all frequency contiguous rules.
> We don't need any chanes in CRDA or internal regulatory.
> In case we need auto calculation we just have to set:
>
> country PL: DFS-ETSI
> (2402 - 2482 @ 40), (N/A, 20)
> (5170 - 5250 @ AUTO), (N/A, 20)
> (5250 - 5330 @ AUTO), (N/A, 20), DFS
> (5490 - 5710 @ 80), (N/A, 27), DFS
>
> This mean we will calculate maximum bw for rules where
> AUTO (N/A) was set, 160MHz in example above. So we will
> get:
>
> (5170 - 5250 @ 160), (N/A, 20)
> (5250 - 5330 @ 160), (N/A, 20), DFS
>
> In other case:
> country FR: DFS-ETSI
> (2402 - 2482 @ 40), (N/A, 20)
> (5170 - 5250 @ AUTO), (N/A, 20)
> (5250 - 5330 @ 80), (N/A, 20), DFS
> (5490 - 5710 @ 80), (N/A, 27), DFS
>
> We will get:
> (5170 - 5250 @ 80), (N/A, 20)
> (5250 - 5330 @ 80), (N/A, 20), DFS
>
> Base on this calculations we will set correct channel
> bandwidth flags.
> I decided to don't change freq_range->max_bandwidth_khz
> because they are const.
>
> Signed-off-by: Janusz Dziedzic <[email protected]>
> ---
> *V3 - don't introduce any new flag, base only on freq_range->max_bandwidth_khz
> if == 0 handle as a AUTO calculation request.
>
> net/wireless/reg.c | 120 +++++++++++++++++++++++++++++++++++++++++++++-------
> 1 file changed, 104 insertions(+), 16 deletions(-)
>
> diff --git a/net/wireless/reg.c b/net/wireless/reg.c
> index d58a09c..7fbaade 100644
> --- a/net/wireless/reg.c
> +++ b/net/wireless/reg.c
> @@ -541,6 +541,61 @@ static const struct ieee80211_regdomain *reg_get_regdomain(struct wiphy *wiphy)
> return regd;
> }
>
> +static unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
> + const struct ieee80211_reg_rule *rule)
> +{
> + const struct ieee80211_freq_range *freq_range = &rule->freq_range;
> + const struct ieee80211_freq_range *freq_range_tmp;
> + const struct ieee80211_reg_rule *tmp;
> + u32 start_freq, end_freq, idx, no;
> +
> + for (idx = 0; idx < rd->n_reg_rules; idx++)
> + if (rule == &rd->reg_rules[idx])
> + break;
> +
> + if (idx == rd->n_reg_rules)
> + return 0;
> +
> + /* get start_freq */
> + no = idx;
> +
> + while (no) {
> + tmp = &rd->reg_rules[--no];
> + freq_range_tmp = &tmp->freq_range;
> +
> + if (freq_range_tmp->end_freq_khz < freq_range->start_freq_khz)
> + break;
> +
> + if (freq_range_tmp->max_bandwidth_khz)
> + break;
> +
> + freq_range = freq_range_tmp;
> + };
> +
> + start_freq = freq_range->start_freq_khz;
> +
> + /* get end_freq */
> + freq_range = &rule->freq_range;
> + no = idx;
> +
> + while (no < rd->n_reg_rules - 1) {
> + tmp = &rd->reg_rules[++no];
> + freq_range_tmp = &tmp->freq_range;
> +
> + if (freq_range_tmp->start_freq_khz > freq_range->end_freq_khz)
> + break;
> +
> + if (freq_range_tmp->max_bandwidth_khz)
> + break;
> +
> + freq_range = freq_range_tmp;
> + }
> +
> + end_freq = freq_range->end_freq_khz;
> +
> + return end_freq - start_freq;
> +}
> +
> /* Sanity check on a regulatory rule */
> static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
> {
> @@ -649,7 +704,9 @@ reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1,
> * Helper for regdom_intersect(), this does the real
> * mathematical intersection fun
> */
> -static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1,
> +static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
> + const struct ieee80211_regdomain *rd2,
> + const struct ieee80211_reg_rule *rule1,
> const struct ieee80211_reg_rule *rule2,
> struct ieee80211_reg_rule *intersected_rule)
> {
> @@ -657,7 +714,7 @@ static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1,
> struct ieee80211_freq_range *freq_range;
> const struct ieee80211_power_rule *power_rule1, *power_rule2;
> struct ieee80211_power_rule *power_rule;
> - u32 freq_diff;
> + u32 freq_diff, max_bandwidth1, max_bandwidth2;
>
> freq_range1 = &rule1->freq_range;
> freq_range2 = &rule2->freq_range;
> @@ -671,8 +728,16 @@ static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1,
> freq_range2->start_freq_khz);
> freq_range->end_freq_khz = min(freq_range1->end_freq_khz,
> freq_range2->end_freq_khz);
> - freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz,
> - freq_range2->max_bandwidth_khz);
> +
> + max_bandwidth1 = freq_range1->max_bandwidth_khz;
> + if (!max_bandwidth1)
> + max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1);
> +
> + max_bandwidth2 = freq_range1->max_bandwidth_khz;

I guess you want to use freq_range2 here ...

> + if (!max_bandwidth1)

and check max_bandwidth2 here.

> + max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2);
> +
> + freq_range->max_bandwidth_khz = min(max_bandwidth1, max_bandwidth2);
>
> freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
> if (freq_range->max_bandwidth_khz > freq_diff)

[snip rest which seemed fine on a first glance]


Regards
Jonas

2014-01-29 13:13:50

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v3 2/2] cfg80211: regulatory introduce maximum bandwidth calculation

On Sat, 2014-01-25 at 11:24 +0100, Janusz Dziedzic wrote:
> In case we will get regulatory request with rule
> where max_bandwidth_khz is set to 0, handle this case
> as a special one.
> Generally
> max_bandwidth_khz == 0 mean we should calculate maximum
> available bandwidth base on all frequency contiguous rules.

That's a pretty good solution too, without a flag, but I think you
should have a little bit of documentation changes in nl80211.h (and
probably change nl80211 to not actually require a zero attribute for
auto?)

johannes


2014-01-29 13:18:10

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v3 1/2] cfg80211: add helper reg_get_regdomain() function

On Sat, 2014-01-25 at 11:24 +0100, Janusz Dziedzic wrote:
> Add helper function that will return regdomain.
> Follow the driver's regulatory domain, if present,
> unless a country IE has been processed or a user
> wants to help complaince further.

Applied, but I removed the 'reg' variable since it seemed useless in the
new function.

johannes


2014-01-29 13:16:05

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v3 2/2] cfg80211: regulatory introduce maximum bandwidth calculation

[please trim quotes]

> > @@ -671,8 +728,16 @@ static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1,
> > freq_range2->start_freq_khz);
> > freq_range->end_freq_khz = min(freq_range1->end_freq_khz,
> > freq_range2->end_freq_khz);
> > - freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz,
> > - freq_range2->max_bandwidth_khz);
> > +
> > + max_bandwidth1 = freq_range1->max_bandwidth_khz;
> > + if (!max_bandwidth1)
> > + max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1);
> > +
> > + max_bandwidth2 = freq_range1->max_bandwidth_khz;
>
> I guess you want to use freq_range2 here ...

That does seem likely :)

> > + if (!max_bandwidth1)
>
> and check max_bandwidth2 here.
>
> > + max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2);
> > +
> > + freq_range->max_bandwidth_khz = min(max_bandwidth1, max_bandwidth2);

I'm not sure if you shouldn't do the reg_get_max_bandwidth() on the
result though rather than on the input domains? But I haven't thought
hard about it.

joahnnes