Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cfg80211: Add new wireless regulatory infrastructure

This adds the new wireless regulatory infrastructure. The
main motiviation behind this was to centralize regulatory
code as each driver was implementing their own regulatory solution,
and to replace the initial centralized code we have where:

* only 3 regulatory domains are supported: US, JP and EU
* regulatory domains can only be changed through module parameter
* all rules were built statically in the kernel

We now have support for regulatory domains for many countries
and regulatory domains are now queried through a userspace agent
through udev allowing distributions to update regulatory rules
without updating the kernel.

Each driver can regulatory_hint() a regulatory domain
based on either their EEPROM mapped regulatory domain value to a
respective ISO/IEC 3166-1 country code or pass an internally built
regulatory domain. We also add support to let the user set the
regulatory domain through userspace in case of faulty EEPROMs to
further help compliance.

Support for world roaming will be added soon for cards capable of
this.

For more information see:

http://wireless.kernel.org/en/developers/Regulatory/CRDA

For now we leave an option to enable the old module parameter,
ieee80211_regdom, and to build the 3 old regdomains statically
(US, JP and EU). This option is CONFIG_WIRELESS_OLD_REGULATORY.
These old static definitions and the module parameter is being
scheduled for removal for 2.6.29. Note that if you use this
you won't make use of a world regulatory domain as its pointless.
If you leave this option enabled and if CRDA is present and you
use US or JP we will try to ask CRDA to update us a regulatory
domain for us.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Luis R. Rodriguez and committed by
John W. Linville
b2e1b302 63f2c046

+1525 -130
+18
Documentation/feature-removal-schedule.txt
··· 6 6 7 7 --------------------------- 8 8 9 + What: old static regulatory information and ieee80211_regdom module parameter 10 + When: 2.6.29 11 + Why: The old regulatory infrastructure has been replaced with a new one 12 + which does not require statically defined regulatory domains. We do 13 + not want to keep static regulatory domains in the kernel due to the 14 + the dynamic nature of regulatory law and localization. We kept around 15 + the old static definitions for the regulatory domains of: 16 + * US 17 + * JP 18 + * EU 19 + and used by default the US when CONFIG_WIRELESS_OLD_REGULATORY was 20 + set. We also kept around the ieee80211_regdom module parameter in case 21 + some applications were relying on it. Changing regulatory domains 22 + can now be done instead by using nl80211, as is done with iw. 23 + Who: Luis R. Rodriguez <lrodriguez@atheros.com> 24 + 25 + --------------------------- 26 + 9 27 What: dev->power.power_state 10 28 When: July 2007 11 29 Why: Broken design for runtime control over driver power states, confusing
+194
Documentation/networking/regulatory.txt
··· 1 + Linux wireless regulatory documentation 2 + --------------------------------------- 3 + 4 + This document gives a brief review over how the Linux wireless 5 + regulatory infrastructure works. 6 + 7 + More up to date information can be obtained at the project's web page: 8 + 9 + http://wireless.kernel.org/en/developers/Regulatory 10 + 11 + Keeping regulatory domains in userspace 12 + --------------------------------------- 13 + 14 + Due to the dynamic nature of regulatory domains we keep them 15 + in userspace and provide a framework for userspace to upload 16 + to the kernel one regulatory domain to be used as the central 17 + core regulatory domain all wireless devices should adhere to. 18 + 19 + How to get regulatory domains to the kernel 20 + ------------------------------------------- 21 + 22 + Userspace gets a regulatory domain in the kernel by having 23 + a userspace agent build it and send it via nl80211. Only 24 + expected regulatory domains will be respected by the kernel. 25 + 26 + A currently available userspace agent which can accomplish this 27 + is CRDA - central regulatory domain agent. Its documented here: 28 + 29 + http://wireless.kernel.org/en/developers/Regulatory/CRDA 30 + 31 + Essentially the kernel will send a udev event when it knows 32 + it needs a new regulatory domain. A udev rule can be put in place 33 + to trigger crda to send the respective regulatory domain for a 34 + specific ISO/IEC 3166 alpha2. 35 + 36 + Below is an example udev rule which can be used: 37 + 38 + # Example file, should be put in /etc/udev/rules.d/regulatory.rules 39 + KERNEL=="regulatory*", ACTION=="change", SUBSYSTEM=="platform", RUN+="/sbin/crda" 40 + 41 + The alpha2 is passed as an environment variable under the variable COUNTRY. 42 + 43 + Who asks for regulatory domains? 44 + -------------------------------- 45 + 46 + * Users 47 + 48 + Users can use iw: 49 + 50 + http://wireless.kernel.org/en/users/Documentation/iw 51 + 52 + An example: 53 + 54 + # set regulatory domain to "Costa Rica" 55 + iw reg set CR 56 + 57 + This will request the kernel to set the regulatory domain to 58 + the specificied alpha2. The kernel in turn will then ask userspace 59 + to provide a regulatory domain for the alpha2 specified by the user 60 + by sending a uevent. 61 + 62 + * Wireless subsystems for Country Information elements 63 + 64 + The kernel will send a uevent to inform userspace a new 65 + regulatory domain is required. More on this to be added 66 + as its integration is added. 67 + 68 + * Drivers 69 + 70 + If drivers determine they need a specific regulatory domain 71 + set they can inform the wireless core using regulatory_hint(). 72 + They have two options -- they either provide an alpha2 so that 73 + crda can provide back a regulatory domain for that country or 74 + they can build their own regulatory domain based on internal 75 + custom knowledge so the wireless core can respect it. 76 + 77 + *Most* drivers will rely on the first mechanism of providing a 78 + regulatory hint with an alpha2. For these drivers there is an additional 79 + check that can be used to ensure compliance based on custom EEPROM 80 + regulatory data. This additional check can be used by drivers by 81 + registering on its struct wiphy a reg_notifier() callback. This notifier 82 + is called when the core's regulatory domain has been changed. The driver 83 + can use this to review the changes made and also review who made them 84 + (driver, user, country IE) and determine what to allow based on its 85 + internal EEPROM data. Devices drivers wishing to be capable of world 86 + roaming should use this callback. More on world roaming will be 87 + added to this document when its support is enabled. 88 + 89 + Device drivers who provide their own built regulatory domain 90 + do not need a callback as the channels registered by them are 91 + the only ones that will be allowed and therefore *additional* 92 + cannels cannot be enabled. 93 + 94 + Example code - drivers hinting an alpha2: 95 + ------------------------------------------ 96 + 97 + This example comes from the zd1211rw device driver. You can start 98 + by having a mapping of your device's EEPROM country/regulatory 99 + domain value to to a specific alpha2 as follows: 100 + 101 + static struct zd_reg_alpha2_map reg_alpha2_map[] = { 102 + { ZD_REGDOMAIN_FCC, "US" }, 103 + { ZD_REGDOMAIN_IC, "CA" }, 104 + { ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */ 105 + { ZD_REGDOMAIN_JAPAN, "JP" }, 106 + { ZD_REGDOMAIN_JAPAN_ADD, "JP" }, 107 + { ZD_REGDOMAIN_SPAIN, "ES" }, 108 + { ZD_REGDOMAIN_FRANCE, "FR" }, 109 + 110 + Then you can define a routine to map your read EEPROM value to an alpha2, 111 + as follows: 112 + 113 + static int zd_reg2alpha2(u8 regdomain, char *alpha2) 114 + { 115 + unsigned int i; 116 + struct zd_reg_alpha2_map *reg_map; 117 + for (i = 0; i < ARRAY_SIZE(reg_alpha2_map); i++) { 118 + reg_map = &reg_alpha2_map[i]; 119 + if (regdomain == reg_map->reg) { 120 + alpha2[0] = reg_map->alpha2[0]; 121 + alpha2[1] = reg_map->alpha2[1]; 122 + return 0; 123 + } 124 + } 125 + return 1; 126 + } 127 + 128 + Lastly, you can then hint to the core of your discovered alpha2, if a match 129 + was found. You need to do this after you have registered your wiphy. You 130 + are expected to do this during initialization. 131 + 132 + r = zd_reg2alpha2(mac->regdomain, alpha2); 133 + if (!r) 134 + regulatory_hint(hw->wiphy, alpha2, NULL); 135 + 136 + Example code - drivers providing a built in regulatory domain: 137 + -------------------------------------------------------------- 138 + 139 + If you have regulatory information you can obtain from your 140 + driver and you *need* to use this we let you build a regulatory domain 141 + structure and pass it to the wireless core. To do this you should 142 + kmalloc() a structure big enough to hold your regulatory domain 143 + structure and you should then fill it with your data. Finally you simply 144 + call regulatory_hint() with the regulatory domain structure in it. 145 + 146 + Bellow is a simple example, with a regulatory domain cached using the stack. 147 + Your implementation may vary (read EEPROM cache instead, for example). 148 + 149 + Example cache of some regulatory domain 150 + 151 + struct ieee80211_regdomain mydriver_jp_regdom = { 152 + .n_reg_rules = 3, 153 + .alpha2 = "JP", 154 + //.alpha2 = "99", /* If I have no alpha2 to map it to */ 155 + .reg_rules = { 156 + /* IEEE 802.11b/g, channels 1..14 */ 157 + REG_RULE(2412-20, 2484+20, 40, 6, 20, 0), 158 + /* IEEE 802.11a, channels 34..48 */ 159 + REG_RULE(5170-20, 5240+20, 40, 6, 20, 160 + NL80211_RRF_PASSIVE_SCAN), 161 + /* IEEE 802.11a, channels 52..64 */ 162 + REG_RULE(5260-20, 5320+20, 40, 6, 20, 163 + NL80211_RRF_NO_IBSS | 164 + NL80211_RRF_DFS), 165 + } 166 + }; 167 + 168 + Then in some part of your code after your wiphy has been registered: 169 + 170 + int r; 171 + struct ieee80211_regdomain *rd; 172 + int size_of_regd; 173 + int num_rules = mydriver_jp_regdom.n_reg_rules; 174 + unsigned int i; 175 + 176 + size_of_regd = sizeof(struct ieee80211_regdomain) + 177 + (num_rules * sizeof(struct ieee80211_reg_rule)); 178 + 179 + rd = kzalloc(size_of_regd, GFP_KERNEL); 180 + if (!rd) 181 + return -ENOMEM; 182 + 183 + memcpy(rd, &mydriver_jp_regdom, sizeof(struct ieee80211_regdomain)); 184 + 185 + for (i=0; i < num_rules; i++) { 186 + memcpy(&rd->reg_rules[i], &mydriver_jp_regdom.reg_rules[i], 187 + sizeof(struct ieee80211_reg_rule)); 188 + } 189 + r = regulatory_hint(hw->wiphy, NULL, rd); 190 + if (r) { 191 + kfree(rd); 192 + return r; 193 + } 194 +
+94 -2
include/linux/nl80211.h
··· 92 92 * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by 93 93 * %NL80211_ATTR_IFINDEX. 94 94 * 95 + * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command 96 + * after being queried by the kernel. CRDA replies by sending a regulatory 97 + * domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our 98 + * current alpha2 if it found a match. It also provides 99 + * NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each 100 + * regulatory rule is a nested set of attributes given by 101 + * %NL80211_ATTR_REG_RULE_FREQ_[START|END] and 102 + * %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by 103 + * %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and 104 + * %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP. 105 + * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain 106 + * to the the specified ISO/IEC 3166-1 alpha2 country code. The core will 107 + * store this as a valid request and then query userspace for it. 108 + * 95 109 * @NL80211_CMD_MAX: highest used command number 96 110 * @__NL80211_CMD_AFTER_LAST: internal use 97 111 */ ··· 145 131 146 132 NL80211_CMD_SET_BSS, 147 133 148 - /* add commands here */ 134 + NL80211_CMD_SET_REG, 135 + NL80211_CMD_REQ_SET_REG, 136 + 137 + /* add new commands above here */ 149 138 150 139 /* used to define NL80211_CMD_MAX below */ 151 140 __NL80211_CMD_AFTER_LAST, ··· 214 197 * info given for %NL80211_CMD_GET_MPATH, nested attribute described at 215 198 * &enum nl80211_mpath_info. 216 199 * 217 - * 218 200 * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of 219 201 * &enum nl80211_mntr_flags. 202 + * 203 + * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the 204 + * current regulatory domain should be set to or is already set to. 205 + * For example, 'CR', for Costa Rica. This attribute is used by the kernel 206 + * to query the CRDA to retrieve one regulatory domain. This attribute can 207 + * also be used by userspace to query the kernel for the currently set 208 + * regulatory domain. We chose an alpha2 as that is also used by the 209 + * IEEE-802.11d country information element to identify a country. 210 + * Users can also simply ask the wireless core to set regulatory domain 211 + * to a specific alpha2. 212 + * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory 213 + * rules. 220 214 * 221 215 * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1) 222 216 * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled ··· 293 265 294 266 NL80211_ATTR_SUPPORTED_IFTYPES, 295 267 268 + NL80211_ATTR_REG_ALPHA2, 269 + NL80211_ATTR_REG_RULES, 270 + 296 271 /* add attributes here, update the policy in nl80211.c */ 297 272 298 273 __NL80211_ATTR_AFTER_LAST, ··· 309 278 #define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY 310 279 311 280 #define NL80211_MAX_SUPP_RATES 32 281 + #define NL80211_MAX_SUPP_REG_RULES 32 312 282 #define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 313 283 #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 314 284 #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 ··· 502 470 /* keep last */ 503 471 __NL80211_BITRATE_ATTR_AFTER_LAST, 504 472 NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1 473 + }; 474 + 475 + /** 476 + * enum nl80211_reg_rule_attr - regulatory rule attributes 477 + * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional 478 + * considerations for a given frequency range. These are the 479 + * &enum nl80211_reg_rule_flags. 480 + * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory 481 + * rule in KHz. This is not a center of frequency but an actual regulatory 482 + * band edge. 483 + * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule 484 + * in KHz. This is not a center a frequency but an actual regulatory 485 + * band edge. 486 + * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this 487 + * frequency range, in KHz. 488 + * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain 489 + * for a given frequency range. The value is in mBi (100 * dBi). 490 + * If you don't have one then don't send this. 491 + * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for 492 + * a given frequency range. The value is in mBm (100 * dBm). 493 + */ 494 + enum nl80211_reg_rule_attr { 495 + __NL80211_REG_RULE_ATTR_INVALID, 496 + NL80211_ATTR_REG_RULE_FLAGS, 497 + 498 + NL80211_ATTR_FREQ_RANGE_START, 499 + NL80211_ATTR_FREQ_RANGE_END, 500 + NL80211_ATTR_FREQ_RANGE_MAX_BW, 501 + 502 + NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, 503 + NL80211_ATTR_POWER_RULE_MAX_EIRP, 504 + 505 + /* keep last */ 506 + __NL80211_REG_RULE_ATTR_AFTER_LAST, 507 + NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1 508 + }; 509 + 510 + /** 511 + * enum nl80211_reg_rule_flags - regulatory rule flags 512 + * 513 + * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed 514 + * @NL80211_RRF_NO_CCK: CCK modulation not allowed 515 + * @NL80211_RRF_NO_INDOOR: indoor operation not allowed 516 + * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed 517 + * @NL80211_RRF_DFS: DFS support is required to be used 518 + * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links 519 + * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links 520 + * @NL80211_RRF_PASSIVE_SCAN: passive scan is required 521 + * @NL80211_RRF_NO_IBSS: no IBSS is allowed 522 + */ 523 + enum nl80211_reg_rule_flags { 524 + NL80211_RRF_NO_OFDM = 1<<0, 525 + NL80211_RRF_NO_CCK = 1<<1, 526 + NL80211_RRF_NO_INDOOR = 1<<2, 527 + NL80211_RRF_NO_OUTDOOR = 1<<3, 528 + NL80211_RRF_DFS = 1<<4, 529 + NL80211_RRF_PTP_ONLY = 1<<5, 530 + NL80211_RRF_PTMP_ONLY = 1<<6, 531 + NL80211_RRF_PASSIVE_SCAN = 1<<7, 532 + NL80211_RRF_NO_IBSS = 1<<8, 505 533 }; 506 534 507 535 /**
+60
include/net/cfg80211.h
··· 287 287 int use_short_slot_time; 288 288 }; 289 289 290 + /** 291 + * enum reg_set_by - Indicates who is trying to set the regulatory domain 292 + * @REGDOM_SET_BY_INIT: regulatory domain was set by initialization. We will be 293 + * using a static world regulatory domain by default. 294 + * @REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world regulatory domain. 295 + * @REGDOM_SET_BY_USER: User asked the wireless core to set the 296 + * regulatory domain. 297 + * @REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the wireless core 298 + * it thinks its knows the regulatory domain we should be in. 299 + * @REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an 802.11 country 300 + * information element with regulatory information it thinks we 301 + * should consider. 302 + */ 303 + enum reg_set_by { 304 + REGDOM_SET_BY_INIT, 305 + REGDOM_SET_BY_CORE, 306 + REGDOM_SET_BY_USER, 307 + REGDOM_SET_BY_DRIVER, 308 + REGDOM_SET_BY_COUNTRY_IE, 309 + }; 310 + 311 + struct ieee80211_freq_range { 312 + u32 start_freq_khz; 313 + u32 end_freq_khz; 314 + u32 max_bandwidth_khz; 315 + }; 316 + 317 + struct ieee80211_power_rule { 318 + u32 max_antenna_gain; 319 + u32 max_eirp; 320 + }; 321 + 322 + struct ieee80211_reg_rule { 323 + struct ieee80211_freq_range freq_range; 324 + struct ieee80211_power_rule power_rule; 325 + u32 flags; 326 + }; 327 + 328 + struct ieee80211_regdomain { 329 + u32 n_reg_rules; 330 + char alpha2[2]; 331 + struct ieee80211_reg_rule reg_rules[]; 332 + }; 333 + 334 + #define MHZ_TO_KHZ(freq) (freq * 1000) 335 + #define KHZ_TO_MHZ(freq) (freq / 1000) 336 + #define DBI_TO_MBI(gain) (gain * 100) 337 + #define MBI_TO_DBI(gain) (gain / 100) 338 + #define DBM_TO_MBM(gain) (gain * 100) 339 + #define MBM_TO_DBM(gain) (gain / 100) 340 + 341 + #define REG_RULE(start, end, bw, gain, eirp, reg_flags) { \ 342 + .freq_range.start_freq_khz = (start) * 1000, \ 343 + .freq_range.end_freq_khz = (end) * 1000, \ 344 + .freq_range.max_bandwidth_khz = (bw) * 1000, \ 345 + .power_rule.max_antenna_gain = (gain) * 100, \ 346 + .power_rule.max_eirp = (eirp) * 100, \ 347 + .flags = reg_flags, \ 348 + } 349 + 290 350 /* from net/wireless.h */ 291 351 struct wiphy; 292 352
+2
include/net/mac80211.h
··· 833 833 s8 max_signal; 834 834 }; 835 835 836 + struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy); 837 + 836 838 /** 837 839 * SET_IEEE80211_DEV - set device for 802.11 hardware 838 840 *
+58
include/net/wireless.h
··· 60 60 * with cfg80211. 61 61 * 62 62 * @center_freq: center frequency in MHz 63 + * @max_bandwidth: maximum allowed bandwidth for this channel, in MHz 63 64 * @hw_value: hardware-specific value for the channel 64 65 * @flags: channel flags from &enum ieee80211_channel_flags. 65 66 * @orig_flags: channel flags at registration time, used by regulatory ··· 74 73 struct ieee80211_channel { 75 74 enum ieee80211_band band; 76 75 u16 center_freq; 76 + u8 max_bandwidth; 77 77 u16 hw_value; 78 78 u32 flags; 79 79 int max_antenna_gain; ··· 180 178 * struct wiphy - wireless hardware description 181 179 * @idx: the wiphy index assigned to this item 182 180 * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name> 181 + * @reg_notifier: the driver's regulatory notification callback 183 182 */ 184 183 struct wiphy { 185 184 /* assign these fields before you register the wiphy */ ··· 199 196 void *privid; 200 197 201 198 struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS]; 199 + 200 + /* Lets us get back the wiphy on the callback */ 201 + int (*reg_notifier)(struct wiphy *wiphy, enum reg_set_by setby); 202 202 203 203 /* fields below are read-only, assigned by cfg80211 */ 204 204 ··· 328 322 */ 329 323 extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy, 330 324 int freq); 325 + /** 326 + * __regulatory_hint - hint to the wireless core a regulatory domain 327 + * @wiphy: if a driver is providing the hint this is the driver's very 328 + * own &struct wiphy 329 + * @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain 330 + * should be in. If @rd is set this should be NULL 331 + * @rd: a complete regulatory domain, if passed the caller need not worry 332 + * about freeing it 333 + * 334 + * The Wireless subsystem can use this function to hint to the wireless core 335 + * what it believes should be the current regulatory domain by 336 + * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory 337 + * domain should be in or by providing a completely build regulatory domain. 338 + * 339 + * Returns -EALREADY if *a regulatory domain* has already been set. Note that 340 + * this could be by another driver. It is safe for drivers to continue if 341 + * -EALREADY is returned, if drivers are not capable of world roaming they 342 + * should not register more channels than they support. Right now we only 343 + * support listening to the first driver hint. If the driver is capable 344 + * of world roaming but wants to respect its own EEPROM mappings for 345 + * specific regulatory domains it should register the @reg_notifier callback 346 + * on the &struct wiphy. Returns 0 if the hint went through fine or through an 347 + * intersection operation. Otherwise a standard error code is returned. 348 + * 349 + */ 350 + extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, 351 + const char *alpha2, struct ieee80211_regdomain *rd); 352 + /** 353 + * regulatory_hint - driver hint to the wireless core a regulatory domain 354 + * @wiphy: the driver's very own &struct wiphy 355 + * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain 356 + * should be in. If @rd is set this should be NULL. Note that if you 357 + * set this to NULL you should still set rd->alpha2 to some accepted 358 + * alpha2. 359 + * @rd: a complete regulatory domain provided by the driver. If passed 360 + * the driver does not need to worry about freeing it. 361 + * 362 + * Wireless drivers can use this function to hint to the wireless core 363 + * what it believes should be the current regulatory domain by 364 + * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory 365 + * domain should be in or by providing a completely build regulatory domain. 366 + * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried 367 + * for a regulatory domain structure for the respective country. If 368 + * a regulatory domain is build and passed you should set the alpha2 369 + * if possible, otherwise set it to the special value of "99" which tells 370 + * the wireless core it is unknown. If you pass a built regulatory domain 371 + * and we return non zero you are in charge of kfree()'ing the structure. 372 + * 373 + * See __regulatory_hint() documentation for possible return values. 374 + */ 375 + extern int regulatory_hint(struct wiphy *wiphy, 376 + const char *alpha2, struct ieee80211_regdomain *rd); 331 377 332 378 /** 333 379 * ieee80211_get_channel - get channel struct from wiphy for specified frequency
+7
net/mac80211/cfg.c
··· 17 17 #include "rate.h" 18 18 #include "mesh.h" 19 19 20 + struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy) 21 + { 22 + struct ieee80211_local *local = wiphy_priv(wiphy); 23 + return &local->hw; 24 + } 25 + EXPORT_SYMBOL(wiphy_to_hw); 26 + 20 27 static enum ieee80211_if_types 21 28 nl80211_type_to_mac80211_type(enum nl80211_iftype type) 22 29 {
+32
net/wireless/Kconfig
··· 14 14 15 15 If unsure, say Y. 16 16 17 + config WIRELESS_OLD_REGULATORY 18 + bool "Old wireless static regulatory defintions" 19 + default n 20 + ---help--- 21 + This option enables the old static regulatory information 22 + and uses it within the new framework. This is available 23 + temporarily as an option to help prevent immediate issues 24 + due to the switch to the new regulatory framework which 25 + does require a new userspace application which has the 26 + database of regulatory information (CRDA) and another for 27 + setting regulatory domains (iw). 28 + 29 + For more information see: 30 + 31 + http://wireless.kernel.org/en/developers/Regulatory/CRDA 32 + http://wireless.kernel.org/en/users/Documentation/iw 33 + 34 + It is important to note though that if you *do* have CRDA present 35 + and if this option is enabled CRDA *will* be called to update the 36 + regulatory domain (for US and JP only). Support for letting the user 37 + set the regulatory domain through iw is also supported. This option 38 + mainly exists to leave around for a kernel release some old static 39 + regulatory domains that were defined and to keep around the old 40 + ieee80211_regdom module parameter. This is being phased out and you 41 + should stop using them ASAP. 42 + 43 + Say N unless you cannot install a new userspace application 44 + or have one currently depending on the ieee80211_regdom module 45 + parameter and cannot port it to use the new userspace interfaces. 46 + 47 + This is scheduled for removal for 2.6.29. 48 + 17 49 config WIRELESS_EXT 18 50 bool "Wireless extensions" 19 51 default n
+160 -2
net/wireless/core.c
··· 13 13 #include <linux/debugfs.h> 14 14 #include <linux/notifier.h> 15 15 #include <linux/device.h> 16 + #include <linux/list.h> 16 17 #include <net/genetlink.h> 17 18 #include <net/cfg80211.h> 18 19 #include <net/wireless.h> 19 20 #include "nl80211.h" 20 21 #include "core.h" 21 22 #include "sysfs.h" 23 + #include "reg.h" 22 24 23 25 /* name for sysfs, %d is appended */ 24 26 #define PHY_NAME "phy" ··· 28 26 MODULE_AUTHOR("Johannes Berg"); 29 27 MODULE_LICENSE("GPL"); 30 28 MODULE_DESCRIPTION("wireless configuration support"); 29 + 30 + struct list_head regulatory_requests; 31 + 32 + /* Central wireless core regulatory domains, we only need two, 33 + * the current one and a world regulatory domain in case we have no 34 + * information to give us an alpha2 */ 35 + struct ieee80211_regdomain *cfg80211_regdomain; 36 + 37 + /* We keep a static world regulatory domain in case of the absence of CRDA */ 38 + const struct ieee80211_regdomain world_regdom = { 39 + .n_reg_rules = 1, 40 + .alpha2 = "00", 41 + .reg_rules = { 42 + REG_RULE(2402, 2472, 40, 6, 20, 43 + NL80211_RRF_PASSIVE_SCAN | 44 + NL80211_RRF_NO_IBSS), 45 + } 46 + }; 47 + 48 + #ifdef CONFIG_WIRELESS_OLD_REGULATORY 49 + /* All this fucking static junk will be removed soon, so 50 + * don't fucking count on it !@#$ */ 51 + 52 + static char *ieee80211_regdom = "US"; 53 + module_param(ieee80211_regdom, charp, 0444); 54 + MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); 55 + 56 + /* We assume 40 MHz bandwidth for the old regulatory work. 57 + * We make emphasis we are using the exact same frequencies 58 + * as before */ 59 + 60 + const struct ieee80211_regdomain us_regdom = { 61 + .n_reg_rules = 6, 62 + .alpha2 = "US", 63 + .reg_rules = { 64 + /* IEEE 802.11b/g, channels 1..11 */ 65 + REG_RULE(2412-20, 2462+20, 40, 6, 27, 0), 66 + /* IEEE 802.11a, channel 36 */ 67 + REG_RULE(5180-20, 5180+20, 40, 6, 23, 0), 68 + /* IEEE 802.11a, channel 40 */ 69 + REG_RULE(5200-20, 5200+20, 40, 6, 23, 0), 70 + /* IEEE 802.11a, channel 44 */ 71 + REG_RULE(5220-20, 5220+20, 40, 6, 23, 0), 72 + /* IEEE 802.11a, channels 48..64 */ 73 + REG_RULE(5240-20, 5320+20, 40, 6, 23, 0), 74 + /* IEEE 802.11a, channels 149..165, outdoor */ 75 + REG_RULE(5745-20, 5825+20, 40, 6, 30, 0), 76 + } 77 + }; 78 + 79 + const struct ieee80211_regdomain jp_regdom = { 80 + .n_reg_rules = 3, 81 + .alpha2 = "JP", 82 + .reg_rules = { 83 + /* IEEE 802.11b/g, channels 1..14 */ 84 + REG_RULE(2412-20, 2484+20, 40, 6, 20, 0), 85 + /* IEEE 802.11a, channels 34..48 */ 86 + REG_RULE(5170-20, 5240+20, 40, 6, 20, 87 + NL80211_RRF_PASSIVE_SCAN), 88 + /* IEEE 802.11a, channels 52..64 */ 89 + REG_RULE(5260-20, 5320+20, 40, 6, 20, 90 + NL80211_RRF_NO_IBSS | 91 + NL80211_RRF_DFS), 92 + } 93 + }; 94 + 95 + const struct ieee80211_regdomain eu_regdom = { 96 + .n_reg_rules = 6, 97 + /* This alpha2 is bogus, we leave it here just for stupid 98 + * backward compatibility */ 99 + .alpha2 = "EU", 100 + .reg_rules = { 101 + /* IEEE 802.11b/g, channels 1..13 */ 102 + REG_RULE(2412-20, 2472+20, 40, 6, 20, 0), 103 + /* IEEE 802.11a, channel 36 */ 104 + REG_RULE(5180-20, 5180+20, 40, 6, 23, 105 + NL80211_RRF_PASSIVE_SCAN), 106 + /* IEEE 802.11a, channel 40 */ 107 + REG_RULE(5200-20, 5200+20, 40, 6, 23, 108 + NL80211_RRF_PASSIVE_SCAN), 109 + /* IEEE 802.11a, channel 44 */ 110 + REG_RULE(5220-20, 5220+20, 40, 6, 23, 111 + NL80211_RRF_PASSIVE_SCAN), 112 + /* IEEE 802.11a, channels 48..64 */ 113 + REG_RULE(5240-20, 5320+20, 40, 6, 20, 114 + NL80211_RRF_NO_IBSS | 115 + NL80211_RRF_DFS), 116 + /* IEEE 802.11a, channels 100..140 */ 117 + REG_RULE(5500-20, 5700+20, 40, 6, 30, 118 + NL80211_RRF_NO_IBSS | 119 + NL80211_RRF_DFS), 120 + } 121 + }; 122 + 123 + #endif 124 + 125 + struct ieee80211_regdomain *cfg80211_world_regdom = 126 + (struct ieee80211_regdomain *) &world_regdom; 127 + 128 + LIST_HEAD(regulatory_requests); 129 + DEFINE_MUTEX(cfg80211_reg_mutex); 31 130 32 131 /* RCU might be appropriate here since we usually 33 132 * only read the list, and that can happen quite ··· 405 302 ieee80211_set_bitrate_flags(wiphy); 406 303 407 304 /* set up regulatory info */ 408 - wiphy_update_regulatory(wiphy); 305 + mutex_lock(&cfg80211_reg_mutex); 306 + wiphy_update_regulatory(wiphy, REGDOM_SET_BY_CORE); 307 + mutex_unlock(&cfg80211_reg_mutex); 409 308 410 309 mutex_lock(&cfg80211_drv_mutex); 411 310 ··· 514 409 .notifier_call = cfg80211_netdev_notifier_call, 515 410 }; 516 411 412 + #ifdef CONFIG_WIRELESS_OLD_REGULATORY 413 + const struct ieee80211_regdomain *static_regdom(char *alpha2) 414 + { 415 + if (alpha2[0] == 'U' && alpha2[1] == 'S') 416 + return &us_regdom; 417 + if (alpha2[0] == 'J' && alpha2[1] == 'P') 418 + return &jp_regdom; 419 + if (alpha2[0] == 'E' && alpha2[1] == 'U') 420 + return &eu_regdom; 421 + /* Default, as per the old rules */ 422 + return &us_regdom; 423 + } 424 + #endif 425 + 517 426 static int cfg80211_init(void) 518 427 { 519 - int err = wiphy_sysfs_init(); 428 + int err; 429 + 430 + #ifdef CONFIG_WIRELESS_OLD_REGULATORY 431 + cfg80211_regdomain = 432 + (struct ieee80211_regdomain *) static_regdom(ieee80211_regdom); 433 + /* Used during reset_regdomains_static() */ 434 + cfg80211_world_regdom = cfg80211_regdomain; 435 + #else 436 + cfg80211_regdomain = 437 + (struct ieee80211_regdomain *) cfg80211_world_regdom; 438 + #endif 439 + 440 + err = wiphy_sysfs_init(); 520 441 if (err) 521 442 goto out_fail_sysfs; 522 443 ··· 556 425 557 426 ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL); 558 427 428 + err = regulatory_init(); 429 + if (err) 430 + goto out_fail_reg; 431 + 432 + #ifdef CONFIG_WIRELESS_OLD_REGULATORY 433 + printk(KERN_INFO "cfg80211: Using old static regulatory domain:\n"); 434 + print_regdomain_info(cfg80211_regdomain); 435 + /* The old code still requests for a new regdomain and if 436 + * you have CRDA you get it updated, otherwise you get 437 + * stuck with the static values. We ignore "EU" code as 438 + * that is not a valid ISO / IEC 3166 alpha2 */ 439 + if (ieee80211_regdom[0] != 'E' && 440 + ieee80211_regdom[1] != 'U') 441 + err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, 442 + ieee80211_regdom, NULL); 443 + #else 444 + err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", NULL); 445 + if (err) 446 + printk(KERN_ERR "cfg80211: calling CRDA failed - " 447 + "unable to update world regulatory domain, " 448 + "using static definition\n"); 449 + #endif 450 + 559 451 return 0; 560 452 453 + out_fail_reg: 454 + debugfs_remove(ieee80211_debugfs_dir); 561 455 out_fail_nl80211: 562 456 unregister_netdevice_notifier(&cfg80211_netdev_notifier); 563 457 out_fail_notifier: ··· 590 434 out_fail_sysfs: 591 435 return err; 592 436 } 437 + 593 438 subsys_initcall(cfg80211_init); 594 439 595 440 static void cfg80211_exit(void) ··· 599 442 nl80211_exit(); 600 443 unregister_netdevice_notifier(&cfg80211_netdev_notifier); 601 444 wiphy_sysfs_exit(); 445 + regulatory_exit(); 602 446 } 603 447 module_exit(cfg80211_exit);
+1 -1
net/wireless/core.h
··· 79 79 char *newname); 80 80 81 81 void ieee80211_set_bitrate_flags(struct wiphy *wiphy); 82 - void wiphy_update_regulatory(struct wiphy *wiphy); 82 + void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby); 83 83 84 84 #endif /* __NET_WIRELESS_CORE_H */
+151
net/wireless/nl80211.c
··· 18 18 #include <net/cfg80211.h> 19 19 #include "core.h" 20 20 #include "nl80211.h" 21 + #include "reg.h" 21 22 22 23 /* the netlink family */ 23 24 static struct genl_family nl80211_fam = { ··· 88 87 [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, 89 88 .len = IEEE80211_MAX_MESH_ID_LEN }, 90 89 [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, 90 + 91 + [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 }, 92 + [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED }, 91 93 92 94 [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 }, 93 95 [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 }, ··· 1603 1599 return err; 1604 1600 } 1605 1601 1602 + static const struct nla_policy 1603 + reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { 1604 + [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 }, 1605 + [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 }, 1606 + [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 }, 1607 + [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, 1608 + [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, 1609 + [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, 1610 + }; 1611 + 1612 + static int parse_reg_rule(struct nlattr *tb[], 1613 + struct ieee80211_reg_rule *reg_rule) 1614 + { 1615 + struct ieee80211_freq_range *freq_range = &reg_rule->freq_range; 1616 + struct ieee80211_power_rule *power_rule = &reg_rule->power_rule; 1617 + 1618 + if (!tb[NL80211_ATTR_REG_RULE_FLAGS]) 1619 + return -EINVAL; 1620 + if (!tb[NL80211_ATTR_FREQ_RANGE_START]) 1621 + return -EINVAL; 1622 + if (!tb[NL80211_ATTR_FREQ_RANGE_END]) 1623 + return -EINVAL; 1624 + if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) 1625 + return -EINVAL; 1626 + if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) 1627 + return -EINVAL; 1628 + 1629 + reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]); 1630 + 1631 + freq_range->start_freq_khz = 1632 + nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); 1633 + freq_range->end_freq_khz = 1634 + nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); 1635 + freq_range->max_bandwidth_khz = 1636 + nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); 1637 + 1638 + power_rule->max_eirp = 1639 + nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); 1640 + 1641 + if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]) 1642 + power_rule->max_antenna_gain = 1643 + nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]); 1644 + 1645 + return 0; 1646 + } 1647 + 1648 + static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) 1649 + { 1650 + int r; 1651 + char *data = NULL; 1652 + 1653 + if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) 1654 + return -EINVAL; 1655 + 1656 + data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); 1657 + 1658 + #ifdef CONFIG_WIRELESS_OLD_REGULATORY 1659 + /* We ignore world regdom requests with the old regdom setup */ 1660 + if (is_world_regdom(data)) 1661 + return -EINVAL; 1662 + #endif 1663 + mutex_lock(&cfg80211_drv_mutex); 1664 + r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, NULL); 1665 + mutex_unlock(&cfg80211_drv_mutex); 1666 + return r; 1667 + } 1668 + 1669 + static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) 1670 + { 1671 + struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; 1672 + struct nlattr *nl_reg_rule; 1673 + char *alpha2 = NULL; 1674 + int rem_reg_rules = 0, r = 0; 1675 + u32 num_rules = 0, rule_idx = 0, size_of_regd; 1676 + struct ieee80211_regdomain *rd = NULL; 1677 + 1678 + if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) 1679 + return -EINVAL; 1680 + 1681 + if (!info->attrs[NL80211_ATTR_REG_RULES]) 1682 + return -EINVAL; 1683 + 1684 + alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); 1685 + 1686 + nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], 1687 + rem_reg_rules) { 1688 + num_rules++; 1689 + if (num_rules > NL80211_MAX_SUPP_REG_RULES) 1690 + goto bad_reg; 1691 + } 1692 + 1693 + if (!reg_is_valid_request(alpha2)) 1694 + return -EINVAL; 1695 + 1696 + size_of_regd = sizeof(struct ieee80211_regdomain) + 1697 + (num_rules * sizeof(struct ieee80211_reg_rule)); 1698 + 1699 + rd = kzalloc(size_of_regd, GFP_KERNEL); 1700 + if (!rd) 1701 + return -ENOMEM; 1702 + 1703 + rd->n_reg_rules = num_rules; 1704 + rd->alpha2[0] = alpha2[0]; 1705 + rd->alpha2[1] = alpha2[1]; 1706 + 1707 + nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], 1708 + rem_reg_rules) { 1709 + nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, 1710 + nla_data(nl_reg_rule), nla_len(nl_reg_rule), 1711 + reg_rule_policy); 1712 + r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]); 1713 + if (r) 1714 + goto bad_reg; 1715 + 1716 + rule_idx++; 1717 + 1718 + if (rule_idx > NL80211_MAX_SUPP_REG_RULES) 1719 + goto bad_reg; 1720 + } 1721 + 1722 + BUG_ON(rule_idx != num_rules); 1723 + 1724 + mutex_lock(&cfg80211_drv_mutex); 1725 + r = set_regdom(rd); 1726 + mutex_unlock(&cfg80211_drv_mutex); 1727 + if (r) 1728 + goto bad_reg; 1729 + 1730 + return r; 1731 + 1732 + bad_reg: 1733 + kfree(rd); 1734 + return -EINVAL; 1735 + } 1736 + 1606 1737 static struct genl_ops nl80211_ops[] = { 1607 1738 { 1608 1739 .cmd = NL80211_CMD_GET_WIPHY, ··· 1872 1733 { 1873 1734 .cmd = NL80211_CMD_SET_BSS, 1874 1735 .doit = nl80211_set_bss, 1736 + .policy = nl80211_policy, 1737 + .flags = GENL_ADMIN_PERM, 1738 + }, 1739 + { 1740 + .cmd = NL80211_CMD_SET_REG, 1741 + .doit = nl80211_set_reg, 1742 + .policy = nl80211_policy, 1743 + .flags = GENL_ADMIN_PERM, 1744 + }, 1745 + { 1746 + .cmd = NL80211_CMD_REQ_SET_REG, 1747 + .doit = nl80211_req_set_reg, 1875 1748 .policy = nl80211_policy, 1876 1749 .flags = GENL_ADMIN_PERM, 1877 1750 },
+704 -125
net/wireless/reg.c
··· 2 2 * Copyright 2002-2005, Instant802 Networks, Inc. 3 3 * Copyright 2005-2006, Devicescape Software, Inc. 4 4 * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> 5 + * Copyright 2008 Luis R. Rodriguez <lrodriguz@atheros.com> 5 6 * 6 7 * This program is free software; you can redistribute it and/or modify 7 8 * it under the terms of the GNU General Public License version 2 as 8 9 * published by the Free Software Foundation. 9 10 */ 10 11 11 - /* 12 - * This regulatory domain control implementation is highly incomplete, it 13 - * only exists for the purpose of not regressing mac80211. 14 - * 15 - * For now, drivers can restrict the set of allowed channels by either 16 - * not registering those channels or setting the IEEE80211_CHAN_DISABLED 17 - * flag; that flag will only be *set* by this code, never *cleared. 12 + /** 13 + * DOC: Wireless regulatory infrastructure 18 14 * 19 15 * The usual implementation is for a driver to read a device EEPROM to 20 16 * determine which regulatory domain it should be operating under, then 21 17 * looking up the allowable channels in a driver-local table and finally 22 18 * registering those channels in the wiphy structure. 23 19 * 24 - * Alternatively, drivers that trust the regulatory domain control here 25 - * will register a complete set of capabilities and the control code 26 - * will restrict the set by setting the IEEE80211_CHAN_* flags. 20 + * Another set of compliance enforcement is for drivers to use their 21 + * own compliance limits which can be stored on the EEPROM. The host 22 + * driver or firmware may ensure these are used. 23 + * 24 + * In addition to all this we provide an extra layer of regulatory 25 + * conformance. For drivers which do not have any regulatory 26 + * information CRDA provides the complete regulatory solution. 27 + * For others it provides a community effort on further restrictions 28 + * to enhance compliance. 29 + * 30 + * Note: When number of rules --> infinity we will not be able to 31 + * index on alpha2 any more, instead we'll probably have to 32 + * rely on some SHA1 checksum of the regdomain for example. 33 + * 27 34 */ 28 35 #include <linux/kernel.h> 36 + #include <linux/list.h> 37 + #include <linux/random.h> 38 + #include <linux/nl80211.h> 39 + #include <linux/platform_device.h> 29 40 #include <net/wireless.h> 41 + #include <net/cfg80211.h> 30 42 #include "core.h" 43 + #include "reg.h" 31 44 32 - static char *ieee80211_regdom = "US"; 33 - module_param(ieee80211_regdom, charp, 0444); 34 - MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); 45 + /* To trigger userspace events */ 46 + static struct platform_device *reg_pdev; 35 47 36 - struct ieee80211_channel_range { 37 - short start_freq; 38 - short end_freq; 39 - int max_power; 40 - int max_antenna_gain; 41 - u32 flags; 48 + /* Keep the ordering from large to small */ 49 + static u32 supported_bandwidths[] = { 50 + MHZ_TO_KHZ(40), 51 + MHZ_TO_KHZ(20), 42 52 }; 43 53 44 - struct ieee80211_regdomain { 45 - const char *code; 46 - const struct ieee80211_channel_range *ranges; 47 - int n_ranges; 48 - }; 49 - 50 - #define RANGE_PWR(_start, _end, _pwr, _ag, _flags) \ 51 - { _start, _end, _pwr, _ag, _flags } 52 - 53 - 54 - /* 55 - * Ideally, in the future, these definitions will be loaded from a 56 - * userspace table via some daemon. 57 - */ 58 - static const struct ieee80211_channel_range ieee80211_US_channels[] = { 59 - /* IEEE 802.11b/g, channels 1..11 */ 60 - RANGE_PWR(2412, 2462, 27, 6, 0), 61 - /* IEEE 802.11a, channel 36*/ 62 - RANGE_PWR(5180, 5180, 23, 6, 0), 63 - /* IEEE 802.11a, channel 40*/ 64 - RANGE_PWR(5200, 5200, 23, 6, 0), 65 - /* IEEE 802.11a, channel 44*/ 66 - RANGE_PWR(5220, 5220, 23, 6, 0), 67 - /* IEEE 802.11a, channels 48..64 */ 68 - RANGE_PWR(5240, 5320, 23, 6, 0), 69 - /* IEEE 802.11a, channels 149..165, outdoor */ 70 - RANGE_PWR(5745, 5825, 30, 6, 0), 71 - }; 72 - 73 - static const struct ieee80211_channel_range ieee80211_JP_channels[] = { 74 - /* IEEE 802.11b/g, channels 1..14 */ 75 - RANGE_PWR(2412, 2484, 20, 6, 0), 76 - /* IEEE 802.11a, channels 34..48 */ 77 - RANGE_PWR(5170, 5240, 20, 6, IEEE80211_CHAN_PASSIVE_SCAN), 78 - /* IEEE 802.11a, channels 52..64 */ 79 - RANGE_PWR(5260, 5320, 20, 6, IEEE80211_CHAN_NO_IBSS | 80 - IEEE80211_CHAN_RADAR), 81 - }; 82 - 83 - static const struct ieee80211_channel_range ieee80211_EU_channels[] = { 84 - /* IEEE 802.11b/g, channels 1..13 */ 85 - RANGE_PWR(2412, 2472, 20, 6, 0), 86 - /* IEEE 802.11a, channel 36*/ 87 - RANGE_PWR(5180, 5180, 23, 6, IEEE80211_CHAN_PASSIVE_SCAN), 88 - /* IEEE 802.11a, channel 40*/ 89 - RANGE_PWR(5200, 5200, 23, 6, IEEE80211_CHAN_PASSIVE_SCAN), 90 - /* IEEE 802.11a, channel 44*/ 91 - RANGE_PWR(5220, 5220, 23, 6, IEEE80211_CHAN_PASSIVE_SCAN), 92 - /* IEEE 802.11a, channels 48..64 */ 93 - RANGE_PWR(5240, 5320, 23, 6, IEEE80211_CHAN_NO_IBSS | 94 - IEEE80211_CHAN_RADAR), 95 - /* IEEE 802.11a, channels 100..140 */ 96 - RANGE_PWR(5500, 5700, 30, 6, IEEE80211_CHAN_NO_IBSS | 97 - IEEE80211_CHAN_RADAR), 98 - }; 99 - 100 - #define REGDOM(_code) \ 101 - { \ 102 - .code = __stringify(_code), \ 103 - .ranges = ieee80211_ ##_code## _channels, \ 104 - .n_ranges = ARRAY_SIZE(ieee80211_ ##_code## _channels), \ 105 - } 106 - 107 - static const struct ieee80211_regdomain ieee80211_regdoms[] = { 108 - REGDOM(US), 109 - REGDOM(JP), 110 - REGDOM(EU), 111 - }; 112 - 113 - 114 - static const struct ieee80211_regdomain *get_regdom(void) 54 + bool is_world_regdom(char *alpha2) 115 55 { 116 - static const struct ieee80211_channel_range 117 - ieee80211_world_channels[] = { 118 - /* IEEE 802.11b/g, channels 1..11 */ 119 - RANGE_PWR(2412, 2462, 27, 6, 0), 120 - }; 121 - static const struct ieee80211_regdomain regdom_world = REGDOM(world); 122 - int i; 123 - 124 - for (i = 0; i < ARRAY_SIZE(ieee80211_regdoms); i++) 125 - if (strcmp(ieee80211_regdom, ieee80211_regdoms[i].code) == 0) 126 - return &ieee80211_regdoms[i]; 127 - 128 - return &regdom_world; 56 + if (!alpha2) 57 + return false; 58 + if (alpha2[0] == '0' && alpha2[1] == '0') 59 + return true; 60 + return false; 129 61 } 130 62 63 + static bool is_alpha2_set(char *alpha2) 64 + { 65 + if (!alpha2) 66 + return false; 67 + if (alpha2[0] != 0 && alpha2[1] != 0) 68 + return true; 69 + return false; 70 + } 131 71 132 - static void handle_channel(struct ieee80211_channel *chan, 133 - const struct ieee80211_regdomain *rd) 72 + static bool is_alpha_upper(char letter) 73 + { 74 + /* ASCII A - Z */ 75 + if (letter >= 65 && letter <= 90) 76 + return true; 77 + return false; 78 + } 79 + 80 + static bool is_unknown_alpha2(char *alpha2) 81 + { 82 + if (!alpha2) 83 + return false; 84 + /* Special case where regulatory domain was built by driver 85 + * but a specific alpha2 cannot be determined */ 86 + if (alpha2[0] == '9' && alpha2[1] == '9') 87 + return true; 88 + return false; 89 + } 90 + 91 + static bool is_an_alpha2(char *alpha2) 92 + { 93 + if (!alpha2) 94 + return false; 95 + if (is_alpha_upper(alpha2[0]) && is_alpha_upper(alpha2[1])) 96 + return true; 97 + return false; 98 + } 99 + 100 + static bool alpha2_equal(char *alpha2_x, char *alpha2_y) 101 + { 102 + if (!alpha2_x || !alpha2_y) 103 + return false; 104 + if (alpha2_x[0] == alpha2_y[0] && 105 + alpha2_x[1] == alpha2_y[1]) 106 + return true; 107 + return false; 108 + } 109 + 110 + static bool regdom_changed(char *alpha2) 111 + { 112 + if (!cfg80211_regdomain) 113 + return true; 114 + if (alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) 115 + return false; 116 + return true; 117 + } 118 + 119 + /* This lets us keep regulatory code which is updated on a regulatory 120 + * basis in userspace. */ 121 + static int call_crda(const char *alpha2) 122 + { 123 + char country_env[9 + 2] = "COUNTRY="; 124 + char *envp[] = { 125 + country_env, 126 + NULL 127 + }; 128 + 129 + if (!is_world_regdom((char *) alpha2)) 130 + printk(KERN_INFO "cfg80211: Calling CRDA for country: %c%c\n", 131 + alpha2[0], alpha2[1]); 132 + else 133 + #ifdef CONFIG_WIRELESS_OLD_REGULATORY 134 + return -EINVAL; 135 + #else 136 + printk(KERN_INFO "cfg80211: Calling CRDA to update world " 137 + "regulatory domain\n"); 138 + #endif 139 + 140 + country_env[8] = alpha2[0]; 141 + country_env[9] = alpha2[1]; 142 + 143 + return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, envp); 144 + } 145 + 146 + /* This has the logic which determines when a new request 147 + * should be ignored. */ 148 + static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, 149 + char *alpha2, struct ieee80211_regdomain *rd) 150 + { 151 + struct regulatory_request *last_request = NULL; 152 + 153 + /* All initial requests are respected */ 154 + if (list_empty(&regulatory_requests)) 155 + return 0; 156 + 157 + last_request = list_first_entry(&regulatory_requests, 158 + struct regulatory_request, list); 159 + 160 + switch (set_by) { 161 + case REGDOM_SET_BY_INIT: 162 + return -EINVAL; 163 + case REGDOM_SET_BY_CORE: 164 + /* Always respect new wireless core hints, should only 165 + * come in for updating the world regulatory domain at init 166 + * anyway */ 167 + return 0; 168 + case REGDOM_SET_BY_COUNTRY_IE: 169 + if (last_request->initiator == set_by) { 170 + if (last_request->wiphy != wiphy) { 171 + /* Two cards with two APs claiming different 172 + * different Country IE alpha2s! 173 + * You're special!! */ 174 + if (!alpha2_equal(last_request->alpha2, 175 + cfg80211_regdomain->alpha2)) { 176 + /* XXX: Deal with conflict, consider 177 + * building a new one out of the 178 + * intersection */ 179 + WARN_ON(1); 180 + return -EOPNOTSUPP; 181 + } 182 + return -EALREADY; 183 + } 184 + /* Two consecutive Country IE hints on the same wiphy */ 185 + if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) 186 + return 0; 187 + return -EALREADY; 188 + } 189 + if (WARN_ON(!is_alpha2_set(alpha2) || !is_an_alpha2(alpha2)), 190 + "Invalid Country IE regulatory hint passed " 191 + "to the wireless core\n") 192 + return -EINVAL; 193 + /* We ignore Country IE hints for now, as we haven't yet 194 + * added the dot11MultiDomainCapabilityEnabled flag 195 + * for wiphys */ 196 + return 1; 197 + case REGDOM_SET_BY_DRIVER: 198 + BUG_ON(!wiphy); 199 + if (last_request->initiator == set_by) { 200 + /* Two separate drivers hinting different things, 201 + * this is possible if you have two devices present 202 + * on a system with different EEPROM regulatory 203 + * readings. XXX: Do intersection, we support only 204 + * the first regulatory hint for now */ 205 + if (last_request->wiphy != wiphy) 206 + return -EALREADY; 207 + if (rd) 208 + return -EALREADY; 209 + /* Driver should not be trying to hint different 210 + * regulatory domains! */ 211 + BUG_ON(!alpha2_equal(alpha2, 212 + cfg80211_regdomain->alpha2)); 213 + return -EALREADY; 214 + } 215 + if (last_request->initiator == REGDOM_SET_BY_CORE) 216 + return 0; 217 + /* XXX: Handle intersection, and add the 218 + * dot11MultiDomainCapabilityEnabled flag to wiphy. For now 219 + * we assume the driver has this set to false, following the 220 + * 802.11d dot11MultiDomainCapabilityEnabled documentation */ 221 + if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) 222 + return 0; 223 + return 0; 224 + case REGDOM_SET_BY_USER: 225 + if (last_request->initiator == set_by || 226 + last_request->initiator == REGDOM_SET_BY_CORE) 227 + return 0; 228 + /* Drivers can use their wiphy's reg_notifier() 229 + * to override any information */ 230 + if (last_request->initiator == REGDOM_SET_BY_DRIVER) 231 + return 0; 232 + /* XXX: Handle intersection */ 233 + if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) 234 + return -EOPNOTSUPP; 235 + return 0; 236 + default: 237 + return -EINVAL; 238 + } 239 + } 240 + 241 + static bool __reg_is_valid_request(char *alpha2, 242 + struct regulatory_request **request) 243 + { 244 + struct regulatory_request *req; 245 + if (list_empty(&regulatory_requests)) 246 + return false; 247 + list_for_each_entry(req, &regulatory_requests, list) { 248 + if (alpha2_equal(req->alpha2, alpha2)) { 249 + *request = req; 250 + return true; 251 + } 252 + } 253 + return false; 254 + } 255 + 256 + /* Used by nl80211 before kmalloc'ing our regulatory domain */ 257 + bool reg_is_valid_request(char *alpha2) 258 + { 259 + struct regulatory_request *request = NULL; 260 + return __reg_is_valid_request(alpha2, &request); 261 + } 262 + 263 + /* Sanity check on a regulatory rule */ 264 + static bool is_valid_reg_rule(struct ieee80211_reg_rule *rule) 265 + { 266 + struct ieee80211_freq_range *freq_range = &rule->freq_range; 267 + u32 freq_diff; 268 + 269 + if (freq_range->start_freq_khz == 0 || freq_range->end_freq_khz == 0) 270 + return false; 271 + 272 + if (freq_range->start_freq_khz > freq_range->end_freq_khz) 273 + return false; 274 + 275 + freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; 276 + 277 + if (freq_range->max_bandwidth_khz > freq_diff) 278 + return false; 279 + 280 + return true; 281 + } 282 + 283 + static bool is_valid_rd(struct ieee80211_regdomain *rd) 284 + { 285 + struct ieee80211_reg_rule *reg_rule = NULL; 286 + unsigned int i; 287 + 288 + if (!rd->n_reg_rules) 289 + return false; 290 + 291 + for (i = 0; i < rd->n_reg_rules; i++) { 292 + reg_rule = &rd->reg_rules[i]; 293 + if (!is_valid_reg_rule(reg_rule)) 294 + return false; 295 + } 296 + 297 + return true; 298 + } 299 + 300 + /* Returns value in KHz */ 301 + static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range, 302 + u32 freq) 303 + { 304 + unsigned int i; 305 + for (i = 0; i < ARRAY_SIZE(supported_bandwidths); i++) { 306 + u32 start_freq_khz = freq - supported_bandwidths[i]/2; 307 + u32 end_freq_khz = freq + supported_bandwidths[i]/2; 308 + if (start_freq_khz >= freq_range->start_freq_khz && 309 + end_freq_khz <= freq_range->end_freq_khz) 310 + return supported_bandwidths[i]; 311 + } 312 + return 0; 313 + } 314 + 315 + /* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may 316 + * want to just have the channel structure use these */ 317 + static u32 map_regdom_flags(u32 rd_flags) 318 + { 319 + u32 channel_flags = 0; 320 + if (rd_flags & NL80211_RRF_PASSIVE_SCAN) 321 + channel_flags |= IEEE80211_CHAN_PASSIVE_SCAN; 322 + if (rd_flags & NL80211_RRF_NO_IBSS) 323 + channel_flags |= IEEE80211_CHAN_NO_IBSS; 324 + if (rd_flags & NL80211_RRF_DFS) 325 + channel_flags |= IEEE80211_CHAN_RADAR; 326 + return channel_flags; 327 + } 328 + 329 + /** 330 + * freq_reg_info - get regulatory information for the given frequency 331 + * @center_freq: Frequency in KHz for which we want regulatory information for 332 + * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one 333 + * you can set this to 0. If this frequency is allowed we then set 334 + * this value to the maximum allowed bandwidth. 335 + * @reg_rule: the regulatory rule which we have for this frequency 336 + * 337 + * Use this function to get the regulatory rule for a specific frequency. 338 + */ 339 + static int freq_reg_info(u32 center_freq, u32 *bandwidth, 340 + const struct ieee80211_reg_rule **reg_rule) 134 341 { 135 342 int i; 136 - u32 flags = chan->orig_flags; 137 - const struct ieee80211_channel_range *rg = NULL; 343 + u32 max_bandwidth = 0; 138 344 139 - for (i = 0; i < rd->n_ranges; i++) { 140 - if (rd->ranges[i].start_freq <= chan->center_freq && 141 - chan->center_freq <= rd->ranges[i].end_freq) { 142 - rg = &rd->ranges[i]; 345 + if (!cfg80211_regdomain) 346 + return -EINVAL; 347 + 348 + for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) { 349 + const struct ieee80211_reg_rule *rr; 350 + const struct ieee80211_freq_range *fr = NULL; 351 + const struct ieee80211_power_rule *pr = NULL; 352 + 353 + rr = &cfg80211_regdomain->reg_rules[i]; 354 + fr = &rr->freq_range; 355 + pr = &rr->power_rule; 356 + max_bandwidth = freq_max_bandwidth(fr, center_freq); 357 + if (max_bandwidth && *bandwidth <= max_bandwidth) { 358 + *reg_rule = rr; 359 + *bandwidth = max_bandwidth; 143 360 break; 144 361 } 145 362 } 146 363 147 - if (!rg) { 148 - /* not found */ 364 + return !max_bandwidth; 365 + } 366 + 367 + static void handle_channel(struct ieee80211_channel *chan) 368 + { 369 + int r; 370 + u32 flags = chan->orig_flags; 371 + u32 max_bandwidth = 0; 372 + const struct ieee80211_reg_rule *reg_rule = NULL; 373 + const struct ieee80211_power_rule *power_rule = NULL; 374 + 375 + r = freq_reg_info(MHZ_TO_KHZ(chan->center_freq), 376 + &max_bandwidth, &reg_rule); 377 + 378 + if (r) { 149 379 flags |= IEEE80211_CHAN_DISABLED; 150 380 chan->flags = flags; 151 381 return; 152 382 } 153 383 154 - chan->flags = flags; 384 + power_rule = &reg_rule->power_rule; 385 + 386 + chan->flags = flags | map_regdom_flags(reg_rule->flags); 155 387 chan->max_antenna_gain = min(chan->orig_mag, 156 - rg->max_antenna_gain); 388 + (int) MBI_TO_DBI(power_rule->max_antenna_gain)); 389 + chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); 157 390 if (chan->orig_mpwr) 158 - chan->max_power = min(chan->orig_mpwr, rg->max_power); 391 + chan->max_power = min(chan->orig_mpwr, 392 + (int) MBM_TO_DBM(power_rule->max_eirp)); 159 393 else 160 - chan->max_power = rg->max_power; 394 + chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); 161 395 } 162 396 163 - static void handle_band(struct ieee80211_supported_band *sband, 164 - const struct ieee80211_regdomain *rd) 397 + static void handle_band(struct ieee80211_supported_band *sband) 165 398 { 166 399 int i; 167 400 168 401 for (i = 0; i < sband->n_channels; i++) 169 - handle_channel(&sband->channels[i], rd); 402 + handle_channel(&sband->channels[i]); 170 403 } 171 404 172 - void wiphy_update_regulatory(struct wiphy *wiphy) 405 + static void update_all_wiphy_regulatory(enum reg_set_by setby) 406 + { 407 + struct cfg80211_registered_device *drv; 408 + 409 + list_for_each_entry(drv, &cfg80211_drv_list, list) 410 + wiphy_update_regulatory(&drv->wiphy, setby); 411 + } 412 + 413 + void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) 173 414 { 174 415 enum ieee80211_band band; 175 - const struct ieee80211_regdomain *rd = get_regdom(); 176 - 177 - for (band = 0; band < IEEE80211_NUM_BANDS; band++) 416 + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 178 417 if (wiphy->bands[band]) 179 - handle_band(wiphy->bands[band], rd); 418 + handle_band(wiphy->bands[band]); 419 + if (wiphy->reg_notifier) 420 + wiphy->reg_notifier(wiphy, setby); 421 + } 422 + } 423 + 424 + /* Caller must hold &cfg80211_drv_mutex */ 425 + int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, 426 + const char *alpha2, struct ieee80211_regdomain *rd) 427 + { 428 + struct regulatory_request *request; 429 + char *rd_alpha2; 430 + int r = 0; 431 + 432 + r = ignore_request(wiphy, set_by, (char *) alpha2, rd); 433 + if (r) 434 + return r; 435 + 436 + if (rd) 437 + rd_alpha2 = rd->alpha2; 438 + else 439 + rd_alpha2 = (char *) alpha2; 440 + 441 + switch (set_by) { 442 + case REGDOM_SET_BY_CORE: 443 + case REGDOM_SET_BY_COUNTRY_IE: 444 + case REGDOM_SET_BY_DRIVER: 445 + case REGDOM_SET_BY_USER: 446 + request = kzalloc(sizeof(struct regulatory_request), 447 + GFP_KERNEL); 448 + if (!request) 449 + return -ENOMEM; 450 + 451 + request->alpha2[0] = rd_alpha2[0]; 452 + request->alpha2[1] = rd_alpha2[1]; 453 + request->initiator = set_by; 454 + request->wiphy = wiphy; 455 + 456 + list_add_tail(&request->list, &regulatory_requests); 457 + if (rd) 458 + break; 459 + r = call_crda(alpha2); 460 + #ifndef CONFIG_WIRELESS_OLD_REGULATORY 461 + if (r) 462 + printk(KERN_ERR "cfg80211: Failed calling CRDA\n"); 463 + #endif 464 + break; 465 + default: 466 + r = -ENOTSUPP; 467 + break; 468 + } 469 + 470 + return r; 471 + } 472 + 473 + /* If rd is not NULL and if this call fails the caller must free it */ 474 + int regulatory_hint(struct wiphy *wiphy, const char *alpha2, 475 + struct ieee80211_regdomain *rd) 476 + { 477 + int r; 478 + BUG_ON(!rd && !alpha2); 479 + 480 + mutex_lock(&cfg80211_drv_mutex); 481 + 482 + r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, rd); 483 + if (r || !rd) 484 + goto unlock_and_exit; 485 + 486 + /* If the driver passed a regulatory domain we skipped asking 487 + * userspace for one so we can now go ahead and set it */ 488 + r = set_regdom(rd); 489 + 490 + unlock_and_exit: 491 + mutex_unlock(&cfg80211_drv_mutex); 492 + return r; 493 + } 494 + EXPORT_SYMBOL(regulatory_hint); 495 + 496 + 497 + static void print_rd_rules(struct ieee80211_regdomain *rd) 498 + { 499 + unsigned int i; 500 + struct ieee80211_reg_rule *reg_rule = NULL; 501 + struct ieee80211_freq_range *freq_range = NULL; 502 + struct ieee80211_power_rule *power_rule = NULL; 503 + 504 + printk(KERN_INFO "\t(start_freq - end_freq @ bandwidth), " 505 + "(max_antenna_gain, max_eirp)\n"); 506 + 507 + for (i = 0; i < rd->n_reg_rules; i++) { 508 + reg_rule = &rd->reg_rules[i]; 509 + freq_range = &reg_rule->freq_range; 510 + power_rule = &reg_rule->power_rule; 511 + 512 + /* There may not be documentation for max antenna gain 513 + * in certain regions */ 514 + if (power_rule->max_antenna_gain) 515 + printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), " 516 + "(%d mBi, %d mBm)\n", 517 + freq_range->start_freq_khz, 518 + freq_range->end_freq_khz, 519 + freq_range->max_bandwidth_khz, 520 + power_rule->max_antenna_gain, 521 + power_rule->max_eirp); 522 + else 523 + printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), " 524 + "(N/A, %d mBm)\n", 525 + freq_range->start_freq_khz, 526 + freq_range->end_freq_khz, 527 + freq_range->max_bandwidth_khz, 528 + power_rule->max_eirp); 529 + } 530 + } 531 + 532 + static void print_regdomain(struct ieee80211_regdomain *rd) 533 + { 534 + 535 + if (is_world_regdom(rd->alpha2)) 536 + printk(KERN_INFO "cfg80211: World regulatory " 537 + "domain updated:\n"); 538 + else { 539 + if (is_unknown_alpha2(rd->alpha2)) 540 + printk(KERN_INFO "cfg80211: Regulatory domain " 541 + "changed to driver built-in settings " 542 + "(unknown country)\n"); 543 + else 544 + printk(KERN_INFO "cfg80211: Regulatory domain " 545 + "changed to country: %c%c\n", 546 + rd->alpha2[0], rd->alpha2[1]); 547 + } 548 + print_rd_rules(rd); 549 + } 550 + 551 + void print_regdomain_info(struct ieee80211_regdomain *rd) 552 + { 553 + printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n", 554 + rd->alpha2[0], rd->alpha2[1]); 555 + print_rd_rules(rd); 556 + } 557 + 558 + #ifdef CONFIG_WIRELESS_OLD_REGULATORY 559 + 560 + static bool is_old_static_regdom(struct ieee80211_regdomain *rd) 561 + { 562 + if (rd == &us_regdom || rd == &jp_regdom || rd == &eu_regdom) 563 + return true; 564 + return false; 565 + } 566 + 567 + /* The old crap never deals with a world regulatory domain, it only 568 + * deals with the static regulatory domain passed and if possible 569 + * an updated "US" or "JP" regulatory domain. We do however store the 570 + * old static regulatory domain in cfg80211_world_regdom for convenience 571 + * of use here */ 572 + static void reset_regdomains_static(void) 573 + { 574 + if (!is_old_static_regdom(cfg80211_regdomain)) 575 + kfree(cfg80211_regdomain); 576 + /* This is setting the regdom to the old static regdom */ 577 + cfg80211_regdomain = 578 + (struct ieee80211_regdomain *) cfg80211_world_regdom; 579 + } 580 + #else 581 + static void reset_regdomains(void) 582 + { 583 + if (cfg80211_world_regdom && cfg80211_world_regdom != &world_regdom) { 584 + if (cfg80211_world_regdom == cfg80211_regdomain) { 585 + kfree(cfg80211_regdomain); 586 + } else { 587 + kfree(cfg80211_world_regdom); 588 + kfree(cfg80211_regdomain); 589 + } 590 + } else if (cfg80211_regdomain && cfg80211_regdomain != &world_regdom) 591 + kfree(cfg80211_regdomain); 592 + 593 + cfg80211_world_regdom = (struct ieee80211_regdomain *) &world_regdom; 594 + cfg80211_regdomain = NULL; 595 + } 596 + 597 + /* Dynamic world regulatory domain requested by the wireless 598 + * core upon initialization */ 599 + static void update_world_regdomain(struct ieee80211_regdomain *rd) 600 + { 601 + BUG_ON(list_empty(&regulatory_requests)); 602 + 603 + reset_regdomains(); 604 + 605 + cfg80211_world_regdom = rd; 606 + cfg80211_regdomain = rd; 607 + } 608 + #endif 609 + 610 + static int __set_regdom(struct ieee80211_regdomain *rd) 611 + { 612 + struct regulatory_request *request = NULL; 613 + 614 + /* Some basic sanity checks first */ 615 + 616 + #ifdef CONFIG_WIRELESS_OLD_REGULATORY 617 + /* We ignore the world regdom with the old static regdomains setup 618 + * as there is no point to it with satic regulatory definitions :( 619 + * Don't worry this shit will be removed soon... */ 620 + if (is_world_regdom(rd->alpha2)) 621 + return -EINVAL; 622 + #else 623 + if (is_world_regdom(rd->alpha2)) { 624 + if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request))) 625 + return -EINVAL; 626 + update_world_regdomain(rd); 627 + return 0; 628 + } 629 + #endif 630 + 631 + if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) && 632 + !is_unknown_alpha2(rd->alpha2)) 633 + return -EINVAL; 634 + 635 + if (list_empty(&regulatory_requests)) 636 + return -EINVAL; 637 + 638 + #ifdef CONFIG_WIRELESS_OLD_REGULATORY 639 + /* Static "US" and "JP" will be overridden, but just once */ 640 + if (!is_old_static_regdom(cfg80211_regdomain) && 641 + !regdom_changed(rd->alpha2)) 642 + return -EINVAL; 643 + #else 644 + if (!regdom_changed(rd->alpha2)) 645 + return -EINVAL; 646 + #endif 647 + 648 + /* Now lets set the regulatory domain, update all driver channels 649 + * and finally inform them of what we have done, in case they want 650 + * to review or adjust their own settings based on their own 651 + * internal EEPROM data */ 652 + 653 + if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request))) 654 + return -EINVAL; 655 + 656 + #ifdef CONFIG_WIRELESS_OLD_REGULATORY 657 + reset_regdomains_static(); 658 + #else 659 + reset_regdomains(); 660 + #endif 661 + 662 + /* Country IE parsing coming soon */ 663 + switch (request->initiator) { 664 + case REGDOM_SET_BY_CORE: 665 + case REGDOM_SET_BY_DRIVER: 666 + case REGDOM_SET_BY_USER: 667 + if (!is_valid_rd(rd)) { 668 + printk(KERN_ERR "cfg80211: Invalid " 669 + "regulatory domain detected:\n"); 670 + print_regdomain_info(rd); 671 + return -EINVAL; 672 + } 673 + break; 674 + case REGDOM_SET_BY_COUNTRY_IE: /* Not yet */ 675 + WARN_ON(1); 676 + default: 677 + return -EOPNOTSUPP; 678 + } 679 + 680 + /* Tada! */ 681 + cfg80211_regdomain = rd; 682 + request->granted = 1; 683 + 684 + return 0; 685 + } 686 + 687 + 688 + /* Use this call to set the current regulatory domain. Conflicts with 689 + * multiple drivers can be ironed out later. Caller must've already 690 + * kmalloc'd the rd structure. If this calls fails you should kfree() 691 + * the passed rd. Caller must hold cfg80211_drv_mutex */ 692 + int set_regdom(struct ieee80211_regdomain *rd) 693 + { 694 + struct regulatory_request *this_request = NULL, *prev_request = NULL; 695 + int r; 696 + 697 + if (!list_empty(&regulatory_requests)) 698 + prev_request = list_first_entry(&regulatory_requests, 699 + struct regulatory_request, list); 700 + 701 + /* Note that this doesn't update the wiphys, this is done below */ 702 + r = __set_regdom(rd); 703 + if (r) 704 + return r; 705 + 706 + BUG_ON((!__reg_is_valid_request(rd->alpha2, &this_request))); 707 + 708 + /* The initial standard core update of the world regulatory domain, no 709 + * need to keep that request info around if it didn't fail. */ 710 + if (is_world_regdom(rd->alpha2) && 711 + this_request->initiator == REGDOM_SET_BY_CORE && 712 + this_request->granted) { 713 + list_del(&this_request->list); 714 + kfree(this_request); 715 + this_request = NULL; 716 + } 717 + 718 + /* Remove old requests, we only leave behind the last one */ 719 + if (prev_request) { 720 + list_del(&prev_request->list); 721 + kfree(prev_request); 722 + prev_request = NULL; 723 + } 724 + 725 + /* This would make this whole thing pointless */ 726 + BUG_ON(rd != cfg80211_regdomain); 727 + 728 + /* update all wiphys now with the new established regulatory domain */ 729 + update_all_wiphy_regulatory(this_request->initiator); 730 + 731 + print_regdomain(rd); 732 + 733 + return r; 734 + } 735 + 736 + int regulatory_init(void) 737 + { 738 + reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0); 739 + if (IS_ERR(reg_pdev)) 740 + return PTR_ERR(reg_pdev); 741 + return 0; 742 + } 743 + 744 + void regulatory_exit(void) 745 + { 746 + struct regulatory_request *req, *req_tmp; 747 + mutex_lock(&cfg80211_drv_mutex); 748 + #ifdef CONFIG_WIRELESS_OLD_REGULATORY 749 + reset_regdomains_static(); 750 + #else 751 + reset_regdomains(); 752 + #endif 753 + list_for_each_entry_safe(req, req_tmp, &regulatory_requests, list) { 754 + list_del(&req->list); 755 + kfree(req); 756 + } 757 + platform_device_unregister(reg_pdev); 758 + mutex_unlock(&cfg80211_drv_mutex); 180 759 }
+44
net/wireless/reg.h
··· 1 + #ifndef __NET_WIRELESS_REG_H 2 + #define __NET_WIRELESS_REG_H 3 + 4 + extern const struct ieee80211_regdomain world_regdom; 5 + #ifdef CONFIG_WIRELESS_OLD_REGULATORY 6 + extern const struct ieee80211_regdomain us_regdom; 7 + extern const struct ieee80211_regdomain jp_regdom; 8 + extern const struct ieee80211_regdomain eu_regdom; 9 + #endif 10 + 11 + extern struct ieee80211_regdomain *cfg80211_regdomain; 12 + extern struct ieee80211_regdomain *cfg80211_world_regdom; 13 + extern struct list_head regulatory_requests; 14 + 15 + struct regdom_last_setby { 16 + struct wiphy *wiphy; 17 + u8 initiator; 18 + }; 19 + 20 + /* wiphy is set if this request's initiator is REGDOM_SET_BY_DRIVER */ 21 + struct regulatory_request { 22 + struct list_head list; 23 + struct wiphy *wiphy; 24 + int granted; 25 + enum reg_set_by initiator; 26 + char alpha2[2]; 27 + }; 28 + 29 + bool is_world_regdom(char *alpha2); 30 + bool reg_is_valid_request(char *alpha2); 31 + 32 + int set_regdom(struct ieee80211_regdomain *rd); 33 + int __regulatory_hint_alpha2(struct wiphy *wiphy, enum reg_set_by set_by, 34 + const char *alpha2); 35 + 36 + int regulatory_init(void); 37 + void regulatory_exit(void); 38 + 39 + void print_regdomain_info(struct ieee80211_regdomain *); 40 + 41 + /* If a char is A-Z */ 42 + #define IS_ALPHA(letter) (letter >= 65 && letter <= 90) 43 + 44 + #endif /* __NET_WIRELESS_REG_H */