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