From 7ca43d03b1291481bdf894bbaec5d580e7684e7d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 10:18:53 -0700 Subject: cfg80211: pass the reg hint initiator to helpers This is required later. Cc: Easwar Krishnan Cc: stable@kernel.org signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 4b9f8912526..b64596fe736 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -720,7 +720,9 @@ EXPORT_SYMBOL(freq_reg_info); * on the wiphy with the target_bw specified. Then we can simply use * that below for the desired_bw_khz below. */ -static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, +static void handle_channel(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator, + enum ieee80211_band band, unsigned int chan_idx) { int r; @@ -784,7 +786,9 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); } -static void handle_band(struct wiphy *wiphy, enum ieee80211_band band) +static void handle_band(struct wiphy *wiphy, + enum ieee80211_band band, + enum nl80211_reg_initiator initiator) { unsigned int i; struct ieee80211_supported_band *sband; @@ -793,7 +797,7 @@ static void handle_band(struct wiphy *wiphy, enum ieee80211_band band) sband = wiphy->bands[band]; for (i = 0; i < sband->n_channels; i++) - handle_channel(wiphy, band, i); + handle_channel(wiphy, initiator, band, i); } static bool ignore_reg_update(struct wiphy *wiphy, @@ -1030,7 +1034,7 @@ void wiphy_update_regulatory(struct wiphy *wiphy, goto out; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { if (wiphy->bands[band]) - handle_band(wiphy, band); + handle_band(wiphy, band, initiator); } out: reg_process_beacons(wiphy); -- cgit v1.2.3 From 749b527b21465fb079796c03ffb4302584dc31c1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 10:18:54 -0700 Subject: cfg80211: fix allowing country IEs for WIPHY_FLAG_STRICT_REGULATORY We should be enabling country IE hints for WIPHY_FLAG_STRICT_REGULATORY even if we haven't yet recieved regulatory domain hint for the driver if it needed one. Without this Country IEs are not passed on to drivers that have set WIPHY_FLAG_STRICT_REGULATORY, today this is just all Atheros chipset drivers: ath5k, ath9k, ar9170, carl9170. This was part of the original design, however it was completely overlooked... Cc: Easwar Krishnan Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- include/net/cfg80211.h | 15 ++++++++------- net/wireless/reg.c | 1 + 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'net/wireless') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2a7936d7851..e5702f5ac57 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1321,13 +1321,14 @@ struct cfg80211_ops { * initiator is %REGDOM_SET_BY_CORE). * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will * ignore regulatory domain settings until it gets its own regulatory - * domain via its regulatory_hint(). After its gets its own regulatory - * domain it will only allow further regulatory domain settings to - * further enhance compliance. For example if channel 13 and 14 are - * disabled by this regulatory domain no user regulatory domain can - * enable these channels at a later time. This can be used for devices - * which do not have calibration information gauranteed for frequencies - * or settings outside of its regulatory domain. + * domain via its regulatory_hint() unless the regulatory hint is + * from a country IE. After its gets its own regulatory domain it will + * only allow further regulatory domain settings to further enhance + * compliance. For example if channel 13 and 14 are disabled by this + * regulatory domain no user regulatory domain can enable these channels + * at a later time. This can be used for devices which do not have + * calibration information guaranteed for frequencies or settings + * outside of its regulatory domain. * @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure * that passive scan flags and beaconing flags may not be lifted by * cfg80211 due to regulatory beacon hints. For more information on beacon diff --git a/net/wireless/reg.c b/net/wireless/reg.c index b64596fe736..1bc8131a518 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -813,6 +813,7 @@ static bool ignore_reg_update(struct wiphy *wiphy, * desired regulatory domain set */ if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && + initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && !is_world_regdom(last_request->alpha2)) return true; return false; -- cgit v1.2.3 From ca4ffe8f2848169a8ded0ea8a60b2d81925564c9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 10:18:55 -0700 Subject: cfg80211: fix disabling channels based on hints After a module loads you will have loaded the world roaming regulatory domain or a custom regulatory domain. Further regulatory hints are welcomed and should be respected unless the regulatory hint is coming from a country IE as the IEEE spec allows for a country IE to be a subset of what is allowed by the local regulatory agencies. So disable all channels that do not fit a regulatory domain sent from a unless the hint is from a country IE and the country IE had no information about the band we are currently processing. This fixes a few regulatory issues, for example for drivers that depend on CRDA and had no 5 GHz freqencies allowed were not properly disabling 5 GHz at all, furthermore it also allows users to restrict devices further as was intended. If you recieve a country IE upon association we will also disable the channels that are not allowed if the country IE had at least one channel on the respective band we are procesing. This was the original intention behind this design but it was completely overlooked... Cc: David Quan Cc: Jouni Malinen cc: Easwar Krishnan Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- include/linux/nl80211.h | 6 +++++- net/wireless/reg.c | 20 +++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'net/wireless') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 0edb2566c14..fb877b5621b 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1307,7 +1307,11 @@ enum nl80211_bitrate_attr { * wireless core it thinks its knows the regulatory domain we should be in. * @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an * 802.11 country information element with regulatory information it - * thinks we should consider. + * thinks we should consider. cfg80211 only processes the country + * code from the IE, and relies on the regulatory domain information + * structure pased by userspace (CRDA) from our wireless-regdb. + * If a channel is enabled but the country code indicates it should + * be disabled we disable the channel and re-enable it upon disassociation. */ enum nl80211_reg_initiator { NL80211_REGDOM_SET_BY_CORE, diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 1bc8131a518..8ab65f2afe7 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -750,8 +750,26 @@ static void handle_channel(struct wiphy *wiphy, desired_bw_khz, ®_rule); - if (r) + if (r) { + /* + * We will disable all channels that do not match our + * recieved regulatory rule unless the hint is coming + * from a Country IE and the Country IE had no information + * about a band. The IEEE 802.11 spec allows for an AP + * to send only a subset of the regulatory rules allowed, + * so an AP in the US that only supports 2.4 GHz may only send + * a country IE with information for the 2.4 GHz band + * while 5 GHz is still supported. + */ + if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && + r == -ERANGE) + return; + + REG_DBG_PRINT("cfg80211: Disabling freq %d MHz\n", + chan->center_freq); + chan->flags = IEEE80211_CHAN_DISABLED; return; + } power_rule = ®_rule->power_rule; freq_range = ®_rule->freq_range; -- cgit v1.2.3 From 926a0a094d2b9052db3f7f37438c3d305cea4be7 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 21 Oct 2010 19:17:03 +0530 Subject: cfg80211: add debug prints for when we ignore regulatory hints This can help with debugging issues. You will only see these with CONFIG_CFG80211_REG_DEBUG enabled. Cc: Easwar Krishnan Signed-off-by: Luis R. Rodriguez Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- net/wireless/reg.c | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 8ab65f2afe7..7bff1c1d6c8 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -711,6 +711,25 @@ int freq_reg_info(struct wiphy *wiphy, } EXPORT_SYMBOL(freq_reg_info); +#ifdef CONFIG_CFG80211_REG_DEBUG +static const char *reg_initiator_name(enum nl80211_reg_initiator initiator) +{ + switch (initiator) { + case NL80211_REGDOM_SET_BY_CORE: + return "Set by core"; + case NL80211_REGDOM_SET_BY_USER: + return "Set by user"; + case NL80211_REGDOM_SET_BY_DRIVER: + return "Set by driver"; + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + return "Set by country IE"; + default: + WARN_ON(1); + return "Set by bug"; + } +} +#endif + /* * Note that right now we assume the desired channel bandwidth * is always 20 MHz for each individual channel (HT40 uses 20 MHz @@ -821,19 +840,36 @@ static void handle_band(struct wiphy *wiphy, static bool ignore_reg_update(struct wiphy *wiphy, enum nl80211_reg_initiator initiator) { - if (!last_request) + if (!last_request) { + REG_DBG_PRINT("cfg80211: Ignoring regulatory request %s since " + "last_request is not set\n", + reg_initiator_name(initiator)); return true; + } + if (initiator == NL80211_REGDOM_SET_BY_CORE && - wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) + wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { + REG_DBG_PRINT("cfg80211: Ignoring regulatory request %s " + "since the driver uses its own custom " + "regulatory domain ", + reg_initiator_name(initiator)); return true; + } + /* * wiphy->regd will be set once the device has its own * desired regulatory domain set */ if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && - !is_world_regdom(last_request->alpha2)) + !is_world_regdom(last_request->alpha2)) { + REG_DBG_PRINT("cfg80211: Ignoring regulatory request %s " + "since the driver requires its own regulaotry " + "domain to be set first", + reg_initiator_name(initiator)); return true; + } + return false; } -- cgit v1.2.3 From a65185367f9f876448f0f12ac09a673d20371efc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 10:18:57 -0700 Subject: cfg80211: add debug print when disabling a channel on a custom regd Cc: Easwar Krishnan Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net/wireless') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 7bff1c1d6c8..6e7a9d85319 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1125,6 +1125,11 @@ static void handle_channel_custom(struct wiphy *wiphy, regd); if (r) { + REG_DBG_PRINT("cfg80211: Disabling freq %d MHz as custom " + "regd has no rule that fits a %d MHz " + "wide channel\n", + chan->center_freq, + KHZ_TO_MHZ(desired_bw_khz)); chan->flags = IEEE80211_CHAN_DISABLED; return; } -- cgit v1.2.3 From e702d3cf29143327679ce2e2a60775eaf829f377 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 21 Oct 2010 19:17:04 +0530 Subject: cfg80211: add debug print when processing a channel In the worst case you are seeing really odd things you want more information than what is provided right now, for those that insist and want debug info through CONFIG_CFG80211_REG_DEBUG provide a print of when we are processing a channel and with what regulatory rule. Cc: Easwar Krishnan Signed-off-by: Luis R. Rodriguez Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- net/wireless/reg.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'net/wireless') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 6e7a9d85319..5556c5fe489 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -728,6 +728,41 @@ static const char *reg_initiator_name(enum nl80211_reg_initiator initiator) return "Set by bug"; } } + +static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, + u32 desired_bw_khz, + const struct ieee80211_reg_rule *reg_rule) +{ + const struct ieee80211_power_rule *power_rule; + const struct ieee80211_freq_range *freq_range; + char max_antenna_gain[32]; + + power_rule = ®_rule->power_rule; + freq_range = ®_rule->freq_range; + + if (!power_rule->max_antenna_gain) + snprintf(max_antenna_gain, 32, "N/A"); + else + snprintf(max_antenna_gain, 32, "%d", power_rule->max_antenna_gain); + + REG_DBG_PRINT("cfg80211: Updating information on frequency %d MHz " + "for %d a MHz width channel with regulatory rule:\n", + chan->center_freq, + KHZ_TO_MHZ(desired_bw_khz)); + + REG_DBG_PRINT("cfg80211: %d KHz - %d KHz @ KHz), (%s mBi, %d mBm)\n", + freq_range->start_freq_khz, + freq_range->end_freq_khz, + max_antenna_gain, + power_rule->max_eirp); +} +#else +static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, + u32 desired_bw_khz, + const struct ieee80211_reg_rule *reg_rule) +{ + return; +} #endif /* @@ -790,6 +825,8 @@ static void handle_channel(struct wiphy *wiphy, return; } + chan_reg_rule_print_dbg(chan, desired_bw_khz, reg_rule); + power_rule = ®_rule->power_rule; freq_range = ®_rule->freq_range; @@ -1134,6 +1171,8 @@ static void handle_channel_custom(struct wiphy *wiphy, return; } + chan_reg_rule_print_dbg(chan, desired_bw_khz, reg_rule); + power_rule = ®_rule->power_rule; freq_range = ®_rule->freq_range; -- cgit v1.2.3 From d91e41b690f795c04af4eb6fe28d2cafd3291051 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 10:18:59 -0700 Subject: cfg80211: prefix REG_DBG_PRINT() with cfg80211 Everyone's doing it, its the cool thing. Cc: Easwar Krishnan Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 5556c5fe489..3be18d9a944 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -48,7 +48,7 @@ #ifdef CONFIG_CFG80211_REG_DEBUG #define REG_DBG_PRINT(format, args...) \ do { \ - printk(KERN_DEBUG format , ## args); \ + printk(KERN_DEBUG "cfg80211: " format , ## args); \ } while (0) #else #define REG_DBG_PRINT(args...) @@ -745,12 +745,12 @@ static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, else snprintf(max_antenna_gain, 32, "%d", power_rule->max_antenna_gain); - REG_DBG_PRINT("cfg80211: Updating information on frequency %d MHz " + REG_DBG_PRINT("Updating information on frequency %d MHz " "for %d a MHz width channel with regulatory rule:\n", chan->center_freq, KHZ_TO_MHZ(desired_bw_khz)); - REG_DBG_PRINT("cfg80211: %d KHz - %d KHz @ KHz), (%s mBi, %d mBm)\n", + REG_DBG_PRINT("%d KHz - %d KHz @ KHz), (%s mBi, %d mBm)\n", freq_range->start_freq_khz, freq_range->end_freq_khz, max_antenna_gain, @@ -819,8 +819,7 @@ static void handle_channel(struct wiphy *wiphy, r == -ERANGE) return; - REG_DBG_PRINT("cfg80211: Disabling freq %d MHz\n", - chan->center_freq); + REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq); chan->flags = IEEE80211_CHAN_DISABLED; return; } @@ -878,7 +877,7 @@ static bool ignore_reg_update(struct wiphy *wiphy, enum nl80211_reg_initiator initiator) { if (!last_request) { - REG_DBG_PRINT("cfg80211: Ignoring regulatory request %s since " + REG_DBG_PRINT("Ignoring regulatory request %s since " "last_request is not set\n", reg_initiator_name(initiator)); return true; @@ -886,7 +885,7 @@ static bool ignore_reg_update(struct wiphy *wiphy, if (initiator == NL80211_REGDOM_SET_BY_CORE && wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { - REG_DBG_PRINT("cfg80211: Ignoring regulatory request %s " + REG_DBG_PRINT("Ignoring regulatory request %s " "since the driver uses its own custom " "regulatory domain ", reg_initiator_name(initiator)); @@ -900,7 +899,7 @@ static bool ignore_reg_update(struct wiphy *wiphy, if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && !is_world_regdom(last_request->alpha2)) { - REG_DBG_PRINT("cfg80211: Ignoring regulatory request %s " + REG_DBG_PRINT("Ignoring regulatory request %s " "since the driver requires its own regulaotry " "domain to be set first", reg_initiator_name(initiator)); @@ -1162,7 +1161,7 @@ static void handle_channel_custom(struct wiphy *wiphy, regd); if (r) { - REG_DBG_PRINT("cfg80211: Disabling freq %d MHz as custom " + REG_DBG_PRINT("Disabling freq %d MHz as custom " "regd has no rule that fits a %d MHz " "wide channel\n", chan->center_freq, @@ -1662,7 +1661,7 @@ static void restore_alpha2(char *alpha2, bool reset_user) if (is_user_regdom_saved()) { /* Unless we're asked to ignore it and reset it */ if (reset_user) { - REG_DBG_PRINT("cfg80211: Restoring regulatory settings " + REG_DBG_PRINT("Restoring regulatory settings " "including user preference\n"); user_alpha2[0] = '9'; user_alpha2[1] = '7'; @@ -1673,7 +1672,7 @@ static void restore_alpha2(char *alpha2, bool reset_user) * back as they were for a full restore. */ if (!is_world_regdom(ieee80211_regdom)) { - REG_DBG_PRINT("cfg80211: Keeping preference on " + REG_DBG_PRINT("Keeping preference on " "module parameter ieee80211_regdom: %c%c\n", ieee80211_regdom[0], ieee80211_regdom[1]); @@ -1681,7 +1680,7 @@ static void restore_alpha2(char *alpha2, bool reset_user) alpha2[1] = ieee80211_regdom[1]; } } else { - REG_DBG_PRINT("cfg80211: Restoring regulatory settings " + REG_DBG_PRINT("Restoring regulatory settings " "while preserving user preference for: %c%c\n", user_alpha2[0], user_alpha2[1]); @@ -1689,14 +1688,14 @@ static void restore_alpha2(char *alpha2, bool reset_user) alpha2[1] = user_alpha2[1]; } } else if (!is_world_regdom(ieee80211_regdom)) { - REG_DBG_PRINT("cfg80211: Keeping preference on " + REG_DBG_PRINT("Keeping preference on " "module parameter ieee80211_regdom: %c%c\n", ieee80211_regdom[0], ieee80211_regdom[1]); alpha2[0] = ieee80211_regdom[0]; alpha2[1] = ieee80211_regdom[1]; } else - REG_DBG_PRINT("cfg80211: Restoring regulatory settings\n"); + REG_DBG_PRINT("Restoring regulatory settings\n"); } /* @@ -1764,7 +1763,7 @@ static void restore_regulatory_settings(bool reset_user) void regulatory_hint_disconnect(void) { - REG_DBG_PRINT("cfg80211: All devices are disconnected, going to " + REG_DBG_PRINT("All devices are disconnected, going to " "restore regulatory settings\n"); restore_regulatory_settings(false); } @@ -1794,7 +1793,7 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, if (!reg_beacon) return -ENOMEM; - REG_DBG_PRINT("cfg80211: Found new beacon on " + REG_DBG_PRINT("Found new beacon on " "frequency: %d MHz (Ch %d) on %s\n", beacon_chan->center_freq, ieee80211_frequency_to_channel(beacon_chan->center_freq), -- cgit v1.2.3