Blame view
Documentation/networking/regulatory.rst
7.23 KB
98661e0c5 docs: networking:... |
1 2 3 |
.. SPDX-License-Identifier: GPL-2.0 ======================================= |
b2e1b3029 cfg80211: Add new... |
4 |
Linux wireless regulatory documentation |
98661e0c5 docs: networking:... |
5 |
======================================= |
b2e1b3029 cfg80211: Add new... |
6 7 8 9 10 |
This document gives a brief review over how the Linux wireless regulatory infrastructure works. More up to date information can be obtained at the project's web page: |
327cdb98f doc: networking: ... |
11 |
https://wireless.wiki.kernel.org/en/developers/Regulatory |
b2e1b3029 cfg80211: Add new... |
12 13 14 15 16 17 18 19 20 21 22 |
Keeping regulatory domains in userspace --------------------------------------- Due to the dynamic nature of regulatory domains we keep them in userspace and provide a framework for userspace to upload to the kernel one regulatory domain to be used as the central core regulatory domain all wireless devices should adhere to. How to get regulatory domains to the kernel ------------------------------------------- |
007f6c5e6 cfg80211: support... |
23 24 25 26 27 28 29 |
When the regulatory domain is first set up, the kernel will request a database file (regulatory.db) containing all the regulatory rules. It will then use that database when it needs to look up the rules for a given country. How to get regulatory domains to the kernel (old CRDA solution) --------------------------------------------------------------- |
b2e1b3029 cfg80211: Add new... |
30 31 32 33 34 35 |
Userspace gets a regulatory domain in the kernel by having a userspace agent build it and send it via nl80211. Only expected regulatory domains will be respected by the kernel. A currently available userspace agent which can accomplish this is CRDA - central regulatory domain agent. Its documented here: |
327cdb98f doc: networking: ... |
36 |
https://wireless.wiki.kernel.org/en/developers/Regulatory/CRDA |
b2e1b3029 cfg80211: Add new... |
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
Essentially the kernel will send a udev event when it knows it needs a new regulatory domain. A udev rule can be put in place to trigger crda to send the respective regulatory domain for a specific ISO/IEC 3166 alpha2. Below is an example udev rule which can be used: # Example file, should be put in /etc/udev/rules.d/regulatory.rules KERNEL=="regulatory*", ACTION=="change", SUBSYSTEM=="platform", RUN+="/sbin/crda" The alpha2 is passed as an environment variable under the variable COUNTRY. Who asks for regulatory domains? -------------------------------- * Users Users can use iw: |
327cdb98f doc: networking: ... |
56 |
https://wireless.wiki.kernel.org/en/users/Documentation/iw |
b2e1b3029 cfg80211: Add new... |
57 |
|
98661e0c5 docs: networking:... |
58 |
An example:: |
b2e1b3029 cfg80211: Add new... |
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# set regulatory domain to "Costa Rica" iw reg set CR This will request the kernel to set the regulatory domain to the specificied alpha2. The kernel in turn will then ask userspace to provide a regulatory domain for the alpha2 specified by the user by sending a uevent. * Wireless subsystems for Country Information elements The kernel will send a uevent to inform userspace a new regulatory domain is required. More on this to be added as its integration is added. * Drivers If drivers determine they need a specific regulatory domain set they can inform the wireless core using regulatory_hint(). They have two options -- they either provide an alpha2 so that crda can provide back a regulatory domain for that country or they can build their own regulatory domain based on internal custom knowledge so the wireless core can respect it. *Most* drivers will rely on the first mechanism of providing a regulatory hint with an alpha2. For these drivers there is an additional check that can be used to ensure compliance based on custom EEPROM regulatory data. This additional check can be used by drivers by registering on its struct wiphy a reg_notifier() callback. This notifier is called when the core's regulatory domain has been changed. The driver can use this to review the changes made and also review who made them (driver, user, country IE) and determine what to allow based on its internal EEPROM data. Devices drivers wishing to be capable of world roaming should use this callback. More on world roaming will be added to this document when its support is enabled. Device drivers who provide their own built regulatory domain do not need a callback as the channels registered by them are the only ones that will be allowed and therefore *additional* |
19f594600 trivial: Miscella... |
98 |
channels cannot be enabled. |
b2e1b3029 cfg80211: Add new... |
99 100 101 102 103 104 |
Example code - drivers hinting an alpha2: ------------------------------------------ This example comes from the zd1211rw device driver. You can start by having a mapping of your device's EEPROM country/regulatory |
98661e0c5 docs: networking:... |
105 |
domain value to a specific alpha2 as follows:: |
b2e1b3029 cfg80211: Add new... |
106 |
|
98661e0c5 docs: networking:... |
107 |
static struct zd_reg_alpha2_map reg_alpha2_map[] = { |
b2e1b3029 cfg80211: Add new... |
108 109 110 111 112 113 114 115 116 |
{ ZD_REGDOMAIN_FCC, "US" }, { ZD_REGDOMAIN_IC, "CA" }, { ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */ { ZD_REGDOMAIN_JAPAN, "JP" }, { ZD_REGDOMAIN_JAPAN_ADD, "JP" }, { ZD_REGDOMAIN_SPAIN, "ES" }, { ZD_REGDOMAIN_FRANCE, "FR" }, Then you can define a routine to map your read EEPROM value to an alpha2, |
98661e0c5 docs: networking:... |
117 |
as follows:: |
b2e1b3029 cfg80211: Add new... |
118 |
|
98661e0c5 docs: networking:... |
119 120 |
static int zd_reg2alpha2(u8 regdomain, char *alpha2) { |
b2e1b3029 cfg80211: Add new... |
121 122 123 124 125 126 127 128 129 130 131 |
unsigned int i; struct zd_reg_alpha2_map *reg_map; for (i = 0; i < ARRAY_SIZE(reg_alpha2_map); i++) { reg_map = ®_alpha2_map[i]; if (regdomain == reg_map->reg) { alpha2[0] = reg_map->alpha2[0]; alpha2[1] = reg_map->alpha2[1]; return 0; } } return 1; |
98661e0c5 docs: networking:... |
132 |
} |
b2e1b3029 cfg80211: Add new... |
133 134 135 136 |
Lastly, you can then hint to the core of your discovered alpha2, if a match was found. You need to do this after you have registered your wiphy. You are expected to do this during initialization. |
98661e0c5 docs: networking:... |
137 |
:: |
b2e1b3029 cfg80211: Add new... |
138 139 |
r = zd_reg2alpha2(mac->regdomain, alpha2); if (!r) |
be3d48106 wireless: remove ... |
140 |
regulatory_hint(hw->wiphy, alpha2); |
b2e1b3029 cfg80211: Add new... |
141 142 143 |
Example code - drivers providing a built in regulatory domain: -------------------------------------------------------------- |
be3d48106 wireless: remove ... |
144 |
[NOTE: This API is not currently available, it can be added when required] |
b2e1b3029 cfg80211: Add new... |
145 146 147 148 149 150 151 152 153 |
If you have regulatory information you can obtain from your driver and you *need* to use this we let you build a regulatory domain structure and pass it to the wireless core. To do this you should kmalloc() a structure big enough to hold your regulatory domain structure and you should then fill it with your data. Finally you simply call regulatory_hint() with the regulatory domain structure in it. Bellow is a simple example, with a regulatory domain cached using the stack. Your implementation may vary (read EEPROM cache instead, for example). |
98661e0c5 docs: networking:... |
154 |
Example cache of some regulatory domain:: |
b2e1b3029 cfg80211: Add new... |
155 |
|
98661e0c5 docs: networking:... |
156 |
struct ieee80211_regdomain mydriver_jp_regdom = { |
b2e1b3029 cfg80211: Add new... |
157 158 159 160 161 |
.n_reg_rules = 3, .alpha2 = "JP", //.alpha2 = "99", /* If I have no alpha2 to map it to */ .reg_rules = { /* IEEE 802.11b/g, channels 1..14 */ |
b7f98864d cfg80211: fix exa... |
162 |
REG_RULE(2412-10, 2484+10, 40, 6, 20, 0), |
b2e1b3029 cfg80211: Add new... |
163 |
/* IEEE 802.11a, channels 34..48 */ |
b7f98864d cfg80211: fix exa... |
164 |
REG_RULE(5170-10, 5240+10, 40, 6, 20, |
8fe02e167 cfg80211: consoli... |
165 |
NL80211_RRF_NO_IR), |
b2e1b3029 cfg80211: Add new... |
166 |
/* IEEE 802.11a, channels 52..64 */ |
b7f98864d cfg80211: fix exa... |
167 |
REG_RULE(5260-10, 5320+10, 40, 6, 20, |
8fe02e167 cfg80211: consoli... |
168 |
NL80211_RRF_NO_IR| |
b2e1b3029 cfg80211: Add new... |
169 170 |
NL80211_RRF_DFS), } |
98661e0c5 docs: networking:... |
171 |
}; |
b2e1b3029 cfg80211: Add new... |
172 |
|
98661e0c5 docs: networking:... |
173 |
Then in some part of your code after your wiphy has been registered:: |
b2e1b3029 cfg80211: Add new... |
174 |
|
b2e1b3029 cfg80211: Add new... |
175 176 177 178 179 180 181 182 183 184 |
struct ieee80211_regdomain *rd; int size_of_regd; int num_rules = mydriver_jp_regdom.n_reg_rules; unsigned int i; size_of_regd = sizeof(struct ieee80211_regdomain) + (num_rules * sizeof(struct ieee80211_reg_rule)); rd = kzalloc(size_of_regd, GFP_KERNEL); if (!rd) |
d2372b315 wireless: make re... |
185 |
return -ENOMEM; |
b2e1b3029 cfg80211: Add new... |
186 187 |
memcpy(rd, &mydriver_jp_regdom, sizeof(struct ieee80211_regdomain)); |
d2372b315 wireless: make re... |
188 |
for (i=0; i < num_rules; i++) |
be3d48106 wireless: remove ... |
189 190 191 192 |
memcpy(&rd->reg_rules[i], &mydriver_jp_regdom.reg_rules[i], sizeof(struct ieee80211_reg_rule)); regulatory_struct_hint(rd); |
3b377ea9d wireless: support... |
193 194 195 |
Statically compiled regulatory database --------------------------------------- |
c8c240e28 cfg80211: reg: re... |
196 197 |
When a database should be fixed into the kernel, it can be provided as a firmware file at build time that is then linked into the kernel. |