blob: 133d229d8c314e69a98d01a4ee219efb5a921fa4 [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"
Amar Singhal604ba6cf2016-07-27 15:29:51 -070036#include "cds_regdomain.h"
Amar Singhale4f28ee2015-10-21 14:36:56 -070037#include "qdf_trace.h"
38#include "sme_api.h"
39#include "wlan_hdd_main.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
Amar Singhale4f28ee2015-10-21 14:36:56 -070044
45#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
46#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR
47#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR
48#endif
49
50#define REG_RULE_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
51
52#define REG_RULE_2467_2472 REG_RULE(2467-10, 2472+10, 40, 0, 20, \
Amar Singhale4f28ee2015-10-21 14:36:56 -070053 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
54
Amar Singhal1c944922016-03-23 18:46:49 -070055#define REG_RULE_2484 REG_RULE(2484-10, 2484+10, 20, 0, 20, \
56 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | \
57 NL80211_RRF_NO_OFDM)
58
59#define REG_RULE_5180_5320 REG_RULE(5180-10, 5320+10, 160, 0, 20, \
60 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
61
62#define REG_RULE_5500_5720 REG_RULE(5500-10, 5720+10, 160, 0, 20, \
Amar Singhale4f28ee2015-10-21 14:36:56 -070063 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 */
Jeff Johnson87a24252016-10-05 16:20:52 -0700175static bool hdd_is_world_regdomain(uint32_t reg_domain)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700176{
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/**
Abhishek Singh3e6172f2016-05-04 16:56:48 +0530205 * hdd_reset_global_reg_params - Reset global static reg params
206 *
207 * This function is helpful in static driver to reset
208 * the global params.
209 *
210 * Return: void
211 */
212void hdd_reset_global_reg_params(void)
213{
214 init_by_driver = false;
215 init_by_reg_core = false;
216}
217
218/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700219 * hdd_regulatory_wiphy_init() - regulatory wiphy init
220 * @hdd_ctx: hdd context
221 * @reg: regulatory data
222 * @wiphy: wiphy structure
223 *
224 * Return: void
225 */
226#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
227static void hdd_regulatory_wiphy_init(hdd_context_t *hdd_ctx,
228 struct regulatory *reg,
229 struct wiphy *wiphy)
230{
231 const struct ieee80211_regdomain *reg_rules;
Amar Singhalb7fe2612016-10-19 10:49:58 -0700232 int chan_num;
233 struct ieee80211_channel chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700234
235 if (hdd_is_world_regdomain(reg->reg_domain)) {
236 reg_rules = hdd_get_world_regrules(reg);
237 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
238 } else if (hdd_ctx->config->fRegChangeDefCountry) {
239 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
240 reg_rules = &hdd_world_regrules_60_61_62;
241 } else {
242 wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
243 reg_rules = &hdd_world_regrules_60_61_62;
244 }
245
246 /*
247 * save the original driver regulatory flags
248 */
249 hdd_ctx->reg.reg_flags = wiphy->regulatory_flags;
250 wiphy_apply_custom_regulatory(wiphy, reg_rules);
251
252 /*
Amar Singhalb7fe2612016-10-19 10:49:58 -0700253 * disable 2.4 Ghz channels that dont have 20 mhz bw
254 */
255 for (chan_num = 0;
256 chan_num < wiphy->bands[IEEE80211_BAND_2GHZ]->n_channels;
257 chan_num++) {
258 chan = wiphy->bands[IEEE80211_BAND_2GHZ]->channels[chan_num];
259 if (chan.flags & IEEE80211_CHAN_NO_20MHZ)
260 chan.flags |= IEEE80211_CHAN_DISABLED;
261 }
262
263 /*
Amar Singhale4f28ee2015-10-21 14:36:56 -0700264 * restore the driver regulatory flags since
265 * wiphy_apply_custom_regulatory may have
266 * changed them
267 */
268 wiphy->regulatory_flags = hdd_ctx->reg.reg_flags;
269
270}
271#else
272static void hdd_regulatory_wiphy_init(hdd_context_t *hdd_ctx,
273 struct regulatory *reg,
274 struct wiphy *wiphy)
275{
276 const struct ieee80211_regdomain *reg_rules;
277
278 if (hdd_is_world_regdomain(reg->reg_domain)) {
279 reg_rules = hdd_get_world_regrules(reg);
280 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
281 } else if (hdd_ctx->config->fRegChangeDefCountry) {
282 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
283 reg_rules = &hdd_world_regrules_60_61_62;
284 } else {
285 wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
286 reg_rules = &hdd_world_regrules_60_61_62;
287 }
288
289 /*
290 * save the original driver regulatory flags
291 */
292 hdd_ctx->reg.reg_flags = wiphy->flags;
293 wiphy_apply_custom_regulatory(wiphy, reg_rules);
294
295 /*
296 * restore the driver regulatory flags since
297 * wiphy_apply_custom_regulatory may have
298 * changed them
299 */
300 wiphy->flags = hdd_ctx->reg.reg_flags;
301
302}
303#endif
304
305/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700306 * is_wiphy_custom_regulatory() - is custom regulatory defined
307 * @wiphy: wiphy
308 *
309 * Return: int
310 */
311#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
312static int is_wiphy_custom_regulatory(struct wiphy *wiphy)
313{
314
315 return wiphy->regulatory_flags & REGULATORY_CUSTOM_REG;
316}
317#else
318static int is_wiphy_custom_regulatory(struct wiphy *wiphy)
319{
320 return wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY;
321}
322#endif
323
324
325/**
326 * hdd_modify_wiphy() - modify wiphy
327 * @wiphy: wiphy
328 * @chan: channel structure
329 *
330 * Return: void
331 */
332static void hdd_modify_wiphy(struct wiphy *wiphy,
333 struct ieee80211_channel *chan)
334{
335 const struct ieee80211_reg_rule *reg_rule;
336
337 if (is_wiphy_custom_regulatory(wiphy)) {
338 reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
339 if (!IS_ERR(reg_rule)) {
340 chan->flags &= ~IEEE80211_CHAN_DISABLED;
341
342 if (!(reg_rule->flags & NL80211_RRF_DFS)) {
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530343 hdd_info("Remove dfs restriction for %u",
344 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700345 chan->flags &= ~IEEE80211_CHAN_RADAR;
346 }
347
348 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) {
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530349 hdd_info("Remove passive restriction for %u",
350 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700351 chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
352 }
353
354 if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) {
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530355 hdd_info("Remove no ibss restriction for %u",
356 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700357 chan->flags &= ~IEEE80211_CHAN_NO_IBSS;
358 }
359
360 chan->max_power =
361 MBM_TO_DBM(reg_rule->power_rule.max_eirp);
362 }
363 }
364}
365
366/**
367 * hdd_process_regulatory_data() - process regulatory data
368 * @hdd_ctx: hdd context
369 * @wiphy: wiphy
370 * @reset: whether to reset channel data
371 *
372 * Return: void
373 */
374static void hdd_process_regulatory_data(hdd_context_t *hdd_ctx,
375 struct wiphy *wiphy,
376 bool reset)
377{
Amar Singhal388b3f02016-02-10 13:37:18 -0800378 int band_num;
379 int chan_num;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700380 enum channel_enum chan_enum = CHAN_ENUM_1;
381 struct ieee80211_channel *wiphy_chan, *wiphy_chan_144 = NULL;
Amar Singhal388b3f02016-02-10 13:37:18 -0800382 struct regulatory_channel *cds_chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700383 uint8_t band_capability;
384
385 band_capability = hdd_ctx->config->nBandCapability;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700386
Dustin Browna30892e2016-10-12 17:28:36 -0700387 for (band_num = 0; band_num < NUM_NL80211_BANDS; band_num++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700388
Amar Singhal388b3f02016-02-10 13:37:18 -0800389 if (wiphy->bands[band_num] == NULL)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700390 continue;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700391
Amar Singhal388b3f02016-02-10 13:37:18 -0800392 for (chan_num = 0;
393 chan_num < wiphy->bands[band_num]->n_channels;
394 chan_num++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700395
Amar Singhal388b3f02016-02-10 13:37:18 -0800396 wiphy_chan =
397 &(wiphy->bands[band_num]->channels[chan_num]);
398 cds_chan = &(reg_channels[chan_enum]);
Amar Singhalb2cb3002016-08-11 16:10:36 -0700399 if (CHAN_ENUM_144 == chan_enum)
400 wiphy_chan_144 = wiphy_chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700401
Amar Singhal388b3f02016-02-10 13:37:18 -0800402 chan_enum++;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700403
404 if (!reset)
Amar Singhal388b3f02016-02-10 13:37:18 -0800405 hdd_modify_wiphy(wiphy, wiphy_chan);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700406
Amar Singhal388b3f02016-02-10 13:37:18 -0800407 if (wiphy_chan->flags & IEEE80211_CHAN_DISABLED) {
408 cds_chan->state = CHANNEL_STATE_DISABLE;
Amar Singhal18517882016-08-08 12:26:20 -0700409 } else if ((wiphy_chan->flags &
410 (IEEE80211_CHAN_RADAR |
411 IEEE80211_CHAN_PASSIVE_SCAN)) ||
412 ((hdd_ctx->config->indoor_channel_support
413 == false) &&
414 (wiphy_chan->flags &
415 IEEE80211_CHAN_INDOOR_ONLY))) {
416 if ((wiphy_chan->flags &
417 IEEE80211_CHAN_INDOOR_ONLY) &&
418 (false ==
419 hdd_ctx->config->indoor_channel_support))
Amar Singhal388b3f02016-02-10 13:37:18 -0800420 wiphy_chan->flags |=
Amar Singhale4f28ee2015-10-21 14:36:56 -0700421 IEEE80211_CHAN_PASSIVE_SCAN;
Amar Singhal388b3f02016-02-10 13:37:18 -0800422 cds_chan->state = CHANNEL_STATE_DFS;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700423 } else {
Amar Singhal388b3f02016-02-10 13:37:18 -0800424 cds_chan->state = CHANNEL_STATE_ENABLE;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700425 }
Amar Singhal388b3f02016-02-10 13:37:18 -0800426 cds_chan->pwr_limit = wiphy_chan->max_power;
427 cds_chan->flags = wiphy_chan->flags;
Amar Singhal1c944922016-03-23 18:46:49 -0700428
Amar Singhale4f28ee2015-10-21 14:36:56 -0700429 }
430 }
431
432 if (0 == (hdd_ctx->reg.eeprom_rd_ext &
433 (1 << WHAL_REG_EXT_FCC_CH_144))) {
Amar Singhal388b3f02016-02-10 13:37:18 -0800434 cds_chan = &(reg_channels[CHAN_ENUM_144]);
435 cds_chan->state = CHANNEL_STATE_DISABLE;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700436 if (NULL != wiphy_chan_144)
437 wiphy_chan_144->flags |= IEEE80211_CHAN_DISABLED;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700438 }
Amar Singhal6842e8f2016-02-23 16:30:32 -0800439
440 wlan_hdd_cfg80211_update_band(wiphy, band_capability);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700441}
442
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700443/**
444 * hdd_set_dfs_region() - set the dfs_region
445 * @dfs_region: the dfs_region to set
446 *
447 * Return: void
448 */
449#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
450static void hdd_set_dfs_region(hdd_context_t *hdd_ctx,
451 enum dfs_region dfs_reg)
452{
453 cds_put_dfs_region(dfs_reg);
454}
455#else
456static void hdd_set_dfs_region(hdd_context_t *hdd_ctx,
457 enum dfs_region dfs_reg)
458{
459
460 /* remap the ctl code to dfs region code */
461 switch (hdd_ctx->reg.ctl_5g) {
462 case FCC:
463 cds_put_dfs_region(DFS_FCC_REGION);
464 break;
465 case ETSI:
466 cds_put_dfs_region(DFS_ETSI_REGION);
467 break;
468 case MKK:
469 cds_put_dfs_region(DFS_MKK_REGION);
470 break;
471 default:
472 /* set default dfs_region to FCC */
473 cds_put_dfs_region(DFS_FCC_REGION);
474 break;
475 }
476
477}
478#endif
479
Amar Singhale4f28ee2015-10-21 14:36:56 -0700480
481/**
482 * hdd_regulatory_init() - regulatory_init
483 * @hdd_ctx: hdd context
484 * @wiphy: wiphy
485 *
486 * Return: int
487 */
488int hdd_regulatory_init(hdd_context_t *hdd_ctx, struct wiphy *wiphy)
489{
490 int ret_val;
491 struct regulatory *reg_info;
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700492 enum dfs_region dfs_reg;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700493
494 reg_info = &hdd_ctx->reg;
495
Amar Singhale4f28ee2015-10-21 14:36:56 -0700496 ret_val = cds_fill_some_regulatory_info(reg_info);
497 if (ret_val) {
498 hdd_err("incorrect BDF regulatory data");
499 return ret_val;
500 }
501
Dustin Brown38f2b552016-10-04 13:57:46 -0700502 hdd_regulatory_wiphy_init(hdd_ctx, reg_info, wiphy);
503
504 hdd_process_regulatory_data(hdd_ctx, wiphy, true);
505
506 reg_info->cc_src = SOURCE_DRIVER;
507
Amar Singhale4f28ee2015-10-21 14:36:56 -0700508 cds_put_default_country(reg_info->alpha2);
509
Amar Singhale4f28ee2015-10-21 14:36:56 -0700510 cds_fill_and_send_ctl_to_fw(reg_info);
511
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700512 hdd_set_dfs_region(hdd_ctx, DFS_FCC_REGION);
513 cds_get_dfs_region(&dfs_reg);
514 cds_set_wma_dfs_region(dfs_reg);
515
Amar Singhale4f28ee2015-10-21 14:36:56 -0700516 return 0;
517}
518
519/**
520 * hdd_program_country_code() - process channel information from country code
521 * @hdd_ctx: hddc context
522 *
523 * Return: void
524 */
525void hdd_program_country_code(hdd_context_t *hdd_ctx)
526{
527 struct wiphy *wiphy = hdd_ctx->wiphy;
528 uint8_t *country_alpha2 = hdd_ctx->reg.alpha2;
529
530 if (false == init_by_reg_core) {
531 init_by_driver = true;
532 if (('0' != country_alpha2[0]) ||
Amar Singhal38c5eeb2016-08-22 16:50:01 -0700533 ('0' != country_alpha2[1]))
Amar Singhale4f28ee2015-10-21 14:36:56 -0700534 regulatory_hint(wiphy, country_alpha2);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700535 }
536}
537
538
539/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700540 * hdd_restore_custom_reg_settings() - restore custom reg settings
541 * @wiphy: wiphy structure
542 * @country_alpha2: alpha2 of the country
543 * @reset: whether wiphy is reset
544 *
545 * Return: void
546 */
547#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
548static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
549 uint8_t *country_alpha2,
550 bool *reset)
551{
552}
553#else
554static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
555 uint8_t *country_alpha2,
556 bool *reset)
557{
558 struct ieee80211_supported_band *sband;
Dustin Browna30892e2016-10-12 17:28:36 -0700559 enum nl80211_band band;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700560 struct ieee80211_channel *chan;
561 int i;
562
563 if ((country_alpha2[0] == '0') &&
564 (country_alpha2[1] == '0') &&
565 (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) {
566
Dustin Browna30892e2016-10-12 17:28:36 -0700567 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700568 sband = wiphy->bands[band];
569 if (!sband)
570 continue;
571 for (i = 0; i < sband->n_channels; i++) {
572 chan = &sband->channels[i];
573 chan->flags = chan->orig_flags;
574 chan->max_antenna_gain = chan->orig_mag;
575 chan->max_power = chan->orig_mpwr;
576 }
577 }
578 *reset = true;
579 }
580}
581#endif
582
583
584/**
585 * hdd_restore_reg_flags() - restore regulatory flags
586 * @flags: regulatory flags
587 *
588 * Return: void
589 */
590#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
591static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
592{
593 wiphy->regulatory_flags = flags;
594}
595#else
596static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
597{
598 wiphy->flags = flags;
599}
600#endif
601
602
603/**
604 * hdd_reg_notifier() - regulatory notifier
605 * @wiphy: wiphy
606 * @request: regulatory request
607 *
608 * Return: void
609 */
610void hdd_reg_notifier(struct wiphy *wiphy,
611 struct regulatory_request *request)
612{
613 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700614 bool reset = false;
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700615 enum dfs_region dfs_reg;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700616
617 hdd_info("country: %c%c, initiator %d, dfs_region: %d",
618 request->alpha2[0],
619 request->alpha2[1],
620 request->initiator,
621 request->dfs_region);
622
623 if (NULL == hdd_ctx) {
624 hdd_err("invalid hdd_ctx pointer");
625 return;
626 }
627
628 if (cds_is_driver_unloading() || cds_is_driver_recovering()) {
629 hdd_err("%s: unloading or ssr in progress, ignore",
630 __func__);
631 return;
632 }
633
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700634 if (('K' == request->alpha2[0]) &&
635 ('R' == request->alpha2[1]))
636 request->dfs_region = DFS_KR_REGION;
637
638 if (('C' == request->alpha2[0]) &&
639 ('N' == request->alpha2[1]))
640 request->dfs_region = DFS_CN_REGION;
641
Amar Singhale4f28ee2015-10-21 14:36:56 -0700642 /* first check if this callback is in response to the driver callback */
643
644 switch (request->initiator) {
645 case NL80211_REGDOM_SET_BY_DRIVER:
646 case NL80211_REGDOM_SET_BY_CORE:
647 case NL80211_REGDOM_SET_BY_USER:
648
649 if ((false == init_by_driver) &&
650 (false == init_by_reg_core)) {
651
652 if (NL80211_REGDOM_SET_BY_CORE == request->initiator)
653 return;
654 init_by_reg_core = true;
655 }
656
657 if ((NL80211_REGDOM_SET_BY_DRIVER == request->initiator) &&
658 (true == init_by_driver)) {
659
660 /*
661 * restore the driver regulatory flags since
662 * regulatory_hint may have
663 * changed them
664 */
665 hdd_restore_reg_flags(wiphy, hdd_ctx->reg.reg_flags);
666 }
667
668 if (NL80211_REGDOM_SET_BY_CORE == request->initiator) {
669 hdd_ctx->reg.cc_src = SOURCE_CORE;
670 if (is_wiphy_custom_regulatory(wiphy))
671 reset = true;
672 } else if (NL80211_REGDOM_SET_BY_DRIVER == request->initiator)
673 hdd_ctx->reg.cc_src = SOURCE_DRIVER;
674 else {
675 hdd_ctx->reg.cc_src = SOURCE_USERSPACE;
676 hdd_restore_custom_reg_settings(wiphy,
677 request->alpha2,
678 &reset);
679 }
680
681 hdd_ctx->reg.alpha2[0] = request->alpha2[0];
682 hdd_ctx->reg.alpha2[1] = request->alpha2[1];
683
684 hdd_update_regulatory_info(hdd_ctx);
685
Amar Singhale4f28ee2015-10-21 14:36:56 -0700686 hdd_process_regulatory_data(hdd_ctx, wiphy, reset);
687
Amar Singhale4f28ee2015-10-21 14:36:56 -0700688 sme_generic_change_country_code(hdd_ctx->hHal,
689 hdd_ctx->reg.alpha2);
690
691 cds_fill_and_send_ctl_to_fw(&hdd_ctx->reg);
692
693 hdd_set_dfs_region(hdd_ctx, request->dfs_region);
694
695 cds_get_dfs_region(&dfs_reg);
696 cds_set_wma_dfs_region(dfs_reg);
697 break;
698
699 default:
700 break;
701 }
702}