cfg80211: Allow for strict regulatory settings
authorLuis R. Rodriguez <lrodriguez@atheros.com>
Thu, 22 Jan 2009 23:05:52 +0000 (15:05 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 29 Jan 2009 21:01:18 +0000 (16:01 -0500)
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 <lrodriguez@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
include/net/wireless.h
net/wireless/reg.c

index 9c19764a484920b169697e6f4d7c88f474eb2bf4..a42c1562d52bd61ea377a7253bbaec6ab790e269 100644 (file)
@@ -186,6 +186,15 @@ struct ieee80211_supported_band {
  *     ISO / IEC 3166 alpha2 it belongs to. When this is enabled
  *     we will disregard the first regulatory hint (when the
  *     initiator is %REGDOM_SET_BY_CORE).
+ * @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.
  * @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
@@ -202,6 +211,7 @@ struct wiphy {
        u16 interface_modes;
 
        bool custom_regulatory;
+       bool strict_regulatory;
 
        /* If multiple wiphys are registered and you're handed e.g.
         * a regular netdev with assigned ieee80211_ptr, you won't
index cad4daadba0dd6854e33ff5d0de16fe396b9d6a6..89e0d8b3cf1eec1d9798a070b5fe989ef37eb86e 100644 (file)
@@ -867,6 +867,22 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
 
        power_rule = &reg_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);