iPXE
ath_regd.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008-2009 Atheros Communications Inc.
3  *
4  * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
5  * Original from Linux kernel 3.0.1
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "regd.h"
21 #include "regd_common.h"
22 
23 /*
24  * This is a set of common rules used by our world regulatory domains.
25  * We have 12 world regulatory domains. To save space we consolidate
26  * the regulatory domains in 5 structures by frequency and change
27  * the flags on our reg_notifier() on a case by case basis.
28  */
29 
30 /* Only these channels all allow active scan on all world regulatory domains */
31 #define ATH9K_2GHZ_CH01_11 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
32 
33 /* We enable active scan on these a case by case basis by regulatory domain */
34 #define ATH9K_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\
35  NL80211_RRF_PASSIVE_SCAN)
36 #define ATH9K_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\
37  NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)
38 
39 /* We allow IBSS on these on a case by case basis by regulatory domain */
40 #define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 40, 0, 30,\
41  NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
42 #define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 40, 0, 30,\
43  NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
44 #define ATH9K_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 40, 0, 30,\
45  NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
46 
47 #define ATH9K_2GHZ_ALL ATH9K_2GHZ_CH01_11, \
48  ATH9K_2GHZ_CH12_13, \
49  ATH9K_2GHZ_CH14
50 
51 #define ATH9K_5GHZ_ALL ATH9K_5GHZ_5150_5350, \
52  ATH9K_5GHZ_5470_5850
53 
54 /* This one skips what we call "mid band" */
55 #define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \
56  ATH9K_5GHZ_5725_5850
57 
58 ///* Can be used for:
59 // * 0x60, 0x61, 0x62 */
60 //static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = {
61 // .n_reg_rules = 5,
62 // .alpha2 = "99",
63 // .reg_rules = {
64 // ATH9K_2GHZ_ALL,
65 // ATH9K_5GHZ_ALL,
66 // }
67 //};
68 //
69 ///* Can be used by 0x63 and 0x65 */
70 //static const struct ieee80211_regdomain ath_world_regdom_63_65 = {
71 // .n_reg_rules = 4,
72 // .alpha2 = "99",
73 // .reg_rules = {
74 // ATH9K_2GHZ_CH01_11,
75 // ATH9K_2GHZ_CH12_13,
76 // ATH9K_5GHZ_NO_MIDBAND,
77 // }
78 //};
79 //
80 ///* Can be used by 0x64 only */
81 //static const struct ieee80211_regdomain ath_world_regdom_64 = {
82 // .n_reg_rules = 3,
83 // .alpha2 = "99",
84 // .reg_rules = {
85 // ATH9K_2GHZ_CH01_11,
86 // ATH9K_5GHZ_NO_MIDBAND,
87 // }
88 //};
89 //
90 ///* Can be used by 0x66 and 0x69 */
91 //static const struct ieee80211_regdomain ath_world_regdom_66_69 = {
92 // .n_reg_rules = 3,
93 // .alpha2 = "99",
94 // .reg_rules = {
95 // ATH9K_2GHZ_CH01_11,
96 // ATH9K_5GHZ_ALL,
97 // }
98 //};
99 //
100 ///* Can be used by 0x67, 0x68, 0x6A and 0x6C */
101 //static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = {
102 // .n_reg_rules = 4,
103 // .alpha2 = "99",
104 // .reg_rules = {
105 // ATH9K_2GHZ_CH01_11,
106 // ATH9K_2GHZ_CH12_13,
107 // ATH9K_5GHZ_ALL,
108 // }
109 //};
110 //
111 //static inline int is_wwr_sku(u16 regd)
112 //{
113 // return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) &&
114 // (((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||
115 // (regd == WORLD));
116 //}
117 //
118 //static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg)
119 //{
120 // return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG;
121 //}
122 //
123 //int ath_is_world_regd(struct ath_regulatory *reg)
124 //{
125 // return is_wwr_sku(ath_regd_get_eepromRD(reg));
126 //}
127 //
128 //static const struct ieee80211_regdomain *ath_default_world_regdomain(void)
129 //{
130 // /* this is the most restrictive */
131 // return &ath_world_regdom_64;
132 //}
133 //
134 //static const struct
135 //ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
136 //{
137 // switch (reg->regpair->regDmnEnum) {
138 // case 0x60:
139 // case 0x61:
140 // case 0x62:
141 // return &ath_world_regdom_60_61_62;
142 // case 0x63:
143 // case 0x65:
144 // return &ath_world_regdom_63_65;
145 // case 0x64:
146 // return &ath_world_regdom_64;
147 // case 0x66:
148 // case 0x69:
149 // return &ath_world_regdom_66_69;
150 // case 0x67:
151 // case 0x68:
152 // case 0x6A:
153 // case 0x6C:
154 // return &ath_world_regdom_67_68_6A_6C;
155 // default:
156 // WARN_ON(1);
157 // return ath_default_world_regdomain();
158 // }
159 //}
160 //
161 //int ath_is_49ghz_allowed(u16 regdomain)
162 //{
163 // /* possibly more */
164 // return regdomain == MKK9_MKKC;
165 //}
166 //
167 ///* Frequency is one where radar detection is required */
168 //static int ath_is_radar_freq(u16 center_freq)
169 //{
170 // return (center_freq >= 5260 && center_freq <= 5700);
171 //}
172 //
173 ///*
174 // * N.B: These exception rules do not apply radar freqs.
175 // *
176 // * - We enable adhoc (or beaconing) if allowed by 11d
177 // * - We enable active scan if the channel is allowed by 11d
178 // * - If no country IE has been processed and a we determine we have
179 // * received a beacon on a channel we can enable active scan and
180 // * adhoc (or beaconing).
181 // */
182 //static void
183 //ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
184 // enum nl80211_reg_initiator initiator)
185 //{
186 // int band;
187 // struct ieee80211_supported_band *sband;
188 // const struct ieee80211_reg_rule *reg_rule;
189 // struct net80211_channel *ch;
190 // unsigned int i;
191 // u32 bandwidth = 0;
192 // int r;
193 //
194 // for (band = 0; band < NET80211_NR_BANDS; band++) {
195 //
196 // if (!wiphy->bands[band])
197 // continue;
198 //
199 // sband = wiphy->bands[band];
200 //
201 // for (i = 0; i < sband->n_channels; i++) {
202 //
203 // ch = &sband->channels[i];
204 //
205 // if (ath_is_radar_freq(ch->center_freq) ||
206 // (ch->flags & IEEE80211_CHAN_RADAR))
207 // continue;
208 //
209 // if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
210 // r = freq_reg_info(wiphy,
211 // ch->center_freq,
212 // bandwidth,
213 // &reg_rule);
214 // if (r)
215 // continue;
216 // /*
217 // * If 11d had a rule for this channel ensure
218 // * we enable adhoc/beaconing if it allows us to
219 // * use it. Note that we would have disabled it
220 // * by applying our static world regdomain by
221 // * default during init, prior to calling our
222 // * regulatory_hint().
223 // */
224 // if (!(reg_rule->flags &
225 // NL80211_RRF_NO_IBSS))
226 // ch->flags &=
227 // ~IEEE80211_CHAN_NO_IBSS;
228 // if (!(reg_rule->flags &
229 // NL80211_RRF_PASSIVE_SCAN))
230 // ch->flags &=
231 // ~IEEE80211_CHAN_PASSIVE_SCAN;
232 // } else {
233 // if (ch->beacon_found)
234 // ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
235 // IEEE80211_CHAN_PASSIVE_SCAN);
236 // }
237 // }
238 // }
239 //
240 //}
241 //
242 ///* Allows active scan scan on Ch 12 and 13 */
243 //static void
244 //ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
245 // enum nl80211_reg_initiator initiator)
246 //{
247 // struct ieee80211_supported_band *sband;
248 // struct net80211_channel *ch;
249 // const struct ieee80211_reg_rule *reg_rule;
250 // u32 bandwidth = 0;
251 // int r;
252 //
253 // sband = wiphy->bands[NET80211_BAND_2GHZ];
254 //
255 // /*
256 // * If no country IE has been received always enable active scan
257 // * on these channels. This is only done for specific regulatory SKUs
258 // */
259 // if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
260 // ch = &sband->channels[11]; /* CH 12 */
261 // if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
262 // ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
263 // ch = &sband->channels[12]; /* CH 13 */
264 // if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
265 // ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
266 // return;
267 // }
268 //
269 // /*
270 // * If a country IE has been received check its rule for this
271 // * channel first before enabling active scan. The passive scan
272 // * would have been enforced by the initial processing of our
273 // * custom regulatory domain.
274 // */
275 //
276 // ch = &sband->channels[11]; /* CH 12 */
277 // r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
278 // if (!r) {
279 // if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
280 // if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
281 // ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
282 // }
283 //
284 // ch = &sband->channels[12]; /* CH 13 */
285 // r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
286 // if (!r) {
287 // if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
288 // if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
289 // ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
290 // }
291 //}
292 //
293 ///* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */
294 //static void ath_reg_apply_radar_flags(struct wiphy *wiphy)
295 //{
296 // struct ieee80211_supported_band *sband;
297 // struct net80211_channel *ch;
298 // unsigned int i;
299 //
300 // if (!wiphy->bands[NET80211_BAND_5GHZ])
301 // return;
302 //
303 // sband = wiphy->bands[NET80211_BAND_5GHZ];
304 //
305 // for (i = 0; i < sband->n_channels; i++) {
306 // ch = &sband->channels[i];
307 // if (!ath_is_radar_freq(ch->center_freq))
308 // continue;
309 // /* We always enable radar detection/DFS on this
310 // * frequency range. Additionally we also apply on
311 // * this frequency range:
312 // * - If STA mode does not yet have DFS supports disable
313 // * active scanning
314 // * - If adhoc mode does not support DFS yet then
315 // * disable adhoc in the frequency.
316 // * - If AP mode does not yet support radar detection/DFS
317 // * do not allow AP mode
318 // */
319 // if (!(ch->flags & IEEE80211_CHAN_DISABLED))
320 // ch->flags |= IEEE80211_CHAN_RADAR |
321 // IEEE80211_CHAN_NO_IBSS |
322 // IEEE80211_CHAN_PASSIVE_SCAN;
323 // }
324 //}
325 //
326 //static void ath_reg_apply_world_flags(struct wiphy *wiphy,
327 // enum nl80211_reg_initiator initiator,
328 // struct ath_regulatory *reg)
329 //{
330 // switch (reg->regpair->regDmnEnum) {
331 // case 0x60:
332 // case 0x63:
333 // case 0x66:
334 // case 0x67:
335 // case 0x6C:
336 // ath_reg_apply_beaconing_flags(wiphy, initiator);
337 // break;
338 // case 0x68:
339 // ath_reg_apply_beaconing_flags(wiphy, initiator);
340 // ath_reg_apply_active_scan_flags(wiphy, initiator);
341 // break;
342 // }
343 //}
344 //
345 //int ath_reg_notifier_apply(struct wiphy *wiphy,
346 // struct regulatory_request *request,
347 // struct ath_regulatory *reg)
348 //{
349 // /* We always apply this */
350 // ath_reg_apply_radar_flags(wiphy);
351 //
352 // /*
353 // * This would happen when we have sent a custom regulatory request
354 // * a world regulatory domain and the scheduler hasn't yet processed
355 // * any pending requests in the queue.
356 // */
357 // if (!request)
358 // return 0;
359 //
360 // switch (request->initiator) {
361 // case NL80211_REGDOM_SET_BY_DRIVER:
362 // case NL80211_REGDOM_SET_BY_CORE:
363 // case NL80211_REGDOM_SET_BY_USER:
364 // break;
365 // case NL80211_REGDOM_SET_BY_COUNTRY_IE:
366 // if (ath_is_world_regd(reg))
367 // ath_reg_apply_world_flags(wiphy, request->initiator,
368 // reg);
369 // break;
370 // }
371 //
372 // return 0;
373 //}
374 //
375 //static int ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
376 //{
377 // u16 rd = ath_regd_get_eepromRD(reg);
378 // int i;
379 //
380 // if (rd & COUNTRY_ERD_FLAG) {
381 // /* EEPROM value is a country code */
382 // u16 cc = rd & ~COUNTRY_ERD_FLAG;
383 // DBG2(
384 // "ath: EEPROM indicates we should expect "
385 // "a country code\n");
386 // for (i = 0; i < ARRAY_SIZE(allCountries); i++)
387 // if (allCountries[i].countryCode == cc)
388 // return 1;
389 // } else {
390 // /* EEPROM value is a regpair value */
391 // if (rd != CTRY_DEFAULT)
392 // DBG2("ath: EEPROM indicates we "
393 // "should expect a direct regpair map\n");
394 // for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
395 // if (regDomainPairs[i].regDmnEnum == rd)
396 // return 1;
397 // }
398 // DBG(
399 // "ath: invalid regulatory domain/country code 0x%x\n", rd);
400 // return 0;
401 //}
402 //
403 ///* EEPROM country code to regpair mapping */
404 //static struct country_code_to_enum_rd*
405 //ath_regd_find_country(u16 countryCode)
406 //{
407 // int i;
408 //
409 // for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
410 // if (allCountries[i].countryCode == countryCode)
411 // return &allCountries[i];
412 // }
413 // return NULL;
414 //}
415 //
416 ///* EEPROM rd code to regpair mapping */
417 //static struct country_code_to_enum_rd*
418 //ath_regd_find_country_by_rd(int regdmn)
419 //{
420 // int i;
421 //
422 // for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
423 // if (allCountries[i].regDmnEnum == regdmn)
424 // return &allCountries[i];
425 // }
426 // return NULL;
427 //}
428 //
429 ///* Returns the map of the EEPROM set RD to a country code */
430 //static u16 ath_regd_get_default_country(u16 rd)
431 //{
432 // if (rd & COUNTRY_ERD_FLAG) {
433 // struct country_code_to_enum_rd *country = NULL;
434 // u16 cc = rd & ~COUNTRY_ERD_FLAG;
435 //
436 // country = ath_regd_find_country(cc);
437 // if (country != NULL)
438 // return cc;
439 // }
440 //
441 // return CTRY_DEFAULT;
442 //}
443 //
444 //static struct reg_dmn_pair_mapping*
445 //ath_get_regpair(int regdmn)
446 //{
447 // int i;
448 //
449 // if (regdmn == NO_ENUMRD)
450 // return NULL;
451 // for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
452 // if (regDomainPairs[i].regDmnEnum == regdmn)
453 // return &regDomainPairs[i];
454 // }
455 // return NULL;
456 //}
457 //
458 //static int
459 //ath_regd_init_wiphy(struct ath_regulatory *reg,
460 // struct wiphy *wiphy,
461 // int (*reg_notifier)(struct wiphy *wiphy,
462 // struct regulatory_request *request))
463 //{
464 // const struct ieee80211_regdomain *regd;
465 //
466 // wiphy->reg_notifier = reg_notifier;
467 // wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
468 //
469 // if (ath_is_world_regd(reg)) {
470 // /*
471 // * Anything applied here (prior to wiphy registration) gets
472 // * saved on the wiphy orig_* parameters
473 // */
474 // regd = ath_world_regdomain(reg);
475 // wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
476 // } else {
477 // /*
478 // * This gets applied in the case of the absence of CRDA,
479 // * it's our own custom world regulatory domain, similar to
480 // * cfg80211's but we enable passive scanning.
481 // */
482 // regd = ath_default_world_regdomain();
483 // }
484 // wiphy_apply_custom_regulatory(wiphy, regd);
485 // ath_reg_apply_radar_flags(wiphy);
486 // ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
487 // return 0;
488 //}
489 //
490 ///*
491 // * Some users have reported their EEPROM programmed with
492 // * 0x8000 set, this is not a supported regulatory domain
493 // * but since we have more than one user with it we need
494 // * a solution for them. We default to 0x64, which is the
495 // * default Atheros world regulatory domain.
496 // */
497 //static void ath_regd_sanitize(struct ath_regulatory *reg)
498 //{
499 // if (reg->current_rd != COUNTRY_ERD_FLAG)
500 // return;
501 // DBG2("ath: EEPROM regdomain sanitized\n");
502 // reg->current_rd = 0x64;
503 //}
504 //
505 //int
506 //ath_regd_init(struct ath_regulatory *reg,
507 // struct wiphy *wiphy,
508 // int (*reg_notifier)(struct wiphy *wiphy,
509 // struct regulatory_request *request))
510 //{
511 // struct country_code_to_enum_rd *country = NULL;
512 // u16 regdmn;
513 //
514 // if (!reg)
515 // return -EINVAL;
516 //
517 // ath_regd_sanitize(reg);
518 //
519 // DBG2("ath: EEPROM regdomain: 0x%0x\n", reg->current_rd);
520 //
521 // if (!ath_regd_is_eeprom_valid(reg)) {
522 // DBG("ath: Invalid EEPROM contents\n");
523 // return -EINVAL;
524 // }
525 //
526 // regdmn = ath_regd_get_eepromRD(reg);
527 // reg->country_code = ath_regd_get_default_country(regdmn);
528 //
529 // if (reg->country_code == CTRY_DEFAULT &&
530 // regdmn == CTRY_DEFAULT) {
531 // DBG2("ath: EEPROM indicates default "
532 // "country code should be used\n");
533 // reg->country_code = CTRY_UNITED_STATES;
534 // }
535 //
536 // if (reg->country_code == CTRY_DEFAULT) {
537 // country = NULL;
538 // } else {
539 // DBG2("ath: doing EEPROM country->regdmn "
540 // "map search\n");
541 // country = ath_regd_find_country(reg->country_code);
542 // if (country == NULL) {
543 // DBG(
544 // "ath: no valid country maps found for "
545 // "country code: 0x%0x\n",
546 // reg->country_code);
547 // return -EINVAL;
548 // } else {
549 // regdmn = country->regDmnEnum;
550 // DBG2("ath: country maps to "
551 // "regdmn code: 0x%0x\n",
552 // regdmn);
553 // }
554 // }
555 //
556 // reg->regpair = ath_get_regpair(regdmn);
557 //
558 // if (!reg->regpair) {
559 // DBG("ath: "
560 // "No regulatory domain pair found, cannot continue\n");
561 // return -EINVAL;
562 // }
563 //
564 // if (!country)
565 // country = ath_regd_find_country_by_rd(regdmn);
566 //
567 // if (country) {
568 // reg->alpha2[0] = country->isoName[0];
569 // reg->alpha2[1] = country->isoName[1];
570 // } else {
571 // reg->alpha2[0] = '0';
572 // reg->alpha2[1] = '0';
573 // }
574 //
575 // DBG2("ath: Country alpha2 being used: %c%c\n",
576 // reg->alpha2[0], reg->alpha2[1]);
577 // DBG2("ath: Regpair used: 0x%0x\n",
578 // reg->regpair->regDmnEnum);
579 //
580 // ath_regd_init_wiphy(reg, wiphy, reg_notifier);
581 // return 0;
582 //}
583 
585  int band)
586 {
587  /* TODO Cottsay: reg */
588 // if (!reg->regpair ||
589 // (reg->country_code == CTRY_DEFAULT &&
590 // is_wwr_sku(ath_regd_get_eepromRD(reg)))) {
591 // return SD_NO_CTL;
592 // }
593 
594  switch (band) {
595  case NET80211_BAND_2GHZ:
596  return reg->regpair->reg_2ghz_ctl;
597  case NET80211_BAND_5GHZ:
598  return reg->regpair->reg_5ghz_ctl;
599  default:
600  return NO_CTL;
601  }
602 }
#define NET80211_BAND_2GHZ
The 2.4 GHz ISM band, unlicensed in most countries.
Definition: net80211.h:45
#define NET80211_BAND_5GHZ
The band from 4.9 GHz to 5.7 GHz, which tends to be more restricted.
Definition: net80211.h:47
static unsigned int unsigned int reg
Definition: intel.h:245
#define NO_CTL
Definition: eeprom.h:68
u32 ath_regd_get_band_ctl(struct ath_regulatory *reg, int band)
Definition: ath_regd.c:584
uint32_t u32
Definition: stdint.h:23