From 560e28e14f69ad3440a6e8c283dcfd37e1e41c2d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 7 Jan 2009 17:43:32 -0800 Subject: cfg80211: call reg_notifier() once We are calling the reg_notifier() callback per band, this is not necessary, just call it once. Signed-off-by: Luis R. Rodriguez Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/reg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/wireless/reg.c') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index bc494cef2102..0f93d4526f37 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -947,9 +947,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, 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 -- cgit v1.2.2 From 3e0c3ff36c4c7b9e39af7d600e399664ca04e817 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 7 Jan 2009 17:43:34 -0800 Subject: cfg80211: allow multiple driver regulatory_hints() 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 Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/reg.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 92 insertions(+), 12 deletions(-) (limited to 'net/wireless/reg.c') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 0f93d4526f37..5a746cd114a6 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -784,6 +784,7 @@ 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 @@ -802,22 +803,31 @@ static u32 map_regdom_flags(u32 rd_flags) * 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(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; bool band_rule_found = false; + 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; @@ -859,7 +869,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) { @@ -952,6 +962,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 @@ -999,9 +1033,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; @@ -1028,11 +1062,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) @@ -1048,6 +1099,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 @@ -1341,6 +1397,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; @@ -1354,8 +1427,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(); @@ -1439,6 +1518,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) -- cgit v1.2.2 From 039498c6ec67bd718ac1c8e7f6b4e2cfe2146773 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 7 Jan 2009 17:43:35 -0800 Subject: cfg80211: fix typo on message after intersection Signed-off-by: Luis R. Rodriguez Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/wireless/reg.c') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 5a746cd114a6..b34fd84b3e2f 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1295,7 +1295,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"); -- cgit v1.2.2 From 1fa25e413659f943dfec65da2abe713d566c7fdf Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 22 Jan 2009 15:05:44 -0800 Subject: cfg80211: add wiphy_apply_custom_regulatory() This adds wiphy_apply_custom_regulatory() to be used by drivers prior to wiphy registration to apply a custom regulatory domain. This can be used by drivers that do not have a direct 1-1 mapping between a regulatory domain and a country. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 115 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 91 insertions(+), 24 deletions(-) (limited to 'net/wireless/reg.c') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index b34fd84b3e2f..0d6059502b40 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -782,36 +782,18 @@ static u32 map_regdom_flags(u32 rd_flags) return channel_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 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. - * - * 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) +static int freq_reg_info_regd(struct wiphy *wiphy, + u32 center_freq, + u32 *bandwidth, + const struct ieee80211_reg_rule **reg_rule, + const struct ieee80211_regdomain *custom_regd) { int i; bool band_rule_found = false; const struct ieee80211_regdomain *regd; u32 max_bandwidth = 0; - regd = cfg80211_regdomain; + regd = custom_regd ? custom_regd : cfg80211_regdomain; /* Follow the driver's regulatory domain, if present, unless a country * IE has been processed */ @@ -852,6 +834,34 @@ static int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth, return !max_bandwidth; } +/** + * 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 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. + * + * 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) +{ + return freq_reg_info_regd(wiphy, center_freq, + bandwidth, reg_rule, NULL); +} + static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, unsigned int chan_idx) { @@ -962,6 +972,63 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) wiphy->reg_notifier(wiphy, setby); } +static void handle_channel_custom(struct wiphy *wiphy, + enum ieee80211_band band, + unsigned int chan_idx, + const struct ieee80211_regdomain *regd) +{ + int r; + 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]; + + r = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq), + &max_bandwidth, ®_rule, regd); + + if (r) { + chan->flags = IEEE80211_CHAN_DISABLED; + return; + } + + power_rule = ®_rule->power_rule; + + chan->flags |= map_regdom_flags(reg_rule->flags); + chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); + chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); + chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); +} + +static void handle_band_custom(struct wiphy *wiphy, enum ieee80211_band band, + const struct ieee80211_regdomain *regd) +{ + 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_custom(wiphy, band, i, regd); +} + +/* Used by drivers prior to wiphy registration */ +void wiphy_apply_custom_regulatory(struct wiphy *wiphy, + const struct ieee80211_regdomain *regd) +{ + enum ieee80211_band band; + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (wiphy->bands[band]) + handle_band_custom(wiphy, band, regd); + } +} +EXPORT_SYMBOL(wiphy_apply_custom_regulatory); + static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, const struct ieee80211_regdomain *src_regd) { -- cgit v1.2.2 From 34f573473a659f8c2727d8d408e17b241900c28e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 22 Jan 2009 15:05:45 -0800 Subject: cfg80211: export freq_reg_info() This can be used by drivers on the reg_notifier() Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) (limited to 'net/wireless/reg.c') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 0d6059502b40..d663795d6944 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -833,29 +833,9 @@ static int freq_reg_info_regd(struct wiphy *wiphy, return !max_bandwidth; } +EXPORT_SYMBOL(freq_reg_info); -/** - * 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 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. - * - * 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, +int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth, const struct ieee80211_reg_rule **reg_rule) { return freq_reg_info_regd(wiphy, center_freq, -- cgit v1.2.2 From 5eebade608d695e30e89d4c5ca6136a58f24ed14 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 22 Jan 2009 15:05:47 -0800 Subject: cfg80211: process user requests only after previous user/driver/core requests This prevents user regulatory changes to be considered prior to previous pending user, core or driver requests which have not be applied. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'net/wireless/reg.c') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index d663795d6944..4d2d2d4cc0d4 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1091,6 +1091,16 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, if (last_request->initiator == REGDOM_SET_BY_USER && last_request->intersect) return -EOPNOTSUPP; + /* Process user requests only after previous user/driver/core + * requests have been processed */ + if (last_request->initiator == REGDOM_SET_BY_CORE || + last_request->initiator == REGDOM_SET_BY_DRIVER || + last_request->initiator == REGDOM_SET_BY_USER) { + if (!alpha2_equal(last_request->alpha2, + cfg80211_regdomain->alpha2)) + return -EAGAIN; + } + return 0; } -- cgit v1.2.2 From e74b1e7fb2f12db36f25af2158ee6e2940e4f138 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 22 Jan 2009 15:05:48 -0800 Subject: cfg80211: ignore consecutive equal regulatory hints We ignore regulatory hints for the same alpha2 if we already have processed the same alpha2 on the current regulatory domain. For a driver regulatory_hint() this means we copy onto its wiphy->regd the previously procesed regulatory domain from CRDA without having to call CRDA again. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'net/wireless/reg.c') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 4d2d2d4cc0d4..c201abd38ad1 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1080,8 +1080,13 @@ 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_CORE) - return 0; + if (last_request->initiator == REGDOM_SET_BY_CORE) { + if (is_old_static_regdom(cfg80211_regdomain)) + return 0; + if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) + return 0; + return -EALREADY; + } return REG_INTERSECT; case REGDOM_SET_BY_USER: if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) @@ -1101,6 +1106,10 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, return -EAGAIN; } + if (!is_old_static_regdom(cfg80211_regdomain) && + alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) + return -EALREADY; + return 0; } -- cgit v1.2.2 From 2a44f911d8bac3e6c97a25cc612e4324dfbdfdc4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 22 Jan 2009 15:05:49 -0800 Subject: cfg80211: rename fw_handles_regulatory to custom_regulatory Drivers without firmware can also have custom regulatory maps which do not map to a specific ISO / IEC alpha2 country code. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/wireless/reg.c') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index c201abd38ad1..5db02a3d9c02 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -927,7 +927,7 @@ static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby) if (!last_request) return true; if (setby == REGDOM_SET_BY_CORE && - wiphy->fw_handles_regulatory) + wiphy->custom_regulatory) return true; return false; } -- cgit v1.2.2 From d46e5b1d0c617a2a46353812d7f02115c17b5e72 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 22 Jan 2009 15:05:50 -0800 Subject: cfg80211: move check for ignore_reg_update() on wiphy_update_regulatory() This ensures that the initial REGDOM_SET_BY_CORE upon wiphy registration respects the wiphy->custom_regulatory setting. Without this and if OLD_REG is disabled (which will be default soon as we remove it) the wiphy->custom_regulatory is simply ignored. Signed-off-by: Luis R. Rodriguez Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/reg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net/wireless/reg.c') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 5db02a3d9c02..81acb07f1d44 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -937,13 +937,15 @@ static void update_all_wiphy_regulatory(enum reg_set_by setby) struct cfg80211_registered_device *drv; list_for_each_entry(drv, &cfg80211_drv_list, list) - if (!ignore_reg_update(&drv->wiphy, setby)) - wiphy_update_regulatory(&drv->wiphy, setby); + wiphy_update_regulatory(&drv->wiphy, setby); } void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) { enum ieee80211_band band; + + if (ignore_reg_update(wiphy, setby)) + return; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { if (wiphy->bands[band]) handle_band(wiphy, band); -- cgit v1.2.2 From 716f9392e2b84cacc18cc11f7427cb98adeb1c3d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 22 Jan 2009 15:05:51 -0800 Subject: cfg80211: pass more detailed regulatory request information on reg_notifier() Drivers may need more information than just who set the last regulatory domain, as such lets just pass the last regulatory_request receipt. To do this we need to move out to headers struct regulatory_request, and enum environment_cap. While at it lets add documentation for enum environment_cap. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) (limited to 'net/wireless/reg.c') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 81acb07f1d44..cad4daadba0d 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -42,38 +42,6 @@ #include "core.h" #include "reg.h" -/** - * struct regulatory_request - receipt of last regulatory request - * - * @wiphy: this is set if this request's initiator is - * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This - * can be used by the wireless core to deal with conflicts - * and potentially inform users of which devices specifically - * cased the conflicts. - * @initiator: indicates who sent this request, could be any of - * of those set in reg_set_by, %REGDOM_SET_BY_* - * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested - * regulatory domain. We have a few special codes: - * 00 - World regulatory domain - * 99 - built by driver but a specific alpha2 cannot be determined - * 98 - result of an intersection between two regulatory domains - * @intersect: indicates whether the wireless core should intersect - * the requested regulatory domain with the presently set regulatory - * domain. - * @country_ie_checksum: checksum of the last processed and accepted - * country IE - * @country_ie_env: lets us know if the AP is telling us we are outdoor, - * indoor, or if it doesn't matter - */ -struct regulatory_request { - struct wiphy *wiphy; - enum reg_set_by initiator; - char alpha2[2]; - bool intersect; - u32 country_ie_checksum; - enum environment_cap country_ie_env; -}; - /* Receipt of information from last regulatory request */ static struct regulatory_request *last_request; @@ -951,7 +919,7 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) handle_band(wiphy, band); } if (wiphy->reg_notifier) - wiphy->reg_notifier(wiphy, setby); + wiphy->reg_notifier(wiphy, last_request); } static void handle_channel_custom(struct wiphy *wiphy, -- cgit v1.2.2 From f976376de0d6a9697fb635369f12ae00251f4566 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 22 Jan 2009 15:05:52 -0800 Subject: cfg80211: Allow for strict regulatory settings This allows drivers to request strict regulatory settings to be applied to its devices. This is desirable for devices where proper calibration and compliance can only be gauranteed for for the device's programmed regulatory domain. Regulatory domain settings will be ignored until the device's own regulatory domain is properly configured. If no regulatory domain is received only the world regulatory domain will be applied -- if OLD_REG (default to "US") is not enabled. If OLD_REG behaviour is not acceptable to drivers they must update their wiphy with a custom reuglatory prior to wiphy registration. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'net/wireless/reg.c') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index cad4daadba0d..89e0d8b3cf1e 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -867,6 +867,22 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, power_rule = ®_rule->power_rule; + if (last_request->initiator == REGDOM_SET_BY_DRIVER && + last_request->wiphy && last_request->wiphy == wiphy && + last_request->wiphy->strict_regulatory) { + /* This gaurantees the driver's requested regulatory domain + * will always be used as a base for further regulatory + * settings */ + chan->flags = chan->orig_flags = + map_regdom_flags(reg_rule->flags); + chan->max_antenna_gain = chan->orig_mag = + (int) MBI_TO_DBI(power_rule->max_antenna_gain); + chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); + chan->max_power = chan->orig_mpwr = + (int) MBM_TO_DBM(power_rule->max_eirp); + return; + } + chan->flags = flags | map_regdom_flags(reg_rule->flags); chan->max_antenna_gain = min(chan->orig_mag, (int) MBI_TO_DBI(power_rule->max_antenna_gain)); @@ -897,6 +913,11 @@ static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby) if (setby == REGDOM_SET_BY_CORE && wiphy->custom_regulatory) return true; + /* wiphy->regd will be set once the device has its own + * desired regulatory domain set */ + if (wiphy->strict_regulatory && !wiphy->regd && + !is_world_regdom(last_request->alpha2)) + return true; return false; } @@ -1155,10 +1176,15 @@ new_request: void regulatory_hint(struct wiphy *wiphy, const char *alpha2) { + int r; BUG_ON(!alpha2); mutex_lock(&cfg80211_drv_mutex); - __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, 0, ENVIRON_ANY); + r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, + alpha2, 0, ENVIRON_ANY); + /* This is required so that the orig_* parameters are saved */ + if (r == -EALREADY && wiphy->strict_regulatory) + wiphy_update_regulatory(wiphy, REGDOM_SET_BY_DRIVER); mutex_unlock(&cfg80211_drv_mutex); } EXPORT_SYMBOL(regulatory_hint); -- cgit v1.2.2 From 24ed1da1337b92e3b0a89f2c2b7cd33b9a8fcb62 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 22 Jan 2009 15:05:54 -0800 Subject: cfg80211: allow users to help a driver's compliance Let users be more compliant if so desired. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/wireless/reg.c') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 89e0d8b3cf1e..af9132cea931 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -764,8 +764,9 @@ static int freq_reg_info_regd(struct wiphy *wiphy, regd = custom_regd ? custom_regd : cfg80211_regdomain; /* Follow the driver's regulatory domain, if present, unless a country - * IE has been processed */ + * IE has been processed or a user wants to help complaince further */ if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE && + last_request->initiator != REGDOM_SET_BY_USER && wiphy->regd) regd = wiphy->regd; -- cgit v1.2.2