Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/athk/regd.c
48255 views
1
/*
2
* Copyright (c) 2008-2009 Atheros Communications Inc.
3
*
4
* Permission to use, copy, modify, and/or distribute this software for any
5
* purpose with or without fee is hereby granted, provided that the above
6
* copyright notice and this permission notice appear in all copies.
7
*
8
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
*/
16
17
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
19
#include <linux/kernel.h>
20
#include <linux/export.h>
21
#include <net/cfg80211.h>
22
#include <net/mac80211.h>
23
#include "regd.h"
24
#include "regd_common.h"
25
26
static int __ath_regd_init(struct ath_regulatory *reg);
27
28
/*
29
* This is a set of common rules used by our world regulatory domains.
30
* We have 12 world regulatory domains. To save space we consolidate
31
* the regulatory domains in 5 structures by frequency and change
32
* the flags on our reg_notifier() on a case by case basis.
33
*/
34
35
/* Only these channels all allow active scan on all world regulatory domains */
36
#define ATH_2GHZ_CH01_11 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
37
38
/* We enable active scan on these a case by case basis by regulatory domain */
39
#define ATH_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\
40
NL80211_RRF_NO_IR)
41
#define ATH_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\
42
NL80211_RRF_NO_IR | \
43
NL80211_RRF_NO_OFDM)
44
45
/* We allow IBSS on these on a case by case basis by regulatory domain */
46
#define ATH_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\
47
NL80211_RRF_NO_IR)
48
#define ATH_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\
49
NL80211_RRF_NO_IR)
50
#define ATH_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 80, 0, 30,\
51
NL80211_RRF_NO_IR)
52
53
#define ATH_2GHZ_ALL ATH_2GHZ_CH01_11, \
54
ATH_2GHZ_CH12_13, \
55
ATH_2GHZ_CH14
56
57
#define ATH_5GHZ_ALL ATH_5GHZ_5150_5350, \
58
ATH_5GHZ_5470_5850
59
60
/* This one skips what we call "mid band" */
61
#define ATH_5GHZ_NO_MIDBAND ATH_5GHZ_5150_5350, \
62
ATH_5GHZ_5725_5850
63
64
/* Can be used for:
65
* 0x60, 0x61, 0x62 */
66
static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = {
67
.n_reg_rules = 5,
68
.alpha2 = "99",
69
.reg_rules = {
70
ATH_2GHZ_ALL,
71
ATH_5GHZ_ALL,
72
}
73
};
74
75
/* Can be used by 0x63 and 0x65 */
76
static const struct ieee80211_regdomain ath_world_regdom_63_65 = {
77
.n_reg_rules = 4,
78
.alpha2 = "99",
79
.reg_rules = {
80
ATH_2GHZ_CH01_11,
81
ATH_2GHZ_CH12_13,
82
ATH_5GHZ_NO_MIDBAND,
83
}
84
};
85
86
/* Can be used by 0x64 only */
87
static const struct ieee80211_regdomain ath_world_regdom_64 = {
88
.n_reg_rules = 3,
89
.alpha2 = "99",
90
.reg_rules = {
91
ATH_2GHZ_CH01_11,
92
ATH_5GHZ_NO_MIDBAND,
93
}
94
};
95
96
/* Can be used by 0x66 and 0x69 */
97
static const struct ieee80211_regdomain ath_world_regdom_66_69 = {
98
.n_reg_rules = 3,
99
.alpha2 = "99",
100
.reg_rules = {
101
ATH_2GHZ_CH01_11,
102
ATH_5GHZ_ALL,
103
}
104
};
105
106
/* Can be used by 0x67, 0x68, 0x6A and 0x6C */
107
static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = {
108
.n_reg_rules = 4,
109
.alpha2 = "99",
110
.reg_rules = {
111
ATH_2GHZ_CH01_11,
112
ATH_2GHZ_CH12_13,
113
ATH_5GHZ_ALL,
114
}
115
};
116
117
static bool dynamic_country_user_possible(struct ath_regulatory *reg)
118
{
119
if (IS_ENABLED(CONFIG_ATH_REG_DYNAMIC_USER_CERT_TESTING))
120
return true;
121
122
switch (reg->country_code) {
123
case CTRY_UNITED_STATES:
124
case CTRY_JAPAN1:
125
case CTRY_JAPAN2:
126
case CTRY_JAPAN3:
127
case CTRY_JAPAN4:
128
case CTRY_JAPAN5:
129
case CTRY_JAPAN6:
130
case CTRY_JAPAN7:
131
case CTRY_JAPAN8:
132
case CTRY_JAPAN9:
133
case CTRY_JAPAN10:
134
case CTRY_JAPAN11:
135
case CTRY_JAPAN12:
136
case CTRY_JAPAN13:
137
case CTRY_JAPAN14:
138
case CTRY_JAPAN15:
139
case CTRY_JAPAN16:
140
case CTRY_JAPAN17:
141
case CTRY_JAPAN18:
142
case CTRY_JAPAN19:
143
case CTRY_JAPAN20:
144
case CTRY_JAPAN21:
145
case CTRY_JAPAN22:
146
case CTRY_JAPAN23:
147
case CTRY_JAPAN24:
148
case CTRY_JAPAN25:
149
case CTRY_JAPAN26:
150
case CTRY_JAPAN27:
151
case CTRY_JAPAN28:
152
case CTRY_JAPAN29:
153
case CTRY_JAPAN30:
154
case CTRY_JAPAN31:
155
case CTRY_JAPAN32:
156
case CTRY_JAPAN33:
157
case CTRY_JAPAN34:
158
case CTRY_JAPAN35:
159
case CTRY_JAPAN36:
160
case CTRY_JAPAN37:
161
case CTRY_JAPAN38:
162
case CTRY_JAPAN39:
163
case CTRY_JAPAN40:
164
case CTRY_JAPAN41:
165
case CTRY_JAPAN42:
166
case CTRY_JAPAN43:
167
case CTRY_JAPAN44:
168
case CTRY_JAPAN45:
169
case CTRY_JAPAN46:
170
case CTRY_JAPAN47:
171
case CTRY_JAPAN48:
172
case CTRY_JAPAN49:
173
case CTRY_JAPAN50:
174
case CTRY_JAPAN51:
175
case CTRY_JAPAN52:
176
case CTRY_JAPAN53:
177
case CTRY_JAPAN54:
178
case CTRY_JAPAN55:
179
case CTRY_JAPAN56:
180
case CTRY_JAPAN57:
181
case CTRY_JAPAN58:
182
case CTRY_JAPAN59:
183
return false;
184
}
185
186
return true;
187
}
188
189
static bool ath_reg_dyn_country_user_allow(struct ath_regulatory *reg)
190
{
191
if (!IS_ENABLED(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS))
192
return false;
193
if (!dynamic_country_user_possible(reg))
194
return false;
195
return true;
196
}
197
198
static inline bool is_wwr_sku(u16 regd)
199
{
200
return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) &&
201
(((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||
202
(regd == WORLD));
203
}
204
205
static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg)
206
{
207
return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG;
208
}
209
210
bool ath_is_world_regd(struct ath_regulatory *reg)
211
{
212
return is_wwr_sku(ath_regd_get_eepromRD(reg));
213
}
214
EXPORT_SYMBOL(ath_is_world_regd);
215
216
static const struct ieee80211_regdomain *ath_default_world_regdomain(void)
217
{
218
/* this is the most restrictive */
219
return &ath_world_regdom_64;
220
}
221
222
static const struct
223
ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
224
{
225
switch (reg->regpair->reg_domain) {
226
case 0x60:
227
case 0x61:
228
case 0x62:
229
return &ath_world_regdom_60_61_62;
230
case 0x63:
231
case 0x65:
232
return &ath_world_regdom_63_65;
233
case 0x64:
234
return &ath_world_regdom_64;
235
case 0x66:
236
case 0x69:
237
return &ath_world_regdom_66_69;
238
case 0x67:
239
case 0x68:
240
case 0x6A:
241
case 0x6C:
242
return &ath_world_regdom_67_68_6A_6C;
243
default:
244
WARN_ON(1);
245
return ath_default_world_regdomain();
246
}
247
}
248
249
bool ath_is_49ghz_allowed(u16 regdomain)
250
{
251
/* possibly more */
252
return regdomain == MKK9_MKKC;
253
}
254
EXPORT_SYMBOL(ath_is_49ghz_allowed);
255
256
/* Frequency is one where radar detection is required */
257
static bool ath_is_radar_freq(u16 center_freq,
258
struct ath_regulatory *reg)
259
260
{
261
if (reg->country_code == CTRY_INDIA)
262
return (center_freq >= 5500 && center_freq <= 5700);
263
return (center_freq >= 5260 && center_freq <= 5700);
264
}
265
266
static void ath_force_clear_no_ir_chan(struct wiphy *wiphy,
267
struct ieee80211_channel *ch)
268
{
269
const struct ieee80211_reg_rule *reg_rule;
270
271
reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq));
272
if (IS_ERR(reg_rule))
273
return;
274
275
if (!(reg_rule->flags & NL80211_RRF_NO_IR))
276
if (ch->flags & IEEE80211_CHAN_NO_IR)
277
ch->flags &= ~IEEE80211_CHAN_NO_IR;
278
}
279
280
static void ath_force_clear_no_ir_freq(struct wiphy *wiphy, u16 center_freq)
281
{
282
struct ieee80211_channel *ch;
283
284
ch = ieee80211_get_channel(wiphy, center_freq);
285
if (!ch)
286
return;
287
288
ath_force_clear_no_ir_chan(wiphy, ch);
289
}
290
291
static void ath_force_no_ir_chan(struct ieee80211_channel *ch)
292
{
293
ch->flags |= IEEE80211_CHAN_NO_IR;
294
}
295
296
static void ath_force_no_ir_freq(struct wiphy *wiphy, u16 center_freq)
297
{
298
struct ieee80211_channel *ch;
299
300
ch = ieee80211_get_channel(wiphy, center_freq);
301
if (!ch)
302
return;
303
304
ath_force_no_ir_chan(ch);
305
}
306
307
static void
308
__ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
309
struct ath_regulatory *reg,
310
enum nl80211_reg_initiator initiator,
311
struct ieee80211_channel *ch)
312
{
313
if (ath_is_radar_freq(ch->center_freq, reg) ||
314
(ch->flags & IEEE80211_CHAN_RADAR))
315
return;
316
317
switch (initiator) {
318
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
319
ath_force_clear_no_ir_chan(wiphy, ch);
320
break;
321
case NL80211_REGDOM_SET_BY_USER:
322
if (ath_reg_dyn_country_user_allow(reg))
323
ath_force_clear_no_ir_chan(wiphy, ch);
324
break;
325
default:
326
if (ch->beacon_found)
327
ch->flags &= ~IEEE80211_CHAN_NO_IR;
328
}
329
}
330
331
/*
332
* These exception rules do not apply radar frequencies.
333
*
334
* - We enable initiating radiation if the country IE says its fine:
335
* - If no country IE has been processed and a we determine we have
336
* received a beacon on a channel we can enable initiating radiation.
337
*/
338
static void
339
ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
340
struct ath_regulatory *reg,
341
enum nl80211_reg_initiator initiator)
342
{
343
enum nl80211_band band;
344
struct ieee80211_supported_band *sband;
345
struct ieee80211_channel *ch;
346
unsigned int i;
347
348
for (band = 0; band < NUM_NL80211_BANDS; band++) {
349
if (!wiphy->bands[band])
350
continue;
351
sband = wiphy->bands[band];
352
for (i = 0; i < sband->n_channels; i++) {
353
ch = &sband->channels[i];
354
__ath_reg_apply_beaconing_flags(wiphy, reg,
355
initiator, ch);
356
}
357
}
358
}
359
360
/**
361
* ath_reg_apply_ir_flags()
362
* @wiphy: the wiphy to use
363
* @reg: regulatory structure - used for country selection
364
* @initiator: the regulatory hint initiator
365
*
366
* If no country IE has been received always enable passive scan
367
* and no-ibss on these channels. This is only done for specific
368
* regulatory SKUs.
369
*
370
* If a country IE has been received check its rule for this
371
* channel first before enabling active scan. The passive scan
372
* would have been enforced by the initial processing of our
373
* custom regulatory domain.
374
*/
375
static void
376
ath_reg_apply_ir_flags(struct wiphy *wiphy,
377
struct ath_regulatory *reg,
378
enum nl80211_reg_initiator initiator)
379
{
380
struct ieee80211_supported_band *sband;
381
382
sband = wiphy->bands[NL80211_BAND_2GHZ];
383
if (!sband)
384
return;
385
386
switch(initiator) {
387
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
388
ath_force_clear_no_ir_freq(wiphy, 2467);
389
ath_force_clear_no_ir_freq(wiphy, 2472);
390
break;
391
case NL80211_REGDOM_SET_BY_USER:
392
if (!ath_reg_dyn_country_user_allow(reg))
393
break;
394
ath_force_clear_no_ir_freq(wiphy, 2467);
395
ath_force_clear_no_ir_freq(wiphy, 2472);
396
break;
397
default:
398
ath_force_no_ir_freq(wiphy, 2467);
399
ath_force_no_ir_freq(wiphy, 2472);
400
}
401
}
402
403
/* Always apply Radar/DFS rules on freq range 5500 MHz - 5700 MHz */
404
static void ath_reg_apply_radar_flags(struct wiphy *wiphy,
405
struct ath_regulatory *reg)
406
{
407
struct ieee80211_supported_band *sband;
408
struct ieee80211_channel *ch;
409
unsigned int i;
410
411
if (!wiphy->bands[NL80211_BAND_5GHZ])
412
return;
413
414
sband = wiphy->bands[NL80211_BAND_5GHZ];
415
416
for (i = 0; i < sband->n_channels; i++) {
417
ch = &sband->channels[i];
418
if (!ath_is_radar_freq(ch->center_freq, reg))
419
continue;
420
/* We always enable radar detection/DFS on this
421
* frequency range. Additionally we also apply on
422
* this frequency range:
423
* - If STA mode does not yet have DFS supports disable
424
* active scanning
425
* - If adhoc mode does not support DFS yet then
426
* disable adhoc in the frequency.
427
* - If AP mode does not yet support radar detection/DFS
428
* do not allow AP mode
429
*/
430
if (!(ch->flags & IEEE80211_CHAN_DISABLED))
431
ch->flags |= IEEE80211_CHAN_RADAR |
432
IEEE80211_CHAN_NO_IR;
433
}
434
}
435
436
static void ath_reg_apply_world_flags(struct wiphy *wiphy,
437
enum nl80211_reg_initiator initiator,
438
struct ath_regulatory *reg)
439
{
440
switch (reg->regpair->reg_domain) {
441
case 0x60:
442
case 0x63:
443
case 0x66:
444
case 0x67:
445
case 0x6C:
446
ath_reg_apply_beaconing_flags(wiphy, reg, initiator);
447
break;
448
case 0x68:
449
ath_reg_apply_beaconing_flags(wiphy, reg, initiator);
450
ath_reg_apply_ir_flags(wiphy, reg, initiator);
451
break;
452
default:
453
if (ath_reg_dyn_country_user_allow(reg))
454
ath_reg_apply_beaconing_flags(wiphy, reg, initiator);
455
}
456
}
457
458
u16 ath_regd_find_country_by_name(char *alpha2)
459
{
460
unsigned int i;
461
462
for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
463
if (!memcmp(allCountries[i].isoName, alpha2, 2))
464
return allCountries[i].countryCode;
465
}
466
467
return -1;
468
}
469
EXPORT_SYMBOL(ath_regd_find_country_by_name);
470
471
static int __ath_reg_dyn_country(struct wiphy *wiphy,
472
struct ath_regulatory *reg,
473
struct regulatory_request *request)
474
{
475
u16 country_code;
476
477
if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
478
!ath_is_world_regd(reg))
479
return -EINVAL;
480
481
country_code = ath_regd_find_country_by_name(request->alpha2);
482
if (country_code == (u16) -1)
483
return -EINVAL;
484
485
reg->current_rd = COUNTRY_ERD_FLAG;
486
reg->current_rd |= country_code;
487
488
__ath_regd_init(reg);
489
490
ath_reg_apply_world_flags(wiphy, request->initiator, reg);
491
492
return 0;
493
}
494
495
static void ath_reg_dyn_country(struct wiphy *wiphy,
496
struct ath_regulatory *reg,
497
struct regulatory_request *request)
498
{
499
if (__ath_reg_dyn_country(wiphy, reg, request))
500
return;
501
502
printk(KERN_DEBUG "ath: regdomain 0x%0x "
503
"dynamically updated by %s\n",
504
reg->current_rd,
505
reg_initiator_name(request->initiator));
506
}
507
508
void ath_reg_notifier_apply(struct wiphy *wiphy,
509
struct regulatory_request *request,
510
struct ath_regulatory *reg)
511
{
512
struct ath_common *common = container_of(reg, struct ath_common,
513
regulatory);
514
/* We always apply this */
515
ath_reg_apply_radar_flags(wiphy, reg);
516
517
/*
518
* This would happen when we have sent a custom regulatory request
519
* a world regulatory domain and the scheduler hasn't yet processed
520
* any pending requests in the queue.
521
*/
522
if (!request)
523
return;
524
525
reg->region = request->dfs_region;
526
switch (request->initiator) {
527
case NL80211_REGDOM_SET_BY_CORE:
528
/*
529
* If common->reg_world_copy is world roaming it means we *were*
530
* world roaming... so we now have to restore that data.
531
*/
532
if (!ath_is_world_regd(&common->reg_world_copy))
533
break;
534
535
memcpy(reg, &common->reg_world_copy,
536
sizeof(struct ath_regulatory));
537
break;
538
case NL80211_REGDOM_SET_BY_DRIVER:
539
break;
540
case NL80211_REGDOM_SET_BY_USER:
541
if (ath_reg_dyn_country_user_allow(reg))
542
ath_reg_dyn_country(wiphy, reg, request);
543
break;
544
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
545
ath_reg_dyn_country(wiphy, reg, request);
546
break;
547
}
548
}
549
EXPORT_SYMBOL(ath_reg_notifier_apply);
550
551
static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
552
{
553
u16 rd = ath_regd_get_eepromRD(reg);
554
int i;
555
556
if (rd & COUNTRY_ERD_FLAG) {
557
/* EEPROM value is a country code */
558
u16 cc = rd & ~COUNTRY_ERD_FLAG;
559
printk(KERN_DEBUG
560
"ath: EEPROM indicates we should expect "
561
"a country code\n");
562
for (i = 0; i < ARRAY_SIZE(allCountries); i++)
563
if (allCountries[i].countryCode == cc)
564
return true;
565
} else {
566
/* EEPROM value is a regpair value */
567
if (rd != CTRY_DEFAULT)
568
printk(KERN_DEBUG "ath: EEPROM indicates we "
569
"should expect a direct regpair map\n");
570
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
571
if (regDomainPairs[i].reg_domain == rd)
572
return true;
573
}
574
printk(KERN_DEBUG
575
"ath: invalid regulatory domain/country code 0x%x\n", rd);
576
return false;
577
}
578
579
/* EEPROM country code to regpair mapping */
580
static struct country_code_to_enum_rd*
581
ath_regd_find_country(u16 countryCode)
582
{
583
int i;
584
585
for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
586
if (allCountries[i].countryCode == countryCode)
587
return &allCountries[i];
588
}
589
return NULL;
590
}
591
592
/* EEPROM rd code to regpair mapping */
593
static struct country_code_to_enum_rd*
594
ath_regd_find_country_by_rd(int regdmn)
595
{
596
int i;
597
598
for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
599
if (allCountries[i].regDmnEnum == regdmn)
600
return &allCountries[i];
601
}
602
return NULL;
603
}
604
605
/* Returns the map of the EEPROM set RD to a country code */
606
static u16 ath_regd_get_default_country(u16 rd)
607
{
608
if (rd & COUNTRY_ERD_FLAG) {
609
struct country_code_to_enum_rd *country = NULL;
610
u16 cc = rd & ~COUNTRY_ERD_FLAG;
611
612
country = ath_regd_find_country(cc);
613
if (country != NULL)
614
return cc;
615
}
616
617
return CTRY_DEFAULT;
618
}
619
620
static struct reg_dmn_pair_mapping*
621
ath_get_regpair(int regdmn)
622
{
623
int i;
624
625
if (regdmn == NO_ENUMRD)
626
return NULL;
627
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
628
if (regDomainPairs[i].reg_domain == regdmn)
629
return &regDomainPairs[i];
630
}
631
return NULL;
632
}
633
634
static int
635
ath_regd_init_wiphy(struct ath_regulatory *reg,
636
struct wiphy *wiphy,
637
void (*reg_notifier)(struct wiphy *wiphy,
638
struct regulatory_request *request))
639
{
640
const struct ieee80211_regdomain *regd;
641
642
wiphy->reg_notifier = reg_notifier;
643
wiphy->regulatory_flags |= REGULATORY_STRICT_REG |
644
REGULATORY_CUSTOM_REG;
645
646
if (ath_is_world_regd(reg)) {
647
/*
648
* Anything applied here (prior to wiphy registration) gets
649
* saved on the wiphy orig_* parameters
650
*/
651
regd = ath_world_regdomain(reg);
652
wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_FOLLOW_POWER;
653
} else {
654
/*
655
* This gets applied in the case of the absence of CRDA,
656
* it's our own custom world regulatory domain, similar to
657
* cfg80211's but we enable passive scanning.
658
*/
659
regd = ath_default_world_regdomain();
660
}
661
662
wiphy_apply_custom_regulatory(wiphy, regd);
663
ath_reg_apply_radar_flags(wiphy, reg);
664
ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
665
return 0;
666
}
667
668
/*
669
* Some users have reported their EEPROM programmed with
670
* 0x8000 set, this is not a supported regulatory domain
671
* but since we have more than one user with it we need
672
* a solution for them. We default to 0x64, which is the
673
* default Atheros world regulatory domain.
674
*/
675
static void ath_regd_sanitize(struct ath_regulatory *reg)
676
{
677
if (reg->current_rd != COUNTRY_ERD_FLAG)
678
return;
679
printk(KERN_DEBUG "ath: EEPROM regdomain sanitized\n");
680
reg->current_rd = 0x64;
681
}
682
683
static int __ath_regd_init(struct ath_regulatory *reg)
684
{
685
struct country_code_to_enum_rd *country = NULL;
686
u16 regdmn;
687
688
if (!reg)
689
return -EINVAL;
690
691
ath_regd_sanitize(reg);
692
693
printk(KERN_DEBUG "ath: EEPROM regdomain: 0x%0x\n", reg->current_rd);
694
695
if (!ath_regd_is_eeprom_valid(reg)) {
696
pr_err("Invalid EEPROM contents\n");
697
return -EINVAL;
698
}
699
700
regdmn = ath_regd_get_eepromRD(reg);
701
reg->country_code = ath_regd_get_default_country(regdmn);
702
703
if (reg->country_code == CTRY_DEFAULT &&
704
regdmn == CTRY_DEFAULT) {
705
printk(KERN_DEBUG "ath: EEPROM indicates default "
706
"country code should be used\n");
707
reg->country_code = CTRY_UNITED_STATES;
708
}
709
710
if (reg->country_code == CTRY_DEFAULT) {
711
country = NULL;
712
} else {
713
printk(KERN_DEBUG "ath: doing EEPROM country->regdmn "
714
"map search\n");
715
country = ath_regd_find_country(reg->country_code);
716
if (country == NULL) {
717
printk(KERN_DEBUG
718
"ath: no valid country maps found for "
719
"country code: 0x%0x\n",
720
reg->country_code);
721
return -EINVAL;
722
} else {
723
regdmn = country->regDmnEnum;
724
printk(KERN_DEBUG "ath: country maps to "
725
"regdmn code: 0x%0x\n",
726
regdmn);
727
}
728
}
729
730
reg->regpair = ath_get_regpair(regdmn);
731
732
if (!reg->regpair) {
733
printk(KERN_DEBUG "ath: "
734
"No regulatory domain pair found, cannot continue\n");
735
return -EINVAL;
736
}
737
738
if (!country)
739
country = ath_regd_find_country_by_rd(regdmn);
740
741
if (country) {
742
reg->alpha2[0] = country->isoName[0];
743
reg->alpha2[1] = country->isoName[1];
744
} else {
745
reg->alpha2[0] = '0';
746
reg->alpha2[1] = '0';
747
}
748
749
printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n",
750
reg->alpha2[0], reg->alpha2[1]);
751
printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n",
752
reg->regpair->reg_domain);
753
754
return 0;
755
}
756
757
int
758
ath_regd_init(struct ath_regulatory *reg,
759
struct wiphy *wiphy,
760
void (*reg_notifier)(struct wiphy *wiphy,
761
struct regulatory_request *request))
762
{
763
struct ath_common *common = container_of(reg, struct ath_common,
764
regulatory);
765
int r;
766
767
r = __ath_regd_init(reg);
768
if (r)
769
return r;
770
771
if (ath_is_world_regd(reg))
772
memcpy(&common->reg_world_copy, reg,
773
sizeof(struct ath_regulatory));
774
775
ath_regd_init_wiphy(reg, wiphy, reg_notifier);
776
777
return 0;
778
}
779
EXPORT_SYMBOL(ath_regd_init);
780
781
u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
782
enum nl80211_band band)
783
{
784
if (!reg->regpair ||
785
(reg->country_code == CTRY_DEFAULT &&
786
is_wwr_sku(ath_regd_get_eepromRD(reg)))) {
787
return SD_NO_CTL;
788
}
789
790
if (ath_regd_get_eepromRD(reg) == CTRY_DEFAULT) {
791
switch (reg->region) {
792
case NL80211_DFS_FCC:
793
return CTL_FCC;
794
case NL80211_DFS_ETSI:
795
return CTL_ETSI;
796
case NL80211_DFS_JP:
797
return CTL_MKK;
798
default:
799
break;
800
}
801
}
802
803
switch (band) {
804
case NL80211_BAND_2GHZ:
805
return reg->regpair->reg_2ghz_ctl;
806
case NL80211_BAND_5GHZ:
807
return reg->regpair->reg_5ghz_ctl;
808
default:
809
return NO_CTL;
810
}
811
}
812
EXPORT_SYMBOL(ath_regd_get_band_ctl);
813
814