Back to home page

OSCL-LXR

 
 

    


0001 .. SPDX-License-Identifier: GPL-2.0
0002 
0003 =======================================
0004 Linux wireless regulatory documentation
0005 =======================================
0006 
0007 This document gives a brief review over how the Linux wireless
0008 regulatory infrastructure works.
0009 
0010 More up to date information can be obtained at the project's web page:
0011 
0012 https://wireless.wiki.kernel.org/en/developers/Regulatory
0013 
0014 Keeping regulatory domains in userspace
0015 ---------------------------------------
0016 
0017 Due to the dynamic nature of regulatory domains we keep them
0018 in userspace and provide a framework for userspace to upload
0019 to the kernel one regulatory domain to be used as the central
0020 core regulatory domain all wireless devices should adhere to.
0021 
0022 How to get regulatory domains to the kernel
0023 -------------------------------------------
0024 
0025 When the regulatory domain is first set up, the kernel will request a
0026 database file (regulatory.db) containing all the regulatory rules. It
0027 will then use that database when it needs to look up the rules for a
0028 given country.
0029 
0030 How to get regulatory domains to the kernel (old CRDA solution)
0031 ---------------------------------------------------------------
0032 
0033 Userspace gets a regulatory domain in the kernel by having
0034 a userspace agent build it and send it via nl80211. Only
0035 expected regulatory domains will be respected by the kernel.
0036 
0037 A currently available userspace agent which can accomplish this
0038 is CRDA - central regulatory domain agent. Its documented here:
0039 
0040 https://wireless.wiki.kernel.org/en/developers/Regulatory/CRDA
0041 
0042 Essentially the kernel will send a udev event when it knows
0043 it needs a new regulatory domain. A udev rule can be put in place
0044 to trigger crda to send the respective regulatory domain for a
0045 specific ISO/IEC 3166 alpha2.
0046 
0047 Below is an example udev rule which can be used:
0048 
0049 # Example file, should be put in /etc/udev/rules.d/regulatory.rules
0050 KERNEL=="regulatory*", ACTION=="change", SUBSYSTEM=="platform", RUN+="/sbin/crda"
0051 
0052 The alpha2 is passed as an environment variable under the variable COUNTRY.
0053 
0054 Who asks for regulatory domains?
0055 --------------------------------
0056 
0057 * Users
0058 
0059 Users can use iw:
0060 
0061 https://wireless.wiki.kernel.org/en/users/Documentation/iw
0062 
0063 An example::
0064 
0065   # set regulatory domain to "Costa Rica"
0066   iw reg set CR
0067 
0068 This will request the kernel to set the regulatory domain to
0069 the specificied alpha2. The kernel in turn will then ask userspace
0070 to provide a regulatory domain for the alpha2 specified by the user
0071 by sending a uevent.
0072 
0073 * Wireless subsystems for Country Information elements
0074 
0075 The kernel will send a uevent to inform userspace a new
0076 regulatory domain is required. More on this to be added
0077 as its integration is added.
0078 
0079 * Drivers
0080 
0081 If drivers determine they need a specific regulatory domain
0082 set they can inform the wireless core using regulatory_hint().
0083 They have two options -- they either provide an alpha2 so that
0084 crda can provide back a regulatory domain for that country or
0085 they can build their own regulatory domain based on internal
0086 custom knowledge so the wireless core can respect it.
0087 
0088 *Most* drivers will rely on the first mechanism of providing a
0089 regulatory hint with an alpha2. For these drivers there is an additional
0090 check that can be used to ensure compliance based on custom EEPROM
0091 regulatory data. This additional check can be used by drivers by
0092 registering on its struct wiphy a reg_notifier() callback. This notifier
0093 is called when the core's regulatory domain has been changed. The driver
0094 can use this to review the changes made and also review who made them
0095 (driver, user, country IE) and determine what to allow based on its
0096 internal EEPROM data. Devices drivers wishing to be capable of world
0097 roaming should use this callback. More on world roaming will be
0098 added to this document when its support is enabled.
0099 
0100 Device drivers who provide their own built regulatory domain
0101 do not need a callback as the channels registered by them are
0102 the only ones that will be allowed and therefore *additional*
0103 channels cannot be enabled.
0104 
0105 Example code - drivers hinting an alpha2:
0106 ------------------------------------------
0107 
0108 This example comes from the zd1211rw device driver. You can start
0109 by having a mapping of your device's EEPROM country/regulatory
0110 domain value to a specific alpha2 as follows::
0111 
0112   static struct zd_reg_alpha2_map reg_alpha2_map[] = {
0113         { ZD_REGDOMAIN_FCC, "US" },
0114         { ZD_REGDOMAIN_IC, "CA" },
0115         { ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */
0116         { ZD_REGDOMAIN_JAPAN, "JP" },
0117         { ZD_REGDOMAIN_JAPAN_ADD, "JP" },
0118         { ZD_REGDOMAIN_SPAIN, "ES" },
0119         { ZD_REGDOMAIN_FRANCE, "FR" },
0120 
0121 Then you can define a routine to map your read EEPROM value to an alpha2,
0122 as follows::
0123 
0124   static int zd_reg2alpha2(u8 regdomain, char *alpha2)
0125   {
0126         unsigned int i;
0127         struct zd_reg_alpha2_map *reg_map;
0128                 for (i = 0; i < ARRAY_SIZE(reg_alpha2_map); i++) {
0129                         reg_map = &reg_alpha2_map[i];
0130                         if (regdomain == reg_map->reg) {
0131                         alpha2[0] = reg_map->alpha2[0];
0132                         alpha2[1] = reg_map->alpha2[1];
0133                         return 0;
0134                 }
0135         }
0136         return 1;
0137   }
0138 
0139 Lastly, you can then hint to the core of your discovered alpha2, if a match
0140 was found. You need to do this after you have registered your wiphy. You
0141 are expected to do this during initialization.
0142 
0143 ::
0144 
0145         r = zd_reg2alpha2(mac->regdomain, alpha2);
0146         if (!r)
0147                 regulatory_hint(hw->wiphy, alpha2);
0148 
0149 Example code - drivers providing a built in regulatory domain:
0150 --------------------------------------------------------------
0151 
0152 [NOTE: This API is not currently available, it can be added when required]
0153 
0154 If you have regulatory information you can obtain from your
0155 driver and you *need* to use this we let you build a regulatory domain
0156 structure and pass it to the wireless core. To do this you should
0157 kmalloc() a structure big enough to hold your regulatory domain
0158 structure and you should then fill it with your data. Finally you simply
0159 call regulatory_hint() with the regulatory domain structure in it.
0160 
0161 Bellow is a simple example, with a regulatory domain cached using the stack.
0162 Your implementation may vary (read EEPROM cache instead, for example).
0163 
0164 Example cache of some regulatory domain::
0165 
0166   struct ieee80211_regdomain mydriver_jp_regdom = {
0167         .n_reg_rules = 3,
0168         .alpha2 =  "JP",
0169         //.alpha2 =  "99", /* If I have no alpha2 to map it to */
0170         .reg_rules = {
0171                 /* IEEE 802.11b/g, channels 1..14 */
0172                 REG_RULE(2412-10, 2484+10, 40, 6, 20, 0),
0173                 /* IEEE 802.11a, channels 34..48 */
0174                 REG_RULE(5170-10, 5240+10, 40, 6, 20,
0175                         NL80211_RRF_NO_IR),
0176                 /* IEEE 802.11a, channels 52..64 */
0177                 REG_RULE(5260-10, 5320+10, 40, 6, 20,
0178                         NL80211_RRF_NO_IR|
0179                         NL80211_RRF_DFS),
0180         }
0181   };
0182 
0183 Then in some part of your code after your wiphy has been registered::
0184 
0185         struct ieee80211_regdomain *rd;
0186         int size_of_regd;
0187         int num_rules = mydriver_jp_regdom.n_reg_rules;
0188         unsigned int i;
0189 
0190         size_of_regd = sizeof(struct ieee80211_regdomain) +
0191                 (num_rules * sizeof(struct ieee80211_reg_rule));
0192 
0193         rd = kzalloc(size_of_regd, GFP_KERNEL);
0194         if (!rd)
0195                 return -ENOMEM;
0196 
0197         memcpy(rd, &mydriver_jp_regdom, sizeof(struct ieee80211_regdomain));
0198 
0199         for (i=0; i < num_rules; i++)
0200                 memcpy(&rd->reg_rules[i],
0201                        &mydriver_jp_regdom.reg_rules[i],
0202                        sizeof(struct ieee80211_reg_rule));
0203         regulatory_struct_hint(rd);
0204 
0205 Statically compiled regulatory database
0206 ---------------------------------------
0207 
0208 When a database should be fixed into the kernel, it can be provided as a
0209 firmware file at build time that is then linked into the kernel.