blob: 5ddb11b40e8a5fb4571a0f0b6d6bfb213d8c514d [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"
Amar Singhale4f28ee2015-10-21 14:36:56 -070040#include "wlan_hdd_regulatory.h"
41
42#define WORLD_SKU_MASK 0x00F0
43#define WORLD_SKU_PREFIX 0x0060
44#define REG_WAIT_TIME 50
45
46#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
47#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR
48#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR
49#endif
50
51#define REG_RULE_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
52
53#define REG_RULE_2467_2472 REG_RULE(2467-10, 2472+10, 40, 0, 20, \
54 NL80211_RRF_PASSIVE_SCAN)
55
56#define REG_RULE_2484 REG_RULE(2484-10, 2484+10, 40, 0, 20, \
57 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)
58
59#define REG_RULE_5180_5320 REG_RULE(5180-10, 5320+10, 80, 0, 20, \
60 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
61
62#define REG_RULE_5500_5720 REG_RULE(5500-10, 5720+10, 80, 0, 20, \
63 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
64
65#define REG_RULE_5745_5925 REG_RULE(5745-10, 5925+10, 80, 0, 20, \
66 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
67
68static bool init_by_driver;
69static bool init_by_reg_core;
70
71static const struct ieee80211_regdomain
72hdd_world_regrules_60_61_62 = {
73 .n_reg_rules = 6,
74 .alpha2 = "00",
75 .reg_rules = {
76 REG_RULE_2412_2462,
77 REG_RULE_2467_2472,
78 REG_RULE_2484,
79 REG_RULE_5180_5320,
80 REG_RULE_5500_5720,
81 REG_RULE_5745_5925,
82 }
83};
84
85static const struct ieee80211_regdomain
86hdd_world_regrules_63_65 = {
87 .n_reg_rules = 4,
88 .alpha2 = "00",
89 .reg_rules = {
90 REG_RULE_2412_2462,
91 REG_RULE_2467_2472,
92 REG_RULE_5180_5320,
93 REG_RULE_5745_5925,
94 }
95};
96
97static const struct ieee80211_regdomain
98hdd_world_regrules_64 = {
99 .n_reg_rules = 3,
100 .alpha2 = "00",
101 .reg_rules = {
102 REG_RULE_2412_2462,
103 REG_RULE_5180_5320,
104 REG_RULE_5745_5925,
105 }
106};
107
108static const struct ieee80211_regdomain
109hdd_world_regrules_66_69 = {
110 .n_reg_rules = 4,
111 .alpha2 = "00",
112 .reg_rules = {
113 REG_RULE_2412_2462,
114 REG_RULE_5180_5320,
115 REG_RULE_5500_5720,
116 REG_RULE_5745_5925,
117 }
118};
119
120static const struct ieee80211_regdomain
121hdd_world_regrules_67_68_6A_6C = {
122 .n_reg_rules = 5,
123 .alpha2 = "00",
124 .reg_rules = {
125 REG_RULE_2412_2462,
126 REG_RULE_2467_2472,
127 REG_RULE_5180_5320,
128 REG_RULE_5500_5720,
129 REG_RULE_5745_5925,
130 }
131};
132
133/**
134 * hdd_get_world_regrules() - get the appropriate world regrules
135 * @reg: regulatory data
136 *
137 * Return: regulatory rules ptr
138 */
139static const struct ieee80211_regdomain *hdd_get_world_regrules(
140struct regulatory *reg)
141{
Amar Singhal22995112016-01-22 10:42:33 -0800142 struct reg_dmn_pair *regpair =
143 (struct reg_dmn_pair *)reg->regpair;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700144
Amar Singhala7bb01b2016-01-27 11:31:59 -0800145 switch (regpair->reg_dmn_pair) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700146 case 0x60:
147 case 0x61:
148 case 0x62:
149 return &hdd_world_regrules_60_61_62;
150 case 0x63:
151 case 0x65:
152 return &hdd_world_regrules_63_65;
153 case 0x64:
154 return &hdd_world_regrules_64;
155 case 0x66:
156 case 0x69:
157 return &hdd_world_regrules_66_69;
158 case 0x67:
159 case 0x68:
160 case 0x6A:
161 case 0x6C:
162 return &hdd_world_regrules_67_68_6A_6C;
163 default:
164 hdd_warn("invalid world mode in BDF");
165 return &hdd_world_regrules_60_61_62;
166 }
167}
168
169/**
170 * hdd_is_world_regdomain() - whether world regdomain
171 * @reg_domain: integer regulatory domain
172 *
173 * Return: bool
174 */
175bool hdd_is_world_regdomain(uint32_t reg_domain)
176{
177 uint32_t temp_regd = reg_domain & ~WORLDWIDE_ROAMING_FLAG;
178
179 return ((temp_regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) &&
180 (((temp_regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||
181 (temp_regd == WORLD));
182}
183
184
185/**
186 * hdd_update_regulatory_info() - update regulatory info
187 * @hdd_ctx: hdd context
188 *
189 * Return: void
190 */
191static void hdd_update_regulatory_info(hdd_context_t *hdd_ctx)
192{
193 uint32_t country_code;
194
195 country_code = cds_get_country_from_alpha2(hdd_ctx->reg.alpha2);
196
197 hdd_ctx->reg.reg_domain = COUNTRY_ERD_FLAG;
198 hdd_ctx->reg.reg_domain |= country_code;
199
200 cds_fill_some_regulatory_info(&hdd_ctx->reg);
201
202}
203
204/**
205 * hdd_regulatory_wiphy_init() - regulatory wiphy init
206 * @hdd_ctx: hdd context
207 * @reg: regulatory data
208 * @wiphy: wiphy structure
209 *
210 * Return: void
211 */
212#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
213static void hdd_regulatory_wiphy_init(hdd_context_t *hdd_ctx,
214 struct regulatory *reg,
215 struct wiphy *wiphy)
216{
217 const struct ieee80211_regdomain *reg_rules;
218
219 if (hdd_is_world_regdomain(reg->reg_domain)) {
220 reg_rules = hdd_get_world_regrules(reg);
221 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
222 } else if (hdd_ctx->config->fRegChangeDefCountry) {
223 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
224 reg_rules = &hdd_world_regrules_60_61_62;
225 } else {
226 wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
227 reg_rules = &hdd_world_regrules_60_61_62;
228 }
229
230 /*
231 * save the original driver regulatory flags
232 */
233 hdd_ctx->reg.reg_flags = wiphy->regulatory_flags;
234 wiphy_apply_custom_regulatory(wiphy, reg_rules);
235
236 /*
237 * restore the driver regulatory flags since
238 * wiphy_apply_custom_regulatory may have
239 * changed them
240 */
241 wiphy->regulatory_flags = hdd_ctx->reg.reg_flags;
242
243}
244#else
245static void hdd_regulatory_wiphy_init(hdd_context_t *hdd_ctx,
246 struct regulatory *reg,
247 struct wiphy *wiphy)
248{
249 const struct ieee80211_regdomain *reg_rules;
250
251 if (hdd_is_world_regdomain(reg->reg_domain)) {
252 reg_rules = hdd_get_world_regrules(reg);
253 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
254 } else if (hdd_ctx->config->fRegChangeDefCountry) {
255 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
256 reg_rules = &hdd_world_regrules_60_61_62;
257 } else {
258 wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
259 reg_rules = &hdd_world_regrules_60_61_62;
260 }
261
262 /*
263 * save the original driver regulatory flags
264 */
265 hdd_ctx->reg.reg_flags = wiphy->flags;
266 wiphy_apply_custom_regulatory(wiphy, reg_rules);
267
268 /*
269 * restore the driver regulatory flags since
270 * wiphy_apply_custom_regulatory may have
271 * changed them
272 */
273 wiphy->flags = hdd_ctx->reg.reg_flags;
274
275}
276#endif
277
278/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700279 * is_wiphy_custom_regulatory() - is custom regulatory defined
280 * @wiphy: wiphy
281 *
282 * Return: int
283 */
284#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
285static int is_wiphy_custom_regulatory(struct wiphy *wiphy)
286{
287
288 return wiphy->regulatory_flags & REGULATORY_CUSTOM_REG;
289}
290#else
291static int is_wiphy_custom_regulatory(struct wiphy *wiphy)
292{
293 return wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY;
294}
295#endif
296
297
298/**
299 * hdd_modify_wiphy() - modify wiphy
300 * @wiphy: wiphy
301 * @chan: channel structure
302 *
303 * Return: void
304 */
305static void hdd_modify_wiphy(struct wiphy *wiphy,
306 struct ieee80211_channel *chan)
307{
308 const struct ieee80211_reg_rule *reg_rule;
309
310 if (is_wiphy_custom_regulatory(wiphy)) {
311 reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
312 if (!IS_ERR(reg_rule)) {
313 chan->flags &= ~IEEE80211_CHAN_DISABLED;
314
315 if (!(reg_rule->flags & NL80211_RRF_DFS)) {
316 hdd_info("%s: remove dfs restriction for %u",
317 __func__, chan->center_freq);
318 chan->flags &= ~IEEE80211_CHAN_RADAR;
319 }
320
321 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) {
322 hdd_info("%s: remove passive restriction for %u",
323 __func__, chan->center_freq);
324 chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
325 }
326
327 if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) {
328 hdd_info("%s: remove no ibss restriction for %u",
329 __func__, chan->center_freq);
330 chan->flags &= ~IEEE80211_CHAN_NO_IBSS;
331 }
332
333 chan->max_power =
334 MBM_TO_DBM(reg_rule->power_rule.max_eirp);
335 }
336 }
337}
338
339/**
340 * hdd_process_regulatory_data() - process regulatory data
341 * @hdd_ctx: hdd context
342 * @wiphy: wiphy
343 * @reset: whether to reset channel data
344 *
345 * Return: void
346 */
347static void hdd_process_regulatory_data(hdd_context_t *hdd_ctx,
348 struct wiphy *wiphy,
349 bool reset)
350{
Amar Singhal388b3f02016-02-10 13:37:18 -0800351 int band_num;
352 int chan_num;
353 int chan_enum = 0;
354 struct ieee80211_channel *wiphy_chan;
355 struct regulatory_channel *cds_chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700356 uint8_t band_capability;
357
358 band_capability = hdd_ctx->config->nBandCapability;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700359 hdd_ctx->isVHT80Allowed = 0;
360
Amar Singhal388b3f02016-02-10 13:37:18 -0800361 for (band_num = 0; band_num < IEEE80211_NUM_BANDS; band_num++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700362
Amar Singhal388b3f02016-02-10 13:37:18 -0800363 if (band_num == IEEE80211_BAND_2GHZ &&
Amar Singhale4f28ee2015-10-21 14:36:56 -0700364 band_capability == eCSR_BAND_5G)
365 continue;
366
Amar Singhal388b3f02016-02-10 13:37:18 -0800367 else if (band_num == IEEE80211_BAND_5GHZ &&
Amar Singhale4f28ee2015-10-21 14:36:56 -0700368 band_capability == eCSR_BAND_24)
369 continue;
370
Amar Singhal388b3f02016-02-10 13:37:18 -0800371 if (wiphy->bands[band_num] == NULL)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700372 continue;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700373
Amar Singhal388b3f02016-02-10 13:37:18 -0800374 for (chan_num = 0;
375 chan_num < wiphy->bands[band_num]->n_channels;
376 chan_num++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700377
Amar Singhal388b3f02016-02-10 13:37:18 -0800378 wiphy_chan =
379 &(wiphy->bands[band_num]->channels[chan_num]);
380 cds_chan = &(reg_channels[chan_enum]);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700381
Amar Singhal388b3f02016-02-10 13:37:18 -0800382 chan_enum++;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700383
384 if (!reset)
Amar Singhal388b3f02016-02-10 13:37:18 -0800385 hdd_modify_wiphy(wiphy, wiphy_chan);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700386
Amar Singhal388b3f02016-02-10 13:37:18 -0800387 if (wiphy_chan->flags & IEEE80211_CHAN_DISABLED) {
388 cds_chan->state = CHANNEL_STATE_DISABLE;
389 } else if (wiphy_chan->flags &
Amar Singhale4f28ee2015-10-21 14:36:56 -0700390 (IEEE80211_CHAN_RADAR |
391 IEEE80211_CHAN_PASSIVE_SCAN |
392 IEEE80211_CHAN_INDOOR_ONLY)) {
393
Amar Singhal388b3f02016-02-10 13:37:18 -0800394 if (wiphy_chan->flags &
Amar Singhale4f28ee2015-10-21 14:36:56 -0700395 IEEE80211_CHAN_INDOOR_ONLY)
Amar Singhal388b3f02016-02-10 13:37:18 -0800396 wiphy_chan->flags |=
Amar Singhale4f28ee2015-10-21 14:36:56 -0700397 IEEE80211_CHAN_PASSIVE_SCAN;
Amar Singhal388b3f02016-02-10 13:37:18 -0800398 cds_chan->state = CHANNEL_STATE_DFS;
399 if ((wiphy_chan->flags &
Amar Singhale4f28ee2015-10-21 14:36:56 -0700400 IEEE80211_CHAN_NO_80MHZ) == 0)
401 hdd_ctx->isVHT80Allowed = 1;
402 } else {
Amar Singhal388b3f02016-02-10 13:37:18 -0800403 cds_chan->state = CHANNEL_STATE_ENABLE;
404 if ((wiphy_chan->flags &
Amar Singhale4f28ee2015-10-21 14:36:56 -0700405 IEEE80211_CHAN_NO_80MHZ) == 0)
406 hdd_ctx->isVHT80Allowed = 1;
407 }
Amar Singhal388b3f02016-02-10 13:37:18 -0800408 cds_chan->pwr_limit = wiphy_chan->max_power;
409 cds_chan->flags = wiphy_chan->flags;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700410 }
411 }
412
413 if (0 == (hdd_ctx->reg.eeprom_rd_ext &
414 (1 << WHAL_REG_EXT_FCC_CH_144))) {
Amar Singhal388b3f02016-02-10 13:37:18 -0800415 cds_chan = &(reg_channels[CHAN_ENUM_144]);
416 cds_chan->state = CHANNEL_STATE_DISABLE;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700417 }
Amar Singhale4f28ee2015-10-21 14:36:56 -0700418}
419
420
421/**
422 * hdd_regulatory_init() - regulatory_init
423 * @hdd_ctx: hdd context
424 * @wiphy: wiphy
425 *
426 * Return: int
427 */
428int hdd_regulatory_init(hdd_context_t *hdd_ctx, struct wiphy *wiphy)
429{
430 int ret_val;
431 struct regulatory *reg_info;
432
433 reg_info = &hdd_ctx->reg;
434
435 hdd_regulatory_wiphy_init(hdd_ctx, reg_info, wiphy);
436
437 hdd_process_regulatory_data(hdd_ctx, wiphy, true);
438
439 reg_info->cc_src = SOURCE_DRIVER;
440
441 ret_val = cds_fill_some_regulatory_info(reg_info);
442 if (ret_val) {
443 hdd_err("incorrect BDF regulatory data");
444 return ret_val;
445 }
446
447 cds_put_default_country(reg_info->alpha2);
448
449 init_completion(&hdd_ctx->reg_init);
450
451 cds_fill_and_send_ctl_to_fw(reg_info);
452
453 return 0;
454}
455
456/**
457 * hdd_program_country_code() - process channel information from country code
458 * @hdd_ctx: hddc context
459 *
460 * Return: void
461 */
462void hdd_program_country_code(hdd_context_t *hdd_ctx)
463{
464 struct wiphy *wiphy = hdd_ctx->wiphy;
465 uint8_t *country_alpha2 = hdd_ctx->reg.alpha2;
466
467 if (false == init_by_reg_core) {
468 init_by_driver = true;
469 if (('0' != country_alpha2[0]) ||
470 ('0' != country_alpha2[1])) {
471 INIT_COMPLETION(hdd_ctx->reg_init);
472 regulatory_hint(wiphy, country_alpha2);
473 wait_for_completion_timeout(&hdd_ctx->reg_init,
474 msecs_to_jiffies(REG_WAIT_TIME));
475 }
476 }
477}
478
479
480/**
481 * hdd_set_dfs_region() - set the dfs_region
482 * @dfs_region: the dfs_region to set
483 *
484 * Return: void
485 */
486#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
487static void hdd_set_dfs_region(hdd_context_t *hdd_ctx,
488 uint8_t dfs_reg)
489{
490 cds_put_dfs_region(dfs_reg);
491}
492#else
493static void hdd_set_dfs_region(hdd_context_t *hdd_ctx,
494 uint8_t dfs_reg)
495{
496
497 /* remap the ctl code to dfs region code */
498 switch (hdd_ctx->reg.ctl_5g) {
499 case FCC:
Amar Singhala7bb01b2016-01-27 11:31:59 -0800500 cds_put_dfs_region(DFS_FCC_REGION);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700501 break;
502 case ETSI:
Amar Singhala7bb01b2016-01-27 11:31:59 -0800503 cds_put_dfs_region(DFS_ETSI_REGION);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700504 break;
505 case MKK:
Amar Singhala7bb01b2016-01-27 11:31:59 -0800506 cds_put_dfs_region(DFS_MKK_REGION);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700507 break;
508 default:
509 /* set default dfs_region to FCC */
Amar Singhala7bb01b2016-01-27 11:31:59 -0800510 cds_put_dfs_region(DFS_FCC_REGION);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700511 break;
512 }
513
514}
515#endif
516
517/**
518 * hdd_restore_custom_reg_settings() - restore custom reg settings
519 * @wiphy: wiphy structure
520 * @country_alpha2: alpha2 of the country
521 * @reset: whether wiphy is reset
522 *
523 * Return: void
524 */
525#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
526static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
527 uint8_t *country_alpha2,
528 bool *reset)
529{
530}
531#else
532static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
533 uint8_t *country_alpha2,
534 bool *reset)
535{
536 struct ieee80211_supported_band *sband;
537 enum ieee80211_band band;
538 struct ieee80211_channel *chan;
539 int i;
540
541 if ((country_alpha2[0] == '0') &&
542 (country_alpha2[1] == '0') &&
543 (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) {
544
545 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
546 sband = wiphy->bands[band];
547 if (!sband)
548 continue;
549 for (i = 0; i < sband->n_channels; i++) {
550 chan = &sband->channels[i];
551 chan->flags = chan->orig_flags;
552 chan->max_antenna_gain = chan->orig_mag;
553 chan->max_power = chan->orig_mpwr;
554 }
555 }
556 *reset = true;
557 }
558}
559#endif
560
561
562/**
563 * hdd_restore_reg_flags() - restore regulatory flags
564 * @flags: regulatory flags
565 *
566 * Return: void
567 */
568#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
569static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
570{
571 wiphy->regulatory_flags = flags;
572}
573#else
574static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
575{
576 wiphy->flags = flags;
577}
578#endif
579
580
581/**
582 * hdd_reg_notifier() - regulatory notifier
583 * @wiphy: wiphy
584 * @request: regulatory request
585 *
586 * Return: void
587 */
588void hdd_reg_notifier(struct wiphy *wiphy,
589 struct regulatory_request *request)
590{
591 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
592 eCsrBand band_capability = eCSR_BAND_ALL;
593 bool vht80_allowed;
594 bool reset = false;
595 uint8_t dfs_reg;
596
597 hdd_info("country: %c%c, initiator %d, dfs_region: %d",
598 request->alpha2[0],
599 request->alpha2[1],
600 request->initiator,
601 request->dfs_region);
602
603 if (NULL == hdd_ctx) {
604 hdd_err("invalid hdd_ctx pointer");
605 return;
606 }
607
608 if (cds_is_driver_unloading() || cds_is_driver_recovering()) {
609 hdd_err("%s: unloading or ssr in progress, ignore",
610 __func__);
611 return;
612 }
613
614 sme_get_freq_band(hdd_ctx->hHal, &band_capability);
615
616 /* first check if this callback is in response to the driver callback */
617
618 switch (request->initiator) {
619 case NL80211_REGDOM_SET_BY_DRIVER:
620 case NL80211_REGDOM_SET_BY_CORE:
621 case NL80211_REGDOM_SET_BY_USER:
622
623 if ((false == init_by_driver) &&
624 (false == init_by_reg_core)) {
625
626 if (NL80211_REGDOM_SET_BY_CORE == request->initiator)
627 return;
628 init_by_reg_core = true;
629 }
630
631 if ((NL80211_REGDOM_SET_BY_DRIVER == request->initiator) &&
632 (true == init_by_driver)) {
633
634 /*
635 * restore the driver regulatory flags since
636 * regulatory_hint may have
637 * changed them
638 */
639 hdd_restore_reg_flags(wiphy, hdd_ctx->reg.reg_flags);
640 }
641
642 if (NL80211_REGDOM_SET_BY_CORE == request->initiator) {
643 hdd_ctx->reg.cc_src = SOURCE_CORE;
644 if (is_wiphy_custom_regulatory(wiphy))
645 reset = true;
646 } else if (NL80211_REGDOM_SET_BY_DRIVER == request->initiator)
647 hdd_ctx->reg.cc_src = SOURCE_DRIVER;
648 else {
649 hdd_ctx->reg.cc_src = SOURCE_USERSPACE;
650 hdd_restore_custom_reg_settings(wiphy,
651 request->alpha2,
652 &reset);
653 }
654
655 hdd_ctx->reg.alpha2[0] = request->alpha2[0];
656 hdd_ctx->reg.alpha2[1] = request->alpha2[1];
657
658 hdd_update_regulatory_info(hdd_ctx);
659
660 vht80_allowed = hdd_ctx->isVHT80Allowed;
661
662 hdd_process_regulatory_data(hdd_ctx, wiphy, reset);
663
664 if (hdd_ctx->isVHT80Allowed != vht80_allowed)
665 hdd_checkandupdate_phymode(hdd_ctx);
666
667 if (NL80211_REGDOM_SET_BY_DRIVER == request->initiator)
668 complete(&hdd_ctx->reg_init);
669
670 sme_generic_change_country_code(hdd_ctx->hHal,
671 hdd_ctx->reg.alpha2);
672
673 cds_fill_and_send_ctl_to_fw(&hdd_ctx->reg);
674
675 hdd_set_dfs_region(hdd_ctx, request->dfs_region);
676
677 cds_get_dfs_region(&dfs_reg);
678 cds_set_wma_dfs_region(dfs_reg);
679 break;
680
681 default:
682 break;
683 }
684}