From: Johannes Berg <johannes@sipsolutions.net>
To: "Luis R. Rodriguez" <lrodriguez@atheros.com>
Cc: linville@tuxdriver.com, linux-wireless@vger.kernel.org
Subject: Re: [PATCH 3/6] cfg80211: allow multiple driver regulatory_hints()
Date: Thu, 08 Jan 2009 13:59:54 +0100 [thread overview]
Message-ID: <1231419594.3685.4.camel@johannes> (raw)
In-Reply-To: <1231379017-28363-4-git-send-email-lrodriguez@atheros.com>
[-- 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 --]
next prev parent reply other threads:[~2009-01-08 12:58 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
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 ` Johannes Berg [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1231419594.3685.4.camel@johannes \
--to=johannes@sipsolutions.net \
--cc=linux-wireless@vger.kernel.org \
--cc=linville@tuxdriver.com \
--cc=lrodriguez@atheros.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox