blob: 16782a95b74aabc8464c4b3947f39ae1d7f73b0c [file] [log] [blame]
Mauro Carvalho Chehab98661e02020-04-30 18:04:20 +02001.. SPDX-License-Identifier: GPL-2.0
2
3=======================================
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07004Linux wireless regulatory documentation
Mauro Carvalho Chehab98661e02020-04-30 18:04:20 +02005=======================================
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -07006
7This document gives a brief review over how the Linux wireless
8regulatory infrastructure works.
9
10More up to date information can be obtained at the project's web page:
11
Flavio Suligoi327cdb92020-06-05 17:41:04 +020012https://wireless.wiki.kernel.org/en/developers/Regulatory
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070013
14Keeping regulatory domains in userspace
15---------------------------------------
16
17Due to the dynamic nature of regulatory domains we keep them
18in userspace and provide a framework for userspace to upload
19to the kernel one regulatory domain to be used as the central
20core regulatory domain all wireless devices should adhere to.
21
22How to get regulatory domains to the kernel
23-------------------------------------------
24
Johannes Berg007f6c52015-10-15 11:22:58 +020025When the regulatory domain is first set up, the kernel will request a
26database file (regulatory.db) containing all the regulatory rules. It
27will then use that database when it needs to look up the rules for a
28given country.
29
30How to get regulatory domains to the kernel (old CRDA solution)
31---------------------------------------------------------------
32
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070033Userspace gets a regulatory domain in the kernel by having
34a userspace agent build it and send it via nl80211. Only
35expected regulatory domains will be respected by the kernel.
36
37A currently available userspace agent which can accomplish this
38is CRDA - central regulatory domain agent. Its documented here:
39
Flavio Suligoi327cdb92020-06-05 17:41:04 +020040https://wireless.wiki.kernel.org/en/developers/Regulatory/CRDA
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070041
42Essentially the kernel will send a udev event when it knows
43it needs a new regulatory domain. A udev rule can be put in place
44to trigger crda to send the respective regulatory domain for a
45specific ISO/IEC 3166 alpha2.
46
47Below is an example udev rule which can be used:
48
49# Example file, should be put in /etc/udev/rules.d/regulatory.rules
50KERNEL=="regulatory*", ACTION=="change", SUBSYSTEM=="platform", RUN+="/sbin/crda"
51
52The alpha2 is passed as an environment variable under the variable COUNTRY.
53
54Who asks for regulatory domains?
55--------------------------------
56
57* Users
58
59Users can use iw:
60
Flavio Suligoi327cdb92020-06-05 17:41:04 +020061https://wireless.wiki.kernel.org/en/users/Documentation/iw
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070062
Mauro Carvalho Chehab98661e02020-04-30 18:04:20 +020063An example::
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -070064
65 # set regulatory domain to "Costa Rica"
66 iw reg set CR
67
68This will request the kernel to set the regulatory domain to
69the specificied alpha2. The kernel in turn will then ask userspace
70to provide a regulatory domain for the alpha2 specified by the user
71by sending a uevent.
72
73* Wireless subsystems for Country Information elements
74
75The kernel will send a uevent to inform userspace a new
76regulatory domain is required. More on this to be added
77as its integration is added.
78
79* Drivers
80
81If drivers determine they need a specific regulatory domain
82set they can inform the wireless core using regulatory_hint().
83They have two options -- they either provide an alpha2 so that
84crda can provide back a regulatory domain for that country or
85they can build their own regulatory domain based on internal
86custom knowledge so the wireless core can respect it.
87
88*Most* drivers will rely on the first mechanism of providing a
89regulatory hint with an alpha2. For these drivers there is an additional
90check that can be used to ensure compliance based on custom EEPROM
91regulatory data. This additional check can be used by drivers by
92registering on its struct wiphy a reg_notifier() callback. This notifier
93is called when the core's regulatory domain has been changed. The driver
94can use this to review the changes made and also review who made them
95(driver, user, country IE) and determine what to allow based on its
96internal EEPROM data. Devices drivers wishing to be capable of world
97roaming should use this callback. More on world roaming will be
98added to this document when its support is enabled.
99
100Device drivers who provide their own built regulatory domain
101do not need a callback as the channels registered by them are
102the only ones that will be allowed and therefore *additional*
Matt LaPlante19f59462009-04-27 15:06:31 +0200103channels cannot be enabled.
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700104
105Example code - drivers hinting an alpha2:
106------------------------------------------
107
108This example comes from the zd1211rw device driver. You can start
109by having a mapping of your device's EEPROM country/regulatory
Mauro Carvalho Chehab98661e02020-04-30 18:04:20 +0200110domain value to a specific alpha2 as follows::
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700111
Mauro Carvalho Chehab98661e02020-04-30 18:04:20 +0200112 static struct zd_reg_alpha2_map reg_alpha2_map[] = {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700113 { ZD_REGDOMAIN_FCC, "US" },
114 { ZD_REGDOMAIN_IC, "CA" },
115 { ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */
116 { ZD_REGDOMAIN_JAPAN, "JP" },
117 { ZD_REGDOMAIN_JAPAN_ADD, "JP" },
118 { ZD_REGDOMAIN_SPAIN, "ES" },
119 { ZD_REGDOMAIN_FRANCE, "FR" },
120
121Then you can define a routine to map your read EEPROM value to an alpha2,
Mauro Carvalho Chehab98661e02020-04-30 18:04:20 +0200122as follows::
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700123
Mauro Carvalho Chehab98661e02020-04-30 18:04:20 +0200124 static int zd_reg2alpha2(u8 regdomain, char *alpha2)
125 {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700126 unsigned int i;
127 struct zd_reg_alpha2_map *reg_map;
128 for (i = 0; i < ARRAY_SIZE(reg_alpha2_map); i++) {
129 reg_map = &reg_alpha2_map[i];
130 if (regdomain == reg_map->reg) {
131 alpha2[0] = reg_map->alpha2[0];
132 alpha2[1] = reg_map->alpha2[1];
133 return 0;
134 }
135 }
136 return 1;
Mauro Carvalho Chehab98661e02020-04-30 18:04:20 +0200137 }
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700138
139Lastly, you can then hint to the core of your discovered alpha2, if a match
140was found. You need to do this after you have registered your wiphy. You
141are expected to do this during initialization.
142
Mauro Carvalho Chehab98661e02020-04-30 18:04:20 +0200143::
144
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700145 r = zd_reg2alpha2(mac->regdomain, alpha2);
146 if (!r)
Johannes Bergbe3d4812008-10-24 20:32:21 +0200147 regulatory_hint(hw->wiphy, alpha2);
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700148
149Example code - drivers providing a built in regulatory domain:
150--------------------------------------------------------------
151
Johannes Bergbe3d4812008-10-24 20:32:21 +0200152[NOTE: This API is not currently available, it can be added when required]
153
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700154If you have regulatory information you can obtain from your
155driver and you *need* to use this we let you build a regulatory domain
156structure and pass it to the wireless core. To do this you should
157kmalloc() a structure big enough to hold your regulatory domain
158structure and you should then fill it with your data. Finally you simply
159call regulatory_hint() with the regulatory domain structure in it.
160
161Bellow is a simple example, with a regulatory domain cached using the stack.
162Your implementation may vary (read EEPROM cache instead, for example).
163
Mauro Carvalho Chehab98661e02020-04-30 18:04:20 +0200164Example cache of some regulatory domain::
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700165
Mauro Carvalho Chehab98661e02020-04-30 18:04:20 +0200166 struct ieee80211_regdomain mydriver_jp_regdom = {
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700167 .n_reg_rules = 3,
168 .alpha2 = "JP",
169 //.alpha2 = "99", /* If I have no alpha2 to map it to */
170 .reg_rules = {
171 /* IEEE 802.11b/g, channels 1..14 */
Rafał Miłeckib7f98862017-01-02 08:28:29 +0100172 REG_RULE(2412-10, 2484+10, 40, 6, 20, 0),
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700173 /* IEEE 802.11a, channels 34..48 */
Rafał Miłeckib7f98862017-01-02 08:28:29 +0100174 REG_RULE(5170-10, 5240+10, 40, 6, 20,
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200175 NL80211_RRF_NO_IR),
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700176 /* IEEE 802.11a, channels 52..64 */
Rafał Miłeckib7f98862017-01-02 08:28:29 +0100177 REG_RULE(5260-10, 5320+10, 40, 6, 20,
Luis R. Rodriguez8fe02e12013-10-21 19:22:25 +0200178 NL80211_RRF_NO_IR|
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700179 NL80211_RRF_DFS),
180 }
Mauro Carvalho Chehab98661e02020-04-30 18:04:20 +0200181 };
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700182
Mauro Carvalho Chehab98661e02020-04-30 18:04:20 +0200183Then in some part of your code after your wiphy has been registered::
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700184
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700185 struct ieee80211_regdomain *rd;
186 int size_of_regd;
187 int num_rules = mydriver_jp_regdom.n_reg_rules;
188 unsigned int i;
189
190 size_of_regd = sizeof(struct ieee80211_regdomain) +
191 (num_rules * sizeof(struct ieee80211_reg_rule));
192
193 rd = kzalloc(size_of_regd, GFP_KERNEL);
194 if (!rd)
Johannes Bergd2372b32008-10-24 20:32:20 +0200195 return -ENOMEM;
Luis R. Rodriguezb2e1b302008-09-09 23:19:48 -0700196
197 memcpy(rd, &mydriver_jp_regdom, sizeof(struct ieee80211_regdomain));
198
Johannes Bergd2372b32008-10-24 20:32:20 +0200199 for (i=0; i < num_rules; i++)
Johannes Bergbe3d4812008-10-24 20:32:21 +0200200 memcpy(&rd->reg_rules[i],
201 &mydriver_jp_regdom.reg_rules[i],
202 sizeof(struct ieee80211_reg_rule));
203 regulatory_struct_hint(rd);
John W. Linville3b377ea92009-12-18 17:59:01 -0500204
205Statically compiled regulatory database
206---------------------------------------
207
Johannes Bergc8c240e2015-10-15 14:35:41 +0200208When a database should be fixed into the kernel, it can be provided as a
209firmware file at build time that is then linked into the kernel.