blob: 35886b71ac87de622510fad455107538992435f4 [file] [log] [blame]
Amar Singhale4f28ee2015-10-21 14:36:56 -07001/*
2 * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_regulatory.c
30 *
31 * hdd regulatory implementation
32 */
33
34#include "qdf_types.h"
35#include "cds_reg_service.h"
36#include "qdf_trace.h"
37#include "sme_api.h"
38#include "wlan_hdd_main.h"
39#include "cds_regdomain.h"
40#include "cds_regdomain_common.h"
41#include "wlan_hdd_regulatory.h"
42
43#define WORLD_SKU_MASK 0x00F0
44#define WORLD_SKU_PREFIX 0x0060
45#define REG_WAIT_TIME 50
46
47#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
48#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR
49#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR
50#endif
51
52#define REG_RULE_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
53
54#define REG_RULE_2467_2472 REG_RULE(2467-10, 2472+10, 40, 0, 20, \
55 NL80211_RRF_PASSIVE_SCAN)
56
57#define REG_RULE_2484 REG_RULE(2484-10, 2484+10, 40, 0, 20, \
58 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)
59
60#define REG_RULE_5180_5320 REG_RULE(5180-10, 5320+10, 80, 0, 20, \
61 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
62
63#define REG_RULE_5500_5720 REG_RULE(5500-10, 5720+10, 80, 0, 20, \
64 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
65
66#define REG_RULE_5745_5925 REG_RULE(5745-10, 5925+10, 80, 0, 20, \
67 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
68
69static bool init_by_driver;
70static bool init_by_reg_core;
71
72static const struct ieee80211_regdomain
73hdd_world_regrules_60_61_62 = {
74 .n_reg_rules = 6,
75 .alpha2 = "00",
76 .reg_rules = {
77 REG_RULE_2412_2462,
78 REG_RULE_2467_2472,
79 REG_RULE_2484,
80 REG_RULE_5180_5320,
81 REG_RULE_5500_5720,
82 REG_RULE_5745_5925,
83 }
84};
85
86static const struct ieee80211_regdomain
87hdd_world_regrules_63_65 = {
88 .n_reg_rules = 4,
89 .alpha2 = "00",
90 .reg_rules = {
91 REG_RULE_2412_2462,
92 REG_RULE_2467_2472,
93 REG_RULE_5180_5320,
94 REG_RULE_5745_5925,
95 }
96};
97
98static const struct ieee80211_regdomain
99hdd_world_regrules_64 = {
100 .n_reg_rules = 3,
101 .alpha2 = "00",
102 .reg_rules = {
103 REG_RULE_2412_2462,
104 REG_RULE_5180_5320,
105 REG_RULE_5745_5925,
106 }
107};
108
109static const struct ieee80211_regdomain
110hdd_world_regrules_66_69 = {
111 .n_reg_rules = 4,
112 .alpha2 = "00",
113 .reg_rules = {
114 REG_RULE_2412_2462,
115 REG_RULE_5180_5320,
116 REG_RULE_5500_5720,
117 REG_RULE_5745_5925,
118 }
119};
120
121static const struct ieee80211_regdomain
122hdd_world_regrules_67_68_6A_6C = {
123 .n_reg_rules = 5,
124 .alpha2 = "00",
125 .reg_rules = {
126 REG_RULE_2412_2462,
127 REG_RULE_2467_2472,
128 REG_RULE_5180_5320,
129 REG_RULE_5500_5720,
130 REG_RULE_5745_5925,
131 }
132};
133
134/**
135 * hdd_get_world_regrules() - get the appropriate world regrules
136 * @reg: regulatory data
137 *
138 * Return: regulatory rules ptr
139 */
140static const struct ieee80211_regdomain *hdd_get_world_regrules(
141struct regulatory *reg)
142{
143 REG_DMN_PAIR_MAPPING *regpair =
144 (REG_DMN_PAIR_MAPPING *)reg->regpair;
145
146 switch (regpair->regDmnEnum) {
147 case 0x60:
148 case 0x61:
149 case 0x62:
150 return &hdd_world_regrules_60_61_62;
151 case 0x63:
152 case 0x65:
153 return &hdd_world_regrules_63_65;
154 case 0x64:
155 return &hdd_world_regrules_64;
156 case 0x66:
157 case 0x69:
158 return &hdd_world_regrules_66_69;
159 case 0x67:
160 case 0x68:
161 case 0x6A:
162 case 0x6C:
163 return &hdd_world_regrules_67_68_6A_6C;
164 default:
165 hdd_warn("invalid world mode in BDF");
166 return &hdd_world_regrules_60_61_62;
167 }
168}
169
170/**
171 * hdd_is_world_regdomain() - whether world regdomain
172 * @reg_domain: integer regulatory domain
173 *
174 * Return: bool
175 */
176bool hdd_is_world_regdomain(uint32_t reg_domain)
177{
178 uint32_t temp_regd = reg_domain & ~WORLDWIDE_ROAMING_FLAG;
179
180 return ((temp_regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) &&
181 (((temp_regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||
182 (temp_regd == WORLD));
183}
184
185
186/**
187 * hdd_update_regulatory_info() - update regulatory info
188 * @hdd_ctx: hdd context
189 *
190 * Return: void
191 */
192static void hdd_update_regulatory_info(hdd_context_t *hdd_ctx)
193{
194 uint32_t country_code;
195
196 country_code = cds_get_country_from_alpha2(hdd_ctx->reg.alpha2);
197
198 hdd_ctx->reg.reg_domain = COUNTRY_ERD_FLAG;
199 hdd_ctx->reg.reg_domain |= country_code;
200
201 cds_fill_some_regulatory_info(&hdd_ctx->reg);
202
203}
204
205/**
206 * hdd_regulatory_wiphy_init() - regulatory wiphy init
207 * @hdd_ctx: hdd context
208 * @reg: regulatory data
209 * @wiphy: wiphy structure
210 *
211 * Return: void
212 */
213#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
214static void hdd_regulatory_wiphy_init(hdd_context_t *hdd_ctx,
215 struct regulatory *reg,
216 struct wiphy *wiphy)
217{
218 const struct ieee80211_regdomain *reg_rules;
219
220 if (hdd_is_world_regdomain(reg->reg_domain)) {
221 reg_rules = hdd_get_world_regrules(reg);
222 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
223 } else if (hdd_ctx->config->fRegChangeDefCountry) {
224 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
225 reg_rules = &hdd_world_regrules_60_61_62;
226 } else {
227 wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
228 reg_rules = &hdd_world_regrules_60_61_62;
229 }
230
231 /*
232 * save the original driver regulatory flags
233 */
234 hdd_ctx->reg.reg_flags = wiphy->regulatory_flags;
235 wiphy_apply_custom_regulatory(wiphy, reg_rules);
236
237 /*
238 * restore the driver regulatory flags since
239 * wiphy_apply_custom_regulatory may have
240 * changed them
241 */
242 wiphy->regulatory_flags = hdd_ctx->reg.reg_flags;
243
244}
245#else
246static void hdd_regulatory_wiphy_init(hdd_context_t *hdd_ctx,
247 struct regulatory *reg,
248 struct wiphy *wiphy)
249{
250 const struct ieee80211_regdomain *reg_rules;
251
252 if (hdd_is_world_regdomain(reg->reg_domain)) {
253 reg_rules = hdd_get_world_regrules(reg);
254 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
255 } else if (hdd_ctx->config->fRegChangeDefCountry) {
256 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
257 reg_rules = &hdd_world_regrules_60_61_62;
258 } else {
259 wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
260 reg_rules = &hdd_world_regrules_60_61_62;
261 }
262
263 /*
264 * save the original driver regulatory flags
265 */
266 hdd_ctx->reg.reg_flags = wiphy->flags;
267 wiphy_apply_custom_regulatory(wiphy, reg_rules);
268
269 /*
270 * restore the driver regulatory flags since
271 * wiphy_apply_custom_regulatory may have
272 * changed them
273 */
274 wiphy->flags = hdd_ctx->reg.reg_flags;
275
276}
277#endif
278
279/**
280 * hdd_bw20_ch_index_to_() - convert 20 mhhz channel index to 40 mhz index
281 * @k: 20 mhz channel index
282 *
283 * Return: void
284 */
285static int hdd_bw20_ch_index_to_bw40_ch_index(int k)
286{
287 int m = -1;
288
289 if (k >= RF_CHAN_1 && k <= RF_CHAN_14) {
290 m = k - RF_CHAN_1 + RF_CHAN_BOND_3;
291 if (m > RF_CHAN_BOND_11)
292 m = RF_CHAN_BOND_11;
293 } else if (k >= RF_CHAN_36 && k <= RF_CHAN_64) {
294 m = k - RF_CHAN_36 + RF_CHAN_BOND_38;
295 if (m > RF_CHAN_BOND_62)
296 m = RF_CHAN_BOND_62;
297 } else if (k >= RF_CHAN_100 && k <= RF_CHAN_144) {
298 m = k - RF_CHAN_100 + RF_CHAN_BOND_102;
299 if (m > RF_CHAN_BOND_142)
300 m = RF_CHAN_BOND_142;
301 } else if (k >= RF_CHAN_149 && k <= RF_CHAN_165) {
302 m = k - RF_CHAN_149 + RF_CHAN_BOND_151;
303 if (m > RF_CHAN_BOND_163)
304 m = RF_CHAN_BOND_163;
305 }
306
307 return m;
308}
309
310/**
311 * is_wiphy_custom_regulatory() - is custom regulatory defined
312 * @wiphy: wiphy
313 *
314 * Return: int
315 */
316#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
317static int is_wiphy_custom_regulatory(struct wiphy *wiphy)
318{
319
320 return wiphy->regulatory_flags & REGULATORY_CUSTOM_REG;
321}
322#else
323static int is_wiphy_custom_regulatory(struct wiphy *wiphy)
324{
325 return wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY;
326}
327#endif
328
329
330/**
331 * hdd_modify_wiphy() - modify wiphy
332 * @wiphy: wiphy
333 * @chan: channel structure
334 *
335 * Return: void
336 */
337static void hdd_modify_wiphy(struct wiphy *wiphy,
338 struct ieee80211_channel *chan)
339{
340 const struct ieee80211_reg_rule *reg_rule;
341
342 if (is_wiphy_custom_regulatory(wiphy)) {
343 reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
344 if (!IS_ERR(reg_rule)) {
345 chan->flags &= ~IEEE80211_CHAN_DISABLED;
346
347 if (!(reg_rule->flags & NL80211_RRF_DFS)) {
348 hdd_info("%s: remove dfs restriction for %u",
349 __func__, chan->center_freq);
350 chan->flags &= ~IEEE80211_CHAN_RADAR;
351 }
352
353 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) {
354 hdd_info("%s: remove passive restriction for %u",
355 __func__, chan->center_freq);
356 chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
357 }
358
359 if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) {
360 hdd_info("%s: remove no ibss restriction for %u",
361 __func__, chan->center_freq);
362 chan->flags &= ~IEEE80211_CHAN_NO_IBSS;
363 }
364
365 chan->max_power =
366 MBM_TO_DBM(reg_rule->power_rule.max_eirp);
367 }
368 }
369}
370
371/**
372 * hdd_process_regulatory_data() - process regulatory data
373 * @hdd_ctx: hdd context
374 * @wiphy: wiphy
375 * @reset: whether to reset channel data
376 *
377 * Return: void
378 */
379static void hdd_process_regulatory_data(hdd_context_t *hdd_ctx,
380 struct wiphy *wiphy,
381 bool reset)
382{
383 int i, j, m;
384 int k = 0, n = 0;
385 struct ieee80211_channel *chan;
386 struct regulatory_channel *temp_chan_k, *temp_chan_n, *temp_chan;
387 uint8_t band_capability;
388
389 band_capability = hdd_ctx->config->nBandCapability;
390
391 hdd_ctx->isVHT80Allowed = 0;
392
393 if (band_capability == eCSR_BAND_24)
394 hdd_info("band capability is set to 2G only");
395
396 for (i = 0, m = 0; i < IEEE80211_NUM_BANDS; i++) {
397
398 if (i == IEEE80211_BAND_2GHZ &&
399 band_capability == eCSR_BAND_5G)
400 continue;
401
402 else if (i == IEEE80211_BAND_5GHZ &&
403 band_capability == eCSR_BAND_24)
404 continue;
405
406 if (wiphy->bands[i] == NULL) {
407 hdd_info("wiphy band no %d is NULL", i);
408 continue;
409 }
410
411 if (i == 0)
412 m = 0;
413 else
414 m = wiphy->bands[i-1]->n_channels + m;
415
416 for (j = 0; j < wiphy->bands[i]->n_channels; j++) {
417
418 k = m + j;
419 n = hdd_bw20_ch_index_to_bw40_ch_index(k);
420
421 chan = &(wiphy->bands[i]->channels[j]);
422 temp_chan_k = &(reg_channels[k]);
423 temp_chan_n = &(reg_channels[n]);
424
425 if (!reset)
426 hdd_modify_wiphy(wiphy, chan);
427
428 if (chan->flags & IEEE80211_CHAN_DISABLED) {
429 temp_chan_k->state =
430 CHANNEL_STATE_DISABLE;
431 temp_chan_k->flags = chan->flags;
432 if (n != -1) {
433 temp_chan_n->state =
434 CHANNEL_STATE_DISABLE;
435 temp_chan_n->flags = chan->flags;
436 }
437 } else if (chan->flags &
438 (IEEE80211_CHAN_RADAR |
439 IEEE80211_CHAN_PASSIVE_SCAN |
440 IEEE80211_CHAN_INDOOR_ONLY)) {
441
442 if (chan->flags &
443 IEEE80211_CHAN_INDOOR_ONLY)
444 chan->flags |=
445 IEEE80211_CHAN_PASSIVE_SCAN;
446 temp_chan_k->state = CHANNEL_STATE_DFS;
447 temp_chan_k->pwr_limit =
448 chan->max_power;
449 temp_chan_k->flags = chan->flags;
450
451 if (n != -1) {
452 if ((chan->flags &
453 IEEE80211_CHAN_NO_HT40) ==
454 IEEE80211_CHAN_NO_HT40) {
455 temp_chan_n->state =
456 CHANNEL_STATE_DISABLE;
457 } else {
458 temp_chan_n->state =
459 CHANNEL_STATE_DFS;
460 temp_chan_n->pwr_limit =
461 chan->max_power-3;
462 }
463 temp_chan_n->flags = chan->flags;
464 }
465 if ((chan->flags &
466 IEEE80211_CHAN_NO_80MHZ) == 0)
467 hdd_ctx->isVHT80Allowed = 1;
468 } else {
469 temp_chan_k->state = CHANNEL_STATE_ENABLE;
470 temp_chan_k->pwr_limit = chan->max_power;
471 temp_chan_k->flags = chan->flags;
472 if (n != -1) {
473 if ((chan->flags &
474 IEEE80211_CHAN_NO_HT40) ==
475 IEEE80211_CHAN_NO_HT40) {
476 temp_chan_n->state =
477 CHANNEL_STATE_DISABLE;
478 } else {
479 temp_chan_n->state =
480 CHANNEL_STATE_ENABLE;
481 temp_chan_n->pwr_limit =
482 chan->max_power - 3;
483 }
484 temp_chan_n->flags = chan->flags;
485 }
486 if ((chan->flags &
487 IEEE80211_CHAN_NO_80MHZ) == 0)
488 hdd_ctx->isVHT80Allowed = 1;
489 }
490 }
491 }
492
493 if (0 == (hdd_ctx->reg.eeprom_rd_ext &
494 (1 << WHAL_REG_EXT_FCC_CH_144))) {
495 temp_chan = &(reg_channels[RF_CHAN_144]);
496 temp_chan->state =
497 CHANNEL_STATE_DISABLE;
498 }
499
500}
501
502
503/**
504 * hdd_regulatory_init() - regulatory_init
505 * @hdd_ctx: hdd context
506 * @wiphy: wiphy
507 *
508 * Return: int
509 */
510int hdd_regulatory_init(hdd_context_t *hdd_ctx, struct wiphy *wiphy)
511{
512 int ret_val;
513 struct regulatory *reg_info;
514
515 reg_info = &hdd_ctx->reg;
516
517 hdd_regulatory_wiphy_init(hdd_ctx, reg_info, wiphy);
518
519 hdd_process_regulatory_data(hdd_ctx, wiphy, true);
520
521 reg_info->cc_src = SOURCE_DRIVER;
522
523 ret_val = cds_fill_some_regulatory_info(reg_info);
524 if (ret_val) {
525 hdd_err("incorrect BDF regulatory data");
526 return ret_val;
527 }
528
529 cds_put_default_country(reg_info->alpha2);
530
531 init_completion(&hdd_ctx->reg_init);
532
533 cds_fill_and_send_ctl_to_fw(reg_info);
534
535 return 0;
536}
537
538/**
539 * hdd_program_country_code() - process channel information from country code
540 * @hdd_ctx: hddc context
541 *
542 * Return: void
543 */
544void hdd_program_country_code(hdd_context_t *hdd_ctx)
545{
546 struct wiphy *wiphy = hdd_ctx->wiphy;
547 uint8_t *country_alpha2 = hdd_ctx->reg.alpha2;
548
549 if (false == init_by_reg_core) {
550 init_by_driver = true;
551 if (('0' != country_alpha2[0]) ||
552 ('0' != country_alpha2[1])) {
553 INIT_COMPLETION(hdd_ctx->reg_init);
554 regulatory_hint(wiphy, country_alpha2);
555 wait_for_completion_timeout(&hdd_ctx->reg_init,
556 msecs_to_jiffies(REG_WAIT_TIME));
557 }
558 }
559}
560
561
562/**
563 * hdd_set_dfs_region() - set the dfs_region
564 * @dfs_region: the dfs_region to set
565 *
566 * Return: void
567 */
568#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
569static void hdd_set_dfs_region(hdd_context_t *hdd_ctx,
570 uint8_t dfs_reg)
571{
572 cds_put_dfs_region(dfs_reg);
573}
574#else
575static void hdd_set_dfs_region(hdd_context_t *hdd_ctx,
576 uint8_t dfs_reg)
577{
578
579 /* remap the ctl code to dfs region code */
580 switch (hdd_ctx->reg.ctl_5g) {
581 case FCC:
582 cds_put_dfs_region(DFS_FCC_DOMAIN);
583 break;
584 case ETSI:
585 cds_put_dfs_region(DFS_ETSI_DOMAIN);
586 break;
587 case MKK:
588 cds_put_dfs_region(DFS_MKK4_DOMAIN);
589 break;
590 default:
591 /* set default dfs_region to FCC */
592 cds_put_dfs_region(DFS_FCC_DOMAIN);
593 break;
594 }
595
596}
597#endif
598
599/**
600 * hdd_restore_custom_reg_settings() - restore custom reg settings
601 * @wiphy: wiphy structure
602 * @country_alpha2: alpha2 of the country
603 * @reset: whether wiphy is reset
604 *
605 * Return: void
606 */
607#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
608static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
609 uint8_t *country_alpha2,
610 bool *reset)
611{
612}
613#else
614static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
615 uint8_t *country_alpha2,
616 bool *reset)
617{
618 struct ieee80211_supported_band *sband;
619 enum ieee80211_band band;
620 struct ieee80211_channel *chan;
621 int i;
622
623 if ((country_alpha2[0] == '0') &&
624 (country_alpha2[1] == '0') &&
625 (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) {
626
627 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
628 sband = wiphy->bands[band];
629 if (!sband)
630 continue;
631 for (i = 0; i < sband->n_channels; i++) {
632 chan = &sband->channels[i];
633 chan->flags = chan->orig_flags;
634 chan->max_antenna_gain = chan->orig_mag;
635 chan->max_power = chan->orig_mpwr;
636 }
637 }
638 *reset = true;
639 }
640}
641#endif
642
643
644/**
645 * hdd_restore_reg_flags() - restore regulatory flags
646 * @flags: regulatory flags
647 *
648 * Return: void
649 */
650#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
651static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
652{
653 wiphy->regulatory_flags = flags;
654}
655#else
656static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
657{
658 wiphy->flags = flags;
659}
660#endif
661
662
663/**
664 * hdd_reg_notifier() - regulatory notifier
665 * @wiphy: wiphy
666 * @request: regulatory request
667 *
668 * Return: void
669 */
670void hdd_reg_notifier(struct wiphy *wiphy,
671 struct regulatory_request *request)
672{
673 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
674 eCsrBand band_capability = eCSR_BAND_ALL;
675 bool vht80_allowed;
676 bool reset = false;
677 uint8_t dfs_reg;
678
679 hdd_info("country: %c%c, initiator %d, dfs_region: %d",
680 request->alpha2[0],
681 request->alpha2[1],
682 request->initiator,
683 request->dfs_region);
684
685 if (NULL == hdd_ctx) {
686 hdd_err("invalid hdd_ctx pointer");
687 return;
688 }
689
690 if (cds_is_driver_unloading() || cds_is_driver_recovering()) {
691 hdd_err("%s: unloading or ssr in progress, ignore",
692 __func__);
693 return;
694 }
695
696 sme_get_freq_band(hdd_ctx->hHal, &band_capability);
697
698 /* first check if this callback is in response to the driver callback */
699
700 switch (request->initiator) {
701 case NL80211_REGDOM_SET_BY_DRIVER:
702 case NL80211_REGDOM_SET_BY_CORE:
703 case NL80211_REGDOM_SET_BY_USER:
704
705 if ((false == init_by_driver) &&
706 (false == init_by_reg_core)) {
707
708 if (NL80211_REGDOM_SET_BY_CORE == request->initiator)
709 return;
710 init_by_reg_core = true;
711 }
712
713 if ((NL80211_REGDOM_SET_BY_DRIVER == request->initiator) &&
714 (true == init_by_driver)) {
715
716 /*
717 * restore the driver regulatory flags since
718 * regulatory_hint may have
719 * changed them
720 */
721 hdd_restore_reg_flags(wiphy, hdd_ctx->reg.reg_flags);
722 }
723
724 if (NL80211_REGDOM_SET_BY_CORE == request->initiator) {
725 hdd_ctx->reg.cc_src = SOURCE_CORE;
726 if (is_wiphy_custom_regulatory(wiphy))
727 reset = true;
728 } else if (NL80211_REGDOM_SET_BY_DRIVER == request->initiator)
729 hdd_ctx->reg.cc_src = SOURCE_DRIVER;
730 else {
731 hdd_ctx->reg.cc_src = SOURCE_USERSPACE;
732 hdd_restore_custom_reg_settings(wiphy,
733 request->alpha2,
734 &reset);
735 }
736
737 hdd_ctx->reg.alpha2[0] = request->alpha2[0];
738 hdd_ctx->reg.alpha2[1] = request->alpha2[1];
739
740 hdd_update_regulatory_info(hdd_ctx);
741
742 vht80_allowed = hdd_ctx->isVHT80Allowed;
743
744 hdd_process_regulatory_data(hdd_ctx, wiphy, reset);
745
746 if (hdd_ctx->isVHT80Allowed != vht80_allowed)
747 hdd_checkandupdate_phymode(hdd_ctx);
748
749 if (NL80211_REGDOM_SET_BY_DRIVER == request->initiator)
750 complete(&hdd_ctx->reg_init);
751
752 sme_generic_change_country_code(hdd_ctx->hHal,
753 hdd_ctx->reg.alpha2);
754
755 cds_fill_and_send_ctl_to_fw(&hdd_ctx->reg);
756
757 hdd_set_dfs_region(hdd_ctx, request->dfs_region);
758
759 cds_get_dfs_region(&dfs_reg);
760 cds_set_wma_dfs_region(dfs_reg);
761 break;
762
763 default:
764 break;
765 }
766}