* [PATCH 0/6] cfg80211: few fixes and adds support for multiple reg hints
@ 2009-01-08 1:43 Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 1/6] cfg80211: call reg_notifier() once Luis R. Rodriguez
0 siblings, 1 reply; 13+ messages in thread
From: Luis R. Rodriguez @ 2009-01-08 1:43 UTC (permalink / raw)
To: johannes, johannes, linville; +Cc: Luis R. Rodriguez, linux-wireless
This series fixes a couple of issues with the current 11d code and also
adds support for multiple devices providing a regulatory_hint().
Luis R. Rodriguez (6):
cfg80211: call reg_notifier() once
cfg80211: make handle_band() and handle_channel() wiphy specific
cfg80211: allow multiple driver regulatory_hints()
cfg80211: fix typo on message after intersection
cfg80211: Fix regression with 11d on bands
cfg80211: Fix parsed country IE info for 5 GHz
include/net/wireless.h | 6 +
net/wireless/reg.c | 238 ++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 218 insertions(+), 26 deletions(-)
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/6] cfg80211: call reg_notifier() once
2009-01-08 1:43 [PATCH 0/6] cfg80211: few fixes and adds support for multiple reg hints Luis R. Rodriguez
@ 2009-01-08 1:43 ` Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 2/6] cfg80211: make handle_band() and handle_channel() wiphy specific Luis R. Rodriguez
2009-01-08 12:58 ` [PATCH 1/6] cfg80211: call reg_notifier() once Johannes Berg
0 siblings, 2 replies; 13+ messages in thread
From: Luis R. Rodriguez @ 2009-01-08 1:43 UTC (permalink / raw)
To: johannes, johannes, linville; +Cc: Luis R. Rodriguez, linux-wireless
We are calling the reg_notifier() callback per band, this is
not necessary, just call it once.
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
net/wireless/reg.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 4f87753..2f2ba92 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -841,9 +841,9 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (wiphy->bands[band])
handle_band(wiphy->bands[band]);
- if (wiphy->reg_notifier)
- wiphy->reg_notifier(wiphy, setby);
}
+ if (wiphy->reg_notifier)
+ wiphy->reg_notifier(wiphy, setby);
}
/* Return value which can be used by ignore_request() to indicate
--
1.6.1.rc3.51.g5832d
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/6] cfg80211: make handle_band() and handle_channel() wiphy specific
2009-01-08 1:43 ` [PATCH 1/6] cfg80211: call reg_notifier() once Luis R. Rodriguez
@ 2009-01-08 1:43 ` Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 3/6] cfg80211: allow multiple driver regulatory_hints() Luis R. Rodriguez
2009-01-08 12:58 ` [PATCH 2/6] cfg80211: make handle_band() and handle_channel() wiphy specific Johannes Berg
2009-01-08 12:58 ` [PATCH 1/6] cfg80211: call reg_notifier() once Johannes Berg
1 sibling, 2 replies; 13+ messages in thread
From: Luis R. Rodriguez @ 2009-01-08 1:43 UTC (permalink / raw)
To: johannes, johannes, linville; +Cc: Luis R. Rodriguez, linux-wireless
This allows us to make more wiphy specific judgements when
handling the channels later on.
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
net/wireless/reg.c | 25 +++++++++++++++++++------
1 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 2f2ba92..87b3011 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -778,13 +778,22 @@ static int freq_reg_info(u32 center_freq, u32 *bandwidth,
return !max_bandwidth;
}
-static void handle_channel(struct ieee80211_channel *chan)
+static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
+ unsigned int chan_idx)
{
int r;
- u32 flags = chan->orig_flags;
+ u32 flags;
u32 max_bandwidth = 0;
const struct ieee80211_reg_rule *reg_rule = NULL;
const struct ieee80211_power_rule *power_rule = NULL;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *chan;
+
+ sband = wiphy->bands[band];
+ BUG_ON(chan_idx >= sband->n_channels);
+ chan = &sband->channels[chan_idx];
+
+ flags = chan->orig_flags;
r = freq_reg_info(MHZ_TO_KHZ(chan->center_freq),
&max_bandwidth, ®_rule);
@@ -808,12 +817,16 @@ static void handle_channel(struct ieee80211_channel *chan)
chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);
}
-static void handle_band(struct ieee80211_supported_band *sband)
+static void handle_band(struct wiphy *wiphy, enum ieee80211_band band)
{
- int i;
+ unsigned int i;
+ struct ieee80211_supported_band *sband;
+
+ BUG_ON(!wiphy->bands[band]);
+ sband = wiphy->bands[band];
for (i = 0; i < sband->n_channels; i++)
- handle_channel(&sband->channels[i]);
+ handle_channel(wiphy, band, i);
}
static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby)
@@ -840,7 +853,7 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
enum ieee80211_band band;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (wiphy->bands[band])
- handle_band(wiphy->bands[band]);
+ handle_band(wiphy, band);
}
if (wiphy->reg_notifier)
wiphy->reg_notifier(wiphy, setby);
--
1.6.1.rc3.51.g5832d
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 3/6] cfg80211: allow multiple driver regulatory_hints()
2009-01-08 1:43 ` [PATCH 2/6] cfg80211: make handle_band() and handle_channel() wiphy specific Luis R. Rodriguez
@ 2009-01-08 1:43 ` Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 4/6] cfg80211: fix typo on message after intersection Luis R. Rodriguez
2009-01-08 12:59 ` [PATCH 3/6] cfg80211: allow multiple driver regulatory_hints() Johannes Berg
2009-01-08 12:58 ` [PATCH 2/6] cfg80211: make handle_band() and handle_channel() wiphy specific Johannes Berg
1 sibling, 2 replies; 13+ messages in thread
From: Luis R. Rodriguez @ 2009-01-08 1:43 UTC (permalink / raw)
To: johannes, johannes, linville; +Cc: Luis R. Rodriguez, linux-wireless
We add support for multiple drivers to provide a regulatory_hint()
on a system by adding a wiphy specific regulatory domain cache.
This allows drivers to keep around cache their own regulatory domain
structure queried from CRDA.
We handle conflicts by intersecting multiple regulatory domains,
each driver will stick to its own regulatory domain though unless
a country IE has been received and processed.
If the user already requested a regulatory domain and a driver
requests the same regulatory domain then simply copy to the
driver's regd the same regulatory domain and do not call
CRDA, do not collect $200.
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
include/net/wireless.h | 6 +++
net/wireless/reg.c | 109 ++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 102 insertions(+), 13 deletions(-)
diff --git a/include/net/wireless.h b/include/net/wireless.h
index aedefa5..f57f12f 100644
--- a/include/net/wireless.h
+++ b/include/net/wireless.h
@@ -187,6 +187,10 @@ struct ieee80211_supported_band {
* we will disregard the first regulatory hint (when the
* initiator is %REGDOM_SET_BY_CORE).
* @reg_notifier: the driver's regulatory notification callback
+ * @regd: the driver's regulatory domain, if one was requested via
+ * the regulatory_hint() API. This can be used by the driver
+ * on the reg_notifier() if it chooses to ignore future
+ * regulatory domain changes caused by other drivers.
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -213,6 +217,8 @@ struct wiphy {
/* fields below are read-only, assigned by cfg80211 */
+ const struct ieee80211_regdomain *regd;
+
/* the item in /sys/class/ieee80211/ points to this,
* you need use set_wiphy_dev() (see below) */
struct device dev;
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 87b3011..10a3b11 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -742,29 +742,42 @@ static u32 map_regdom_flags(u32 rd_flags)
/**
* freq_reg_info - get regulatory information for the given frequency
+ * @wiphy: the wiphy for which we want to process this rule for
* @center_freq: Frequency in KHz for which we want regulatory information for
* @bandwidth: the bandwidth requirement you have in KHz, if you do not have one
* you can set this to 0. If this frequency is allowed we then set
* this value to the maximum allowed bandwidth.
* @reg_rule: the regulatory rule which we have for this frequency
*
- * Use this function to get the regulatory rule for a specific frequency.
+ * Use this function to get the regulatory rule for a specific frequency on
+ * a given wireless device. If the device has a specific regulatory domain
+ * it wants to follow we respect that unless a country IE has been received
+ * and processed already.
*/
-static int freq_reg_info(u32 center_freq, u32 *bandwidth,
+static int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
const struct ieee80211_reg_rule **reg_rule)
{
int i;
+ const struct ieee80211_regdomain *regd;
u32 max_bandwidth = 0;
- if (!cfg80211_regdomain)
+ regd = cfg80211_regdomain;
+
+ /* Follow the driver's regulatory domain, if present, unless a country
+ * IE has been processed */
+ if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE &&
+ wiphy->regd)
+ regd = wiphy->regd;
+
+ if (!regd)
return -EINVAL;
- for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) {
+ for (i = 0; i < regd->n_reg_rules; i++) {
const struct ieee80211_reg_rule *rr;
const struct ieee80211_freq_range *fr = NULL;
const struct ieee80211_power_rule *pr = NULL;
- rr = &cfg80211_regdomain->reg_rules[i];
+ rr = ®d->reg_rules[i];
fr = &rr->freq_range;
pr = &rr->power_rule;
max_bandwidth = freq_max_bandwidth(fr, center_freq);
@@ -795,7 +808,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
flags = chan->orig_flags;
- r = freq_reg_info(MHZ_TO_KHZ(chan->center_freq),
+ r = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq),
&max_bandwidth, ®_rule);
if (r) {
@@ -859,6 +872,30 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
wiphy->reg_notifier(wiphy, setby);
}
+static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
+ const struct ieee80211_regdomain *src_regd)
+{
+ struct ieee80211_regdomain *regd;
+ int size_of_regd = 0;
+ unsigned int i;
+
+ size_of_regd = sizeof(struct ieee80211_regdomain) +
+ ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
+
+ regd = kzalloc(size_of_regd, GFP_KERNEL);
+ if (!regd)
+ return -ENOMEM;
+
+ memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
+
+ for (i = 0; i < src_regd->n_reg_rules; i++)
+ memcpy(®d->reg_rules[i], &src_regd->reg_rules[i],
+ sizeof(struct ieee80211_reg_rule));
+
+ *dst_regd = regd;
+ return 0;
+}
+
/* Return value which can be used by ignore_request() to indicate
* it has been determined we should intersect two regulatory domains */
#define REG_INTERSECT 1
@@ -906,9 +943,9 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
}
return REG_INTERSECT;
case REGDOM_SET_BY_DRIVER:
- if (last_request->initiator == REGDOM_SET_BY_DRIVER)
- return -EALREADY;
- return 0;
+ if (last_request->initiator == REGDOM_SET_BY_CORE)
+ return 0;
+ return REG_INTERSECT;
case REGDOM_SET_BY_USER:
if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
return REG_INTERSECT;
@@ -935,11 +972,28 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
r = ignore_request(wiphy, set_by, alpha2);
- if (r == REG_INTERSECT)
+ if (r == REG_INTERSECT) {
+ if (set_by == REGDOM_SET_BY_DRIVER) {
+ r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
+ if (r)
+ return r;
+ }
intersect = true;
- else if (r)
+ } else if (r) {
+ /* If the regulatory domain being requested by the
+ * driver has already been set just copy it to the
+ * wiphy */
+ if (r == -EALREADY && set_by == REGDOM_SET_BY_DRIVER) {
+ r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
+ if (r)
+ return r;
+ r = -EALREADY;
+ goto new_request;
+ }
return r;
+ }
+new_request:
request = kzalloc(sizeof(struct regulatory_request),
GFP_KERNEL);
if (!request)
@@ -955,6 +1009,11 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
kfree(last_request);
last_request = request;
+
+ /* When r == REG_INTERSECT we do need to call CRDA */
+ if (r < 0)
+ return r;
+
/*
* Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled
* AND if CRDA is NOT present nothing will happen, if someone
@@ -1248,6 +1307,23 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
}
if (!last_request->intersect) {
+ int r;
+
+ if (last_request->initiator != REGDOM_SET_BY_DRIVER) {
+ reset_regdomains();
+ cfg80211_regdomain = rd;
+ return 0;
+ }
+
+ /* For a driver hint, lets copy the regulatory domain the
+ * driver wanted to the wiphy to deal with conflicts */
+
+ BUG_ON(last_request->wiphy->regd);
+
+ r = reg_copy_regd(&last_request->wiphy->regd, rd);
+ if (r)
+ return r;
+
reset_regdomains();
cfg80211_regdomain = rd;
return 0;
@@ -1261,8 +1337,14 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
if (!intersected_rd)
return -EINVAL;
- /* We can trash what CRDA provided now */
- kfree(rd);
+ /* We can trash what CRDA provided now.
+ * However if a driver requested this specific regulatory
+ * domain we keep it for its private use */
+ if (last_request->initiator == REGDOM_SET_BY_DRIVER)
+ last_request->wiphy->regd = rd;
+ else
+ kfree(rd);
+
rd = NULL;
reset_regdomains();
@@ -1346,6 +1428,7 @@ int set_regdom(const struct ieee80211_regdomain *rd)
/* Caller must hold cfg80211_drv_mutex */
void reg_device_remove(struct wiphy *wiphy)
{
+ kfree(wiphy->regd);
if (!last_request || !last_request->wiphy)
return;
if (last_request->wiphy != wiphy)
--
1.6.1.rc3.51.g5832d
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 4/6] cfg80211: fix typo on message after intersection
2009-01-08 1:43 ` [PATCH 3/6] cfg80211: allow multiple driver regulatory_hints() Luis R. Rodriguez
@ 2009-01-08 1:43 ` Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 5/6] cfg80211: Fix regression with 11d on bands Luis R. Rodriguez
2009-01-08 13:00 ` [PATCH 4/6] cfg80211: fix typo on message after intersection Johannes Berg
2009-01-08 12:59 ` [PATCH 3/6] cfg80211: allow multiple driver regulatory_hints() Johannes Berg
1 sibling, 2 replies; 13+ messages in thread
From: Luis R. Rodriguez @ 2009-01-08 1:43 UTC (permalink / raw)
To: johannes, johannes, linville; +Cc: Luis R. Rodriguez, linux-wireless
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
net/wireless/reg.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 10a3b11..3d56a1d 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1205,7 +1205,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
"domain intersected: \n");
} else
printk(KERN_INFO "cfg80211: Current regulatory "
- "intersected: \n");
+ "domain intersected: \n");
} else if (is_world_regdom(rd->alpha2))
printk(KERN_INFO "cfg80211: World regulatory "
"domain updated:\n");
--
1.6.1.rc3.51.g5832d
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 5/6] cfg80211: Fix regression with 11d on bands
2009-01-08 1:43 ` [PATCH 4/6] cfg80211: fix typo on message after intersection Luis R. Rodriguez
@ 2009-01-08 1:43 ` Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 6/6] cfg80211: Fix parsed country IE info for 5 GHz Luis R. Rodriguez
2009-01-08 13:03 ` [PATCH 5/6] cfg80211: Fix regression with 11d on bands Johannes Berg
2009-01-08 13:00 ` [PATCH 4/6] cfg80211: fix typo on message after intersection Johannes Berg
1 sibling, 2 replies; 13+ messages in thread
From: Luis R. Rodriguez @ 2009-01-08 1:43 UTC (permalink / raw)
To: johannes, johannes, linville; +Cc: Luis R. Rodriguez, linux-wireless
This fixes a regression on disallowing bands introduced with the new
802.11d support. The issue is that IEEE-802.11 allows APs to send
a subset of what a country regulatory domain defines. This was clarified
in this document:
http://tinyurl.com/11d-clarification
As such it is possible, and this is what is done in practice, that a
single band 2.4 GHz AP will only send 2.4 GHz band regulatory information
through the 802.11 country information element and then the current
intersection with what CRDA provided yields a regulatory domain with
no 5 GHz information -- even though that country may actually allow
5 GHz operation. We correct this by only applying the intersection rules
on a channel if the the intersection yields a regulatory rule on the
same band the channel is on.
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
net/wireless/reg.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 75 insertions(+), 2 deletions(-)
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 3d56a1d..bea98ed 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -421,6 +421,31 @@ static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range,
return 0;
}
+/**
+ * freq_in_rule_band - tells us if a frequency is in a frequency band
+ * @freq_range: frequency rule we want to query
+ * @freq_khz: frequency we are inquiring about
+ *
+ * This lets us know if a specific frequency rule is or is not relevant to
+ * a specific frequency's band. Bands are device specific and artificial
+ * definitions (the "2.4 GHz band" and the "5 GHz band"), however it is
+ * safe for now to assume that a frequency rule should not be part of a
+ * frequency's band if the start freq or end freq are off by more than 2 GHz.
+ * This resolution can be lowered and should be considered as we add
+ * regulatory rule support for other "bands".
+ **/
+static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
+ u32 freq_khz)
+{
+#define ONE_GHZ_IN_KHZ 1000000
+ if (abs(freq_khz - freq_range->start_freq_khz) <= (2 * ONE_GHZ_IN_KHZ))
+ return true;
+ if (abs(freq_khz - freq_range->end_freq_khz) <= (2 * ONE_GHZ_IN_KHZ))
+ return true;
+ return false;
+#undef ONE_GHZ_IN_KHZ
+}
+
/* Converts a country IE to a regulatory domain. A regulatory domain
* structure has a lot of information which the IE doesn't yet have,
* so for the other values we use upper max values as we will intersect
@@ -753,11 +778,19 @@ static u32 map_regdom_flags(u32 rd_flags)
* a given wireless device. If the device has a specific regulatory domain
* it wants to follow we respect that unless a country IE has been received
* and processed already.
+ *
+ * Returns 0 if it was able to find a valid regulatory rule which does
+ * apply to the given center_freq otherwise it returns non-zero. It will
+ * also return -ERANGE if we determine the given center_freq does not even have
+ * a regulatory rule for a frequency range in the center_freq's band. See
+ * freq_in_rule_band() for our current definition of a band -- this is purely
+ * subjective and right now its 802.11 specific.
*/
static int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
const struct ieee80211_reg_rule **reg_rule)
{
int i;
+ bool band_rule_found = false;
const struct ieee80211_regdomain *regd;
u32 max_bandwidth = 0;
@@ -780,7 +813,15 @@ static int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
rr = ®d->reg_rules[i];
fr = &rr->freq_range;
pr = &rr->power_rule;
+
+ /* We only need to know if one frequency rule was
+ * was in center_freq's band, that's enough, so lets
+ * not overwrite it once found */
+ if (!band_rule_found)
+ band_rule_found = freq_in_rule_band(fr, center_freq);
+
max_bandwidth = freq_max_bandwidth(fr, center_freq);
+
if (max_bandwidth && *bandwidth <= max_bandwidth) {
*reg_rule = rr;
*bandwidth = max_bandwidth;
@@ -788,6 +829,9 @@ static int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
}
}
+ if (!band_rule_found)
+ return -ERANGE;
+
return !max_bandwidth;
}
@@ -812,8 +856,37 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
&max_bandwidth, ®_rule);
if (r) {
- flags |= IEEE80211_CHAN_DISABLED;
- chan->flags = flags;
+ /* This means no regulatory rule was found in the country IE
+ * with a frequency range on the center_freq's band, since
+ * IEEE-802.11 allows for a country IE to have a subset of the
+ * regulatory information provided in a country we ignore
+ * disabling the channel unless at least one reg rule was
+ * found on the center_freq's band. For details see this
+ * clarification:
+ *
+ * http://tinyurl.com/11d-clarification
+ */
+ if (r == -ERANGE &&
+ last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
+#ifdef CONFIG_CFG80211_REG_DEBUG
+ printk(KERN_DEBUG "cfg80211: Leaving channel %d MHz "
+ "intact on %s - no rule found in band on "
+ "Country IE\n",
+ chan->center_freq, wiphy_name(wiphy));
+#endif
+ } else {
+ /* In this case we know the country IE has at least one reg rule
+ * for the band so we respect its band definitions */
+#ifdef CONFIG_CFG80211_REG_DEBUG
+ if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
+ printk(KERN_DEBUG "cfg80211: Disabling "
+ "channel %d MHz on %s due to "
+ "Country IE\n",
+ chan->center_freq, wiphy_name(wiphy));
+#endif
+ flags |= IEEE80211_CHAN_DISABLED;
+ chan->flags = flags;
+ }
return;
}
--
1.6.1.rc3.51.g5832d
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 6/6] cfg80211: Fix parsed country IE info for 5 GHz
2009-01-08 1:43 ` [PATCH 5/6] cfg80211: Fix regression with 11d on bands Luis R. Rodriguez
@ 2009-01-08 1:43 ` Luis R. Rodriguez
2009-01-08 13:04 ` Johannes Berg
2009-01-08 13:03 ` [PATCH 5/6] cfg80211: Fix regression with 11d on bands Johannes Berg
1 sibling, 1 reply; 13+ messages in thread
From: Luis R. Rodriguez @ 2009-01-08 1:43 UTC (permalink / raw)
To: johannes, johannes, linville; +Cc: Luis R. Rodriguez, linux-wireless
The country IE number of channels on 5 GHz specifies the number
of 5 GHz channels, not the number of sequential channel numbers.
For example, if in a country IEs if the first channel given is 36
and the number of channels passed is 4 then the individual channel
numbers defined for the 5 GHz PHY by these parameters
are: 36, 40, 44, 48
not: 36, 37, 38, 39
See: http://tinyurl.com/11d-clarification
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
net/wireless/reg.c | 21 +++++++++++++++++++--
1 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index bea98ed..b34fd84 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -563,6 +563,7 @@ static struct ieee80211_regdomain *country_ie_2_rd(
/* This time around we fill in the rd */
while (country_ie_len >= 3) {
+ int end_channel = 0;
struct ieee80211_country_ie_triplet *triplet =
(struct ieee80211_country_ie_triplet *) country_ie;
struct ieee80211_reg_rule *reg_rule = NULL;
@@ -584,6 +585,23 @@ static struct ieee80211_regdomain *country_ie_2_rd(
reg_rule->flags = flags;
+ /* 2 GHz */
+ if (triplet->chans.first_channel <= 14)
+ end_channel = triplet->chans.first_channel +
+ triplet->chans.num_channels;
+ else
+ /*
+ * 5 GHz -- For example in country IEs if the first
+ * channel given is 36 and the number of channels is 4
+ * then the individual channel numbers defined for the
+ * 5 GHz PHY by these parameters are: 36, 40, 44, and 48
+ * and not 36, 37, 38, 39.
+ *
+ * See: http://tinyurl.com/11d-clarification
+ */
+ end_channel = triplet->chans.first_channel +
+ (4 * (triplet->chans.num_channels - 1));
+
/* The +10 is since the regulatory domain expects
* the actual band edge, not the center of freq for
* its start and end freqs, assuming 20 MHz bandwidth on
@@ -593,8 +611,7 @@ static struct ieee80211_regdomain *country_ie_2_rd(
triplet->chans.first_channel) - 10);
freq_range->end_freq_khz =
MHZ_TO_KHZ(ieee80211_channel_to_frequency(
- triplet->chans.first_channel +
- triplet->chans.num_channels) + 10);
+ end_channel) + 10);
/* Large arbitrary values, we intersect later */
/* Increment this if we ever support >= 40 MHz channels
--
1.6.1.rc3.51.g5832d
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 1/6] cfg80211: call reg_notifier() once
2009-01-08 1:43 ` [PATCH 1/6] cfg80211: call reg_notifier() once Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 2/6] cfg80211: make handle_band() and handle_channel() wiphy specific Luis R. Rodriguez
@ 2009-01-08 12:58 ` Johannes Berg
1 sibling, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2009-01-08 12:58 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: linville, linux-wireless
[-- Attachment #1: Type: text/plain, Size: 984 bytes --]
On Wed, 2009-01-07 at 17:43 -0800, Luis R. Rodriguez wrote:
> We are calling the reg_notifier() callback per band, this is
> not necessary, just call it once.
>
> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
> ---
> net/wireless/reg.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/net/wireless/reg.c b/net/wireless/reg.c
> index 4f87753..2f2ba92 100644
> --- a/net/wireless/reg.c
> +++ b/net/wireless/reg.c
> @@ -841,9 +841,9 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
> for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
> if (wiphy->bands[band])
> handle_band(wiphy->bands[band]);
> - if (wiphy->reg_notifier)
> - wiphy->reg_notifier(wiphy, setby);
> }
> + if (wiphy->reg_notifier)
> + wiphy->reg_notifier(wiphy, setby);
> }
>
> /* Return value which can be used by ignore_request() to indicate
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/6] cfg80211: make handle_band() and handle_channel() wiphy specific
2009-01-08 1:43 ` [PATCH 2/6] cfg80211: make handle_band() and handle_channel() wiphy specific Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 3/6] cfg80211: allow multiple driver regulatory_hints() Luis R. Rodriguez
@ 2009-01-08 12:58 ` Johannes Berg
1 sibling, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2009-01-08 12:58 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: linville, linux-wireless
[-- Attachment #1: Type: text/plain, Size: 2430 bytes --]
On Wed, 2009-01-07 at 17:43 -0800, Luis R. Rodriguez wrote:
> This allows us to make more wiphy specific judgements when
> handling the channels later on.
>
> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
> ---
> net/wireless/reg.c | 25 +++++++++++++++++++------
> 1 files changed, 19 insertions(+), 6 deletions(-)
>
> diff --git a/net/wireless/reg.c b/net/wireless/reg.c
> index 2f2ba92..87b3011 100644
> --- a/net/wireless/reg.c
> +++ b/net/wireless/reg.c
> @@ -778,13 +778,22 @@ static int freq_reg_info(u32 center_freq, u32 *bandwidth,
> return !max_bandwidth;
> }
>
> -static void handle_channel(struct ieee80211_channel *chan)
> +static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
> + unsigned int chan_idx)
> {
> int r;
> - u32 flags = chan->orig_flags;
> + u32 flags;
> u32 max_bandwidth = 0;
> const struct ieee80211_reg_rule *reg_rule = NULL;
> const struct ieee80211_power_rule *power_rule = NULL;
> + struct ieee80211_supported_band *sband;
> + struct ieee80211_channel *chan;
> +
> + sband = wiphy->bands[band];
> + BUG_ON(chan_idx >= sband->n_channels);
> + chan = &sband->channels[chan_idx];
> +
> + flags = chan->orig_flags;
>
> r = freq_reg_info(MHZ_TO_KHZ(chan->center_freq),
> &max_bandwidth, ®_rule);
> @@ -808,12 +817,16 @@ static void handle_channel(struct ieee80211_channel *chan)
> chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);
> }
>
> -static void handle_band(struct ieee80211_supported_band *sband)
> +static void handle_band(struct wiphy *wiphy, enum ieee80211_band band)
> {
> - int i;
> + unsigned int i;
> + struct ieee80211_supported_band *sband;
> +
> + BUG_ON(!wiphy->bands[band]);
> + sband = wiphy->bands[band];
>
> for (i = 0; i < sband->n_channels; i++)
> - handle_channel(&sband->channels[i]);
> + handle_channel(wiphy, band, i);
> }
>
> static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby)
> @@ -840,7 +853,7 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
> enum ieee80211_band band;
> for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
> if (wiphy->bands[band])
> - handle_band(wiphy->bands[band]);
> + handle_band(wiphy, band);
> }
> if (wiphy->reg_notifier)
> wiphy->reg_notifier(wiphy, setby);
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/6] cfg80211: allow multiple driver regulatory_hints()
2009-01-08 1:43 ` [PATCH 3/6] cfg80211: allow multiple driver regulatory_hints() Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 4/6] cfg80211: fix typo on message after intersection Luis R. Rodriguez
@ 2009-01-08 12:59 ` Johannes Berg
1 sibling, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2009-01-08 12:59 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: linville, linux-wireless
[-- Attachment #1: Type: text/plain, Size: 8997 bytes --]
On Wed, 2009-01-07 at 17:43 -0800, Luis R. Rodriguez wrote:
> We add support for multiple drivers to provide a regulatory_hint()
> on a system by adding a wiphy specific regulatory domain cache.
> This allows drivers to keep around cache their own regulatory domain
> structure queried from CRDA.
>
> We handle conflicts by intersecting multiple regulatory domains,
> each driver will stick to its own regulatory domain though unless
> a country IE has been received and processed.
>
> If the user already requested a regulatory domain and a driver
> requests the same regulatory domain then simply copy to the
> driver's regd the same regulatory domain and do not call
> CRDA, do not collect $200.
Could be an intersection already then? Not sure right now, but seems ok
to me either way, and if not we can fix it when we find a problem.
> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
> ---
> include/net/wireless.h | 6 +++
> net/wireless/reg.c | 109 ++++++++++++++++++++++++++++++++++++++++++------
> 2 files changed, 102 insertions(+), 13 deletions(-)
>
> diff --git a/include/net/wireless.h b/include/net/wireless.h
> index aedefa5..f57f12f 100644
> --- a/include/net/wireless.h
> +++ b/include/net/wireless.h
> @@ -187,6 +187,10 @@ struct ieee80211_supported_band {
> * we will disregard the first regulatory hint (when the
> * initiator is %REGDOM_SET_BY_CORE).
> * @reg_notifier: the driver's regulatory notification callback
> + * @regd: the driver's regulatory domain, if one was requested via
> + * the regulatory_hint() API. This can be used by the driver
> + * on the reg_notifier() if it chooses to ignore future
> + * regulatory domain changes caused by other drivers.
> */
> struct wiphy {
> /* assign these fields before you register the wiphy */
> @@ -213,6 +217,8 @@ struct wiphy {
>
> /* fields below are read-only, assigned by cfg80211 */
>
> + const struct ieee80211_regdomain *regd;
> +
> /* the item in /sys/class/ieee80211/ points to this,
> * you need use set_wiphy_dev() (see below) */
> struct device dev;
> diff --git a/net/wireless/reg.c b/net/wireless/reg.c
> index 87b3011..10a3b11 100644
> --- a/net/wireless/reg.c
> +++ b/net/wireless/reg.c
> @@ -742,29 +742,42 @@ static u32 map_regdom_flags(u32 rd_flags)
>
> /**
> * freq_reg_info - get regulatory information for the given frequency
> + * @wiphy: the wiphy for which we want to process this rule for
> * @center_freq: Frequency in KHz for which we want regulatory information for
> * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one
> * you can set this to 0. If this frequency is allowed we then set
> * this value to the maximum allowed bandwidth.
> * @reg_rule: the regulatory rule which we have for this frequency
> *
> - * Use this function to get the regulatory rule for a specific frequency.
> + * Use this function to get the regulatory rule for a specific frequency on
> + * a given wireless device. If the device has a specific regulatory domain
> + * it wants to follow we respect that unless a country IE has been received
> + * and processed already.
> */
> -static int freq_reg_info(u32 center_freq, u32 *bandwidth,
> +static int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
> const struct ieee80211_reg_rule **reg_rule)
> {
> int i;
> + const struct ieee80211_regdomain *regd;
> u32 max_bandwidth = 0;
>
> - if (!cfg80211_regdomain)
> + regd = cfg80211_regdomain;
> +
> + /* Follow the driver's regulatory domain, if present, unless a country
> + * IE has been processed */
> + if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE &&
> + wiphy->regd)
> + regd = wiphy->regd;
> +
> + if (!regd)
> return -EINVAL;
>
> - for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) {
> + for (i = 0; i < regd->n_reg_rules; i++) {
> const struct ieee80211_reg_rule *rr;
> const struct ieee80211_freq_range *fr = NULL;
> const struct ieee80211_power_rule *pr = NULL;
>
> - rr = &cfg80211_regdomain->reg_rules[i];
> + rr = ®d->reg_rules[i];
> fr = &rr->freq_range;
> pr = &rr->power_rule;
> max_bandwidth = freq_max_bandwidth(fr, center_freq);
> @@ -795,7 +808,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
>
> flags = chan->orig_flags;
>
> - r = freq_reg_info(MHZ_TO_KHZ(chan->center_freq),
> + r = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq),
> &max_bandwidth, ®_rule);
>
> if (r) {
> @@ -859,6 +872,30 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
> wiphy->reg_notifier(wiphy, setby);
> }
>
> +static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
> + const struct ieee80211_regdomain *src_regd)
> +{
> + struct ieee80211_regdomain *regd;
> + int size_of_regd = 0;
> + unsigned int i;
> +
> + size_of_regd = sizeof(struct ieee80211_regdomain) +
> + ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
> +
> + regd = kzalloc(size_of_regd, GFP_KERNEL);
> + if (!regd)
> + return -ENOMEM;
> +
> + memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
> +
> + for (i = 0; i < src_regd->n_reg_rules; i++)
> + memcpy(®d->reg_rules[i], &src_regd->reg_rules[i],
> + sizeof(struct ieee80211_reg_rule));
> +
> + *dst_regd = regd;
> + return 0;
> +}
> +
> /* Return value which can be used by ignore_request() to indicate
> * it has been determined we should intersect two regulatory domains */
> #define REG_INTERSECT 1
> @@ -906,9 +943,9 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
> }
> return REG_INTERSECT;
> case REGDOM_SET_BY_DRIVER:
> - if (last_request->initiator == REGDOM_SET_BY_DRIVER)
> - return -EALREADY;
> - return 0;
> + if (last_request->initiator == REGDOM_SET_BY_CORE)
> + return 0;
> + return REG_INTERSECT;
> case REGDOM_SET_BY_USER:
> if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
> return REG_INTERSECT;
> @@ -935,11 +972,28 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
>
> r = ignore_request(wiphy, set_by, alpha2);
>
> - if (r == REG_INTERSECT)
> + if (r == REG_INTERSECT) {
> + if (set_by == REGDOM_SET_BY_DRIVER) {
> + r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
> + if (r)
> + return r;
> + }
> intersect = true;
> - else if (r)
> + } else if (r) {
> + /* If the regulatory domain being requested by the
> + * driver has already been set just copy it to the
> + * wiphy */
> + if (r == -EALREADY && set_by == REGDOM_SET_BY_DRIVER) {
> + r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
> + if (r)
> + return r;
> + r = -EALREADY;
> + goto new_request;
> + }
> return r;
> + }
>
> +new_request:
> request = kzalloc(sizeof(struct regulatory_request),
> GFP_KERNEL);
> if (!request)
> @@ -955,6 +1009,11 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
>
> kfree(last_request);
> last_request = request;
> +
> + /* When r == REG_INTERSECT we do need to call CRDA */
> + if (r < 0)
> + return r;
> +
> /*
> * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled
> * AND if CRDA is NOT present nothing will happen, if someone
> @@ -1248,6 +1307,23 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
> }
>
> if (!last_request->intersect) {
> + int r;
> +
> + if (last_request->initiator != REGDOM_SET_BY_DRIVER) {
> + reset_regdomains();
> + cfg80211_regdomain = rd;
> + return 0;
> + }
> +
> + /* For a driver hint, lets copy the regulatory domain the
> + * driver wanted to the wiphy to deal with conflicts */
> +
> + BUG_ON(last_request->wiphy->regd);
> +
> + r = reg_copy_regd(&last_request->wiphy->regd, rd);
> + if (r)
> + return r;
> +
> reset_regdomains();
> cfg80211_regdomain = rd;
> return 0;
> @@ -1261,8 +1337,14 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
> if (!intersected_rd)
> return -EINVAL;
>
> - /* We can trash what CRDA provided now */
> - kfree(rd);
> + /* We can trash what CRDA provided now.
> + * However if a driver requested this specific regulatory
> + * domain we keep it for its private use */
> + if (last_request->initiator == REGDOM_SET_BY_DRIVER)
> + last_request->wiphy->regd = rd;
> + else
> + kfree(rd);
> +
> rd = NULL;
>
> reset_regdomains();
> @@ -1346,6 +1428,7 @@ int set_regdom(const struct ieee80211_regdomain *rd)
> /* Caller must hold cfg80211_drv_mutex */
> void reg_device_remove(struct wiphy *wiphy)
> {
> + kfree(wiphy->regd);
> if (!last_request || !last_request->wiphy)
> return;
> if (last_request->wiphy != wiphy)
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 4/6] cfg80211: fix typo on message after intersection
2009-01-08 1:43 ` [PATCH 4/6] cfg80211: fix typo on message after intersection Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 5/6] cfg80211: Fix regression with 11d on bands Luis R. Rodriguez
@ 2009-01-08 13:00 ` Johannes Berg
1 sibling, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2009-01-08 13:00 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: linville, linux-wireless
[-- Attachment #1: Type: text/plain, Size: 810 bytes --]
On Wed, 2009-01-07 at 17:43 -0800, Luis R. Rodriguez wrote:
> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
> ---
> net/wireless/reg.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/net/wireless/reg.c b/net/wireless/reg.c
> index 10a3b11..3d56a1d 100644
> --- a/net/wireless/reg.c
> +++ b/net/wireless/reg.c
> @@ -1205,7 +1205,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
> "domain intersected: \n");
> } else
> printk(KERN_INFO "cfg80211: Current regulatory "
> - "intersected: \n");
> + "domain intersected: \n");
> } else if (is_world_regdom(rd->alpha2))
> printk(KERN_INFO "cfg80211: World regulatory "
> "domain updated:\n");
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 5/6] cfg80211: Fix regression with 11d on bands
2009-01-08 1:43 ` [PATCH 5/6] cfg80211: Fix regression with 11d on bands Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 6/6] cfg80211: Fix parsed country IE info for 5 GHz Luis R. Rodriguez
@ 2009-01-08 13:03 ` Johannes Berg
1 sibling, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2009-01-08 13:03 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: linville, linux-wireless
[-- Attachment #1: Type: text/plain, Size: 6250 bytes --]
On Wed, 2009-01-07 at 17:43 -0800, Luis R. Rodriguez wrote:
> This fixes a regression on disallowing bands introduced with the new
> 802.11d support. The issue is that IEEE-802.11 allows APs to send
> a subset of what a country regulatory domain defines. This was clarified
> in this document:
>
> http://tinyurl.com/11d-clarification
I think you should give the full link, regardless of how long it is.
It's just on the 802 docserver, no?
> As such it is possible, and this is what is done in practice, that a
> single band 2.4 GHz AP will only send 2.4 GHz band regulatory information
> through the 802.11 country information element and then the current
> intersection with what CRDA provided yields a regulatory domain with
> no 5 GHz information -- even though that country may actually allow
> 5 GHz operation. We correct this by only applying the intersection rules
> on a channel if the the intersection yields a regulatory rule on the
> same band the channel is on.
Seems sane to me.
> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
> ---
> net/wireless/reg.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 files changed, 75 insertions(+), 2 deletions(-)
>
> diff --git a/net/wireless/reg.c b/net/wireless/reg.c
> index 3d56a1d..bea98ed 100644
> --- a/net/wireless/reg.c
> +++ b/net/wireless/reg.c
> @@ -421,6 +421,31 @@ static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range,
> return 0;
> }
>
> +/**
> + * freq_in_rule_band - tells us if a frequency is in a frequency band
> + * @freq_range: frequency rule we want to query
> + * @freq_khz: frequency we are inquiring about
> + *
> + * This lets us know if a specific frequency rule is or is not relevant to
> + * a specific frequency's band. Bands are device specific and artificial
> + * definitions (the "2.4 GHz band" and the "5 GHz band"), however it is
> + * safe for now to assume that a frequency rule should not be part of a
> + * frequency's band if the start freq or end freq are off by more than 2 GHz.
> + * This resolution can be lowered and should be considered as we add
> + * regulatory rule support for other "bands".
> + **/
> +static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
> + u32 freq_khz)
> +{
> +#define ONE_GHZ_IN_KHZ 1000000
> + if (abs(freq_khz - freq_range->start_freq_khz) <= (2 * ONE_GHZ_IN_KHZ))
> + return true;
> + if (abs(freq_khz - freq_range->end_freq_khz) <= (2 * ONE_GHZ_IN_KHZ))
> + return true;
> + return false;
> +#undef ONE_GHZ_IN_KHZ
> +}
> +
> /* Converts a country IE to a regulatory domain. A regulatory domain
> * structure has a lot of information which the IE doesn't yet have,
> * so for the other values we use upper max values as we will intersect
> @@ -753,11 +778,19 @@ static u32 map_regdom_flags(u32 rd_flags)
> * a given wireless device. If the device has a specific regulatory domain
> * it wants to follow we respect that unless a country IE has been received
> * and processed already.
> + *
> + * Returns 0 if it was able to find a valid regulatory rule which does
> + * apply to the given center_freq otherwise it returns non-zero. It will
> + * also return -ERANGE if we determine the given center_freq does not even have
> + * a regulatory rule for a frequency range in the center_freq's band. See
> + * freq_in_rule_band() for our current definition of a band -- this is purely
> + * subjective and right now its 802.11 specific.
> */
> static int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
> const struct ieee80211_reg_rule **reg_rule)
> {
> int i;
> + bool band_rule_found = false;
> const struct ieee80211_regdomain *regd;
> u32 max_bandwidth = 0;
>
> @@ -780,7 +813,15 @@ static int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
> rr = ®d->reg_rules[i];
> fr = &rr->freq_range;
> pr = &rr->power_rule;
> +
> + /* We only need to know if one frequency rule was
> + * was in center_freq's band, that's enough, so lets
> + * not overwrite it once found */
> + if (!band_rule_found)
> + band_rule_found = freq_in_rule_band(fr, center_freq);
> +
> max_bandwidth = freq_max_bandwidth(fr, center_freq);
> +
> if (max_bandwidth && *bandwidth <= max_bandwidth) {
> *reg_rule = rr;
> *bandwidth = max_bandwidth;
> @@ -788,6 +829,9 @@ static int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
> }
> }
>
> + if (!band_rule_found)
> + return -ERANGE;
> +
> return !max_bandwidth;
> }
>
> @@ -812,8 +856,37 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
> &max_bandwidth, ®_rule);
>
> if (r) {
> - flags |= IEEE80211_CHAN_DISABLED;
> - chan->flags = flags;
> + /* This means no regulatory rule was found in the country IE
> + * with a frequency range on the center_freq's band, since
> + * IEEE-802.11 allows for a country IE to have a subset of the
> + * regulatory information provided in a country we ignore
> + * disabling the channel unless at least one reg rule was
> + * found on the center_freq's band. For details see this
> + * clarification:
> + *
> + * http://tinyurl.com/11d-clarification
> + */
> + if (r == -ERANGE &&
> + last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
> +#ifdef CONFIG_CFG80211_REG_DEBUG
> + printk(KERN_DEBUG "cfg80211: Leaving channel %d MHz "
> + "intact on %s - no rule found in band on "
> + "Country IE\n",
> + chan->center_freq, wiphy_name(wiphy));
> +#endif
> + } else {
> + /* In this case we know the country IE has at least one reg rule
> + * for the band so we respect its band definitions */
> +#ifdef CONFIG_CFG80211_REG_DEBUG
> + if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
> + printk(KERN_DEBUG "cfg80211: Disabling "
> + "channel %d MHz on %s due to "
> + "Country IE\n",
> + chan->center_freq, wiphy_name(wiphy));
> +#endif
> + flags |= IEEE80211_CHAN_DISABLED;
> + chan->flags = flags;
> + }
> return;
> }
>
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 6/6] cfg80211: Fix parsed country IE info for 5 GHz
2009-01-08 1:43 ` [PATCH 6/6] cfg80211: Fix parsed country IE info for 5 GHz Luis R. Rodriguez
@ 2009-01-08 13:04 ` Johannes Berg
0 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2009-01-08 13:04 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: linville, linux-wireless
[-- Attachment #1: Type: text/plain, Size: 2591 bytes --]
On Wed, 2009-01-07 at 17:43 -0800, Luis R. Rodriguez wrote:
> The country IE number of channels on 5 GHz specifies the number
> of 5 GHz channels, not the number of sequential channel numbers.
> For example, if in a country IEs if the first channel given is 36
> and the number of channels passed is 4 then the individual channel
> numbers defined for the 5 GHz PHY by these parameters
>
> are: 36, 40, 44, 48
> not: 36, 37, 38, 39
>
> See: http://tinyurl.com/11d-clarification
>
> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
> ---
> net/wireless/reg.c | 21 +++++++++++++++++++--
> 1 files changed, 19 insertions(+), 2 deletions(-)
>
> diff --git a/net/wireless/reg.c b/net/wireless/reg.c
> index bea98ed..b34fd84 100644
> --- a/net/wireless/reg.c
> +++ b/net/wireless/reg.c
> @@ -563,6 +563,7 @@ static struct ieee80211_regdomain *country_ie_2_rd(
>
> /* This time around we fill in the rd */
> while (country_ie_len >= 3) {
> + int end_channel = 0;
> struct ieee80211_country_ie_triplet *triplet =
> (struct ieee80211_country_ie_triplet *) country_ie;
> struct ieee80211_reg_rule *reg_rule = NULL;
> @@ -584,6 +585,23 @@ static struct ieee80211_regdomain *country_ie_2_rd(
>
> reg_rule->flags = flags;
>
> + /* 2 GHz */
> + if (triplet->chans.first_channel <= 14)
> + end_channel = triplet->chans.first_channel +
> + triplet->chans.num_channels;
> + else
> + /*
> + * 5 GHz -- For example in country IEs if the first
> + * channel given is 36 and the number of channels is 4
> + * then the individual channel numbers defined for the
> + * 5 GHz PHY by these parameters are: 36, 40, 44, and 48
> + * and not 36, 37, 38, 39.
> + *
> + * See: http://tinyurl.com/11d-clarification
> + */
> + end_channel = triplet->chans.first_channel +
> + (4 * (triplet->chans.num_channels - 1));
> +
> /* The +10 is since the regulatory domain expects
> * the actual band edge, not the center of freq for
> * its start and end freqs, assuming 20 MHz bandwidth on
> @@ -593,8 +611,7 @@ static struct ieee80211_regdomain *country_ie_2_rd(
> triplet->chans.first_channel) - 10);
> freq_range->end_freq_khz =
> MHZ_TO_KHZ(ieee80211_channel_to_frequency(
> - triplet->chans.first_channel +
> - triplet->chans.num_channels) + 10);
> + end_channel) + 10);
>
> /* Large arbitrary values, we intersect later */
> /* Increment this if we ever support >= 40 MHz channels
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2009-01-08 13:03 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-08 1:43 [PATCH 0/6] cfg80211: few fixes and adds support for multiple reg hints Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 1/6] cfg80211: call reg_notifier() once Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 2/6] cfg80211: make handle_band() and handle_channel() wiphy specific Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 3/6] cfg80211: allow multiple driver regulatory_hints() Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 4/6] cfg80211: fix typo on message after intersection Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 5/6] cfg80211: Fix regression with 11d on bands Luis R. Rodriguez
2009-01-08 1:43 ` [PATCH 6/6] cfg80211: Fix parsed country IE info for 5 GHz Luis R. Rodriguez
2009-01-08 13:04 ` Johannes Berg
2009-01-08 13:03 ` [PATCH 5/6] cfg80211: Fix regression with 11d on bands Johannes Berg
2009-01-08 13:00 ` [PATCH 4/6] cfg80211: fix typo on message after intersection Johannes Berg
2009-01-08 12:59 ` [PATCH 3/6] cfg80211: allow multiple driver regulatory_hints() Johannes Berg
2009-01-08 12:58 ` [PATCH 2/6] cfg80211: make handle_band() and handle_channel() wiphy specific Johannes Berg
2009-01-08 12:58 ` [PATCH 1/6] cfg80211: call reg_notifier() once Johannes Berg
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox