blob: 666bc778e6fcf65ad60ec3c8b3ba49c14aa551e5 [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"
Amar Singhal5f997862016-08-24 13:17:50 -070035#include "qdf_trace.h"
Amar Singhale4f28ee2015-10-21 14:36:56 -070036#include "cds_reg_service.h"
Amar Singhal604ba6cf2016-07-27 15:29:51 -070037#include "cds_regdomain.h"
Amar Singhale4f28ee2015-10-21 14:36:56 -070038#include "sme_api.h"
39#include "wlan_hdd_main.h"
Amar Singhale4f28ee2015-10-21 14:36:56 -070040#include "wlan_hdd_regulatory.h"
41
Amar Singhale4f28ee2015-10-21 14:36:56 -070042#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
43#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR
44#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR
45#endif
46
47#define REG_RULE_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
48
49#define REG_RULE_2467_2472 REG_RULE(2467-10, 2472+10, 40, 0, 20, \
Amar Singhale4f28ee2015-10-21 14:36:56 -070050 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
51
Amar Singhal1c944922016-03-23 18:46:49 -070052#define REG_RULE_2484 REG_RULE(2484-10, 2484+10, 20, 0, 20, \
53 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | \
54 NL80211_RRF_NO_OFDM)
55
56#define REG_RULE_5180_5320 REG_RULE(5180-10, 5320+10, 160, 0, 20, \
57 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
58
59#define REG_RULE_5500_5720 REG_RULE(5500-10, 5720+10, 160, 0, 20, \
Amar Singhale4f28ee2015-10-21 14:36:56 -070060 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
61
62#define REG_RULE_5745_5925 REG_RULE(5745-10, 5925+10, 80, 0, 20, \
63 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
64
65static bool init_by_driver;
66static bool init_by_reg_core;
67
68static const struct ieee80211_regdomain
69hdd_world_regrules_60_61_62 = {
70 .n_reg_rules = 6,
71 .alpha2 = "00",
72 .reg_rules = {
73 REG_RULE_2412_2462,
74 REG_RULE_2467_2472,
75 REG_RULE_2484,
76 REG_RULE_5180_5320,
77 REG_RULE_5500_5720,
78 REG_RULE_5745_5925,
79 }
80};
81
82static const struct ieee80211_regdomain
83hdd_world_regrules_63_65 = {
84 .n_reg_rules = 4,
85 .alpha2 = "00",
86 .reg_rules = {
87 REG_RULE_2412_2462,
88 REG_RULE_2467_2472,
89 REG_RULE_5180_5320,
90 REG_RULE_5745_5925,
91 }
92};
93
94static const struct ieee80211_regdomain
95hdd_world_regrules_64 = {
96 .n_reg_rules = 3,
97 .alpha2 = "00",
98 .reg_rules = {
99 REG_RULE_2412_2462,
100 REG_RULE_5180_5320,
101 REG_RULE_5745_5925,
102 }
103};
104
105static const struct ieee80211_regdomain
106hdd_world_regrules_66_69 = {
107 .n_reg_rules = 4,
108 .alpha2 = "00",
109 .reg_rules = {
110 REG_RULE_2412_2462,
111 REG_RULE_5180_5320,
112 REG_RULE_5500_5720,
113 REG_RULE_5745_5925,
114 }
115};
116
117static const struct ieee80211_regdomain
118hdd_world_regrules_67_68_6A_6C = {
119 .n_reg_rules = 5,
120 .alpha2 = "00",
121 .reg_rules = {
122 REG_RULE_2412_2462,
123 REG_RULE_2467_2472,
124 REG_RULE_5180_5320,
125 REG_RULE_5500_5720,
126 REG_RULE_5745_5925,
127 }
128};
129
130/**
131 * hdd_get_world_regrules() - get the appropriate world regrules
132 * @reg: regulatory data
133 *
134 * Return: regulatory rules ptr
135 */
136static const struct ieee80211_regdomain *hdd_get_world_regrules(
137struct regulatory *reg)
138{
Amar Singhal22995112016-01-22 10:42:33 -0800139 struct reg_dmn_pair *regpair =
140 (struct reg_dmn_pair *)reg->regpair;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700141
Amar Singhala7bb01b2016-01-27 11:31:59 -0800142 switch (regpair->reg_dmn_pair) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700143 case 0x60:
144 case 0x61:
145 case 0x62:
146 return &hdd_world_regrules_60_61_62;
147 case 0x63:
148 case 0x65:
149 return &hdd_world_regrules_63_65;
150 case 0x64:
151 return &hdd_world_regrules_64;
152 case 0x66:
153 case 0x69:
154 return &hdd_world_regrules_66_69;
155 case 0x67:
156 case 0x68:
157 case 0x6A:
158 case 0x6C:
159 return &hdd_world_regrules_67_68_6A_6C;
160 default:
161 hdd_warn("invalid world mode in BDF");
162 return &hdd_world_regrules_60_61_62;
163 }
164}
165
166/**
167 * hdd_is_world_regdomain() - whether world regdomain
168 * @reg_domain: integer regulatory domain
169 *
170 * Return: bool
171 */
Jeff Johnson87a24252016-10-05 16:20:52 -0700172static bool hdd_is_world_regdomain(uint32_t reg_domain)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700173{
Amar Singhal5f997862016-08-24 13:17:50 -0700174 uint32_t temp_regd = reg_domain & ~WORLD_ROAMING_FLAG;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700175
Amar Singhal5f997862016-08-24 13:17:50 -0700176 return ((temp_regd & CTRY_FLAG) != CTRY_FLAG) &&
177 ((temp_regd & WORLD_ROAMING_MASK) ==
178 WORLD_ROAMING_PREFIX);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700179}
180
181
182/**
183 * hdd_update_regulatory_info() - update regulatory info
184 * @hdd_ctx: hdd context
185 *
186 * Return: void
187 */
188static void hdd_update_regulatory_info(hdd_context_t *hdd_ctx)
189{
190 uint32_t country_code;
191
192 country_code = cds_get_country_from_alpha2(hdd_ctx->reg.alpha2);
193
Amar Singhal5f997862016-08-24 13:17:50 -0700194 hdd_ctx->reg.reg_domain = CTRY_FLAG;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700195 hdd_ctx->reg.reg_domain |= country_code;
196
197 cds_fill_some_regulatory_info(&hdd_ctx->reg);
198
199}
200
201/**
Abhishek Singh3e6172f2016-05-04 16:56:48 +0530202 * hdd_reset_global_reg_params - Reset global static reg params
203 *
204 * This function is helpful in static driver to reset
205 * the global params.
206 *
207 * Return: void
208 */
209void hdd_reset_global_reg_params(void)
210{
211 init_by_driver = false;
212 init_by_reg_core = false;
213}
214
215/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700216 * hdd_regulatory_wiphy_init() - regulatory wiphy init
217 * @hdd_ctx: hdd context
218 * @reg: regulatory data
219 * @wiphy: wiphy structure
220 *
221 * Return: void
222 */
223#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
224static void hdd_regulatory_wiphy_init(hdd_context_t *hdd_ctx,
225 struct regulatory *reg,
226 struct wiphy *wiphy)
227{
228 const struct ieee80211_regdomain *reg_rules;
Amar Singhalb7fe2612016-10-19 10:49:58 -0700229 int chan_num;
Amar Singhal6fc66382016-11-09 13:33:33 -0800230 struct ieee80211_channel *chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700231
232 if (hdd_is_world_regdomain(reg->reg_domain)) {
233 reg_rules = hdd_get_world_regrules(reg);
234 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
235 } else if (hdd_ctx->config->fRegChangeDefCountry) {
236 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
237 reg_rules = &hdd_world_regrules_60_61_62;
238 } else {
239 wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
240 reg_rules = &hdd_world_regrules_60_61_62;
241 }
242
243 /*
244 * save the original driver regulatory flags
245 */
246 hdd_ctx->reg.reg_flags = wiphy->regulatory_flags;
247 wiphy_apply_custom_regulatory(wiphy, reg_rules);
248
249 /*
Amar Singhalb7fe2612016-10-19 10:49:58 -0700250 * disable 2.4 Ghz channels that dont have 20 mhz bw
251 */
252 for (chan_num = 0;
253 chan_num < wiphy->bands[IEEE80211_BAND_2GHZ]->n_channels;
254 chan_num++) {
Amar Singhal6fc66382016-11-09 13:33:33 -0800255 chan = &(wiphy->bands[IEEE80211_BAND_2GHZ]->channels[chan_num]);
256 if (chan->flags & IEEE80211_CHAN_NO_20MHZ)
257 chan->flags |= IEEE80211_CHAN_DISABLED;
Amar Singhalb7fe2612016-10-19 10:49:58 -0700258 }
259
260 /*
Amar Singhale4f28ee2015-10-21 14:36:56 -0700261 * restore the driver regulatory flags since
262 * wiphy_apply_custom_regulatory may have
263 * changed them
264 */
265 wiphy->regulatory_flags = hdd_ctx->reg.reg_flags;
266
267}
268#else
269static void hdd_regulatory_wiphy_init(hdd_context_t *hdd_ctx,
270 struct regulatory *reg,
271 struct wiphy *wiphy)
272{
273 const struct ieee80211_regdomain *reg_rules;
274
275 if (hdd_is_world_regdomain(reg->reg_domain)) {
276 reg_rules = hdd_get_world_regrules(reg);
277 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
278 } else if (hdd_ctx->config->fRegChangeDefCountry) {
279 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
280 reg_rules = &hdd_world_regrules_60_61_62;
281 } else {
282 wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
283 reg_rules = &hdd_world_regrules_60_61_62;
284 }
285
286 /*
287 * save the original driver regulatory flags
288 */
289 hdd_ctx->reg.reg_flags = wiphy->flags;
290 wiphy_apply_custom_regulatory(wiphy, reg_rules);
291
292 /*
293 * restore the driver regulatory flags since
294 * wiphy_apply_custom_regulatory may have
295 * changed them
296 */
297 wiphy->flags = hdd_ctx->reg.reg_flags;
298
299}
300#endif
301
302/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700303 * is_wiphy_custom_regulatory() - is custom regulatory defined
304 * @wiphy: wiphy
305 *
306 * Return: int
307 */
308#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
309static int is_wiphy_custom_regulatory(struct wiphy *wiphy)
310{
311
312 return wiphy->regulatory_flags & REGULATORY_CUSTOM_REG;
313}
314#else
315static int is_wiphy_custom_regulatory(struct wiphy *wiphy)
316{
317 return wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY;
318}
319#endif
320
321
322/**
323 * hdd_modify_wiphy() - modify wiphy
324 * @wiphy: wiphy
325 * @chan: channel structure
326 *
327 * Return: void
328 */
329static void hdd_modify_wiphy(struct wiphy *wiphy,
330 struct ieee80211_channel *chan)
331{
332 const struct ieee80211_reg_rule *reg_rule;
333
334 if (is_wiphy_custom_regulatory(wiphy)) {
335 reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
336 if (!IS_ERR(reg_rule)) {
337 chan->flags &= ~IEEE80211_CHAN_DISABLED;
338
339 if (!(reg_rule->flags & NL80211_RRF_DFS)) {
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530340 hdd_info("Remove dfs restriction for %u",
341 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700342 chan->flags &= ~IEEE80211_CHAN_RADAR;
343 }
344
345 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) {
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530346 hdd_info("Remove passive restriction for %u",
347 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700348 chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
349 }
350
351 if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) {
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530352 hdd_info("Remove no ibss restriction for %u",
353 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700354 chan->flags &= ~IEEE80211_CHAN_NO_IBSS;
355 }
356
357 chan->max_power =
358 MBM_TO_DBM(reg_rule->power_rule.max_eirp);
359 }
360 }
361}
362
363/**
364 * hdd_process_regulatory_data() - process regulatory data
365 * @hdd_ctx: hdd context
366 * @wiphy: wiphy
367 * @reset: whether to reset channel data
368 *
369 * Return: void
370 */
371static void hdd_process_regulatory_data(hdd_context_t *hdd_ctx,
372 struct wiphy *wiphy,
373 bool reset)
374{
Amar Singhal388b3f02016-02-10 13:37:18 -0800375 int band_num;
376 int chan_num;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700377 enum channel_enum chan_enum = CHAN_ENUM_1;
378 struct ieee80211_channel *wiphy_chan, *wiphy_chan_144 = NULL;
Amar Singhal388b3f02016-02-10 13:37:18 -0800379 struct regulatory_channel *cds_chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700380 uint8_t band_capability;
381
382 band_capability = hdd_ctx->config->nBandCapability;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700383
Dustin Browna30892e2016-10-12 17:28:36 -0700384 for (band_num = 0; band_num < NUM_NL80211_BANDS; band_num++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700385
Amar Singhal388b3f02016-02-10 13:37:18 -0800386 if (wiphy->bands[band_num] == NULL)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700387 continue;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700388
Amar Singhal388b3f02016-02-10 13:37:18 -0800389 for (chan_num = 0;
Manjeet Singhec402062016-10-27 15:58:01 +0530390 chan_num < wiphy->bands[band_num]->n_channels &&
391 chan_enum < NUM_CHANNELS;
Amar Singhal388b3f02016-02-10 13:37:18 -0800392 chan_num++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700393
Amar Singhal388b3f02016-02-10 13:37:18 -0800394 wiphy_chan =
395 &(wiphy->bands[band_num]->channels[chan_num]);
396 cds_chan = &(reg_channels[chan_enum]);
Amar Singhalb2cb3002016-08-11 16:10:36 -0700397 if (CHAN_ENUM_144 == chan_enum)
398 wiphy_chan_144 = wiphy_chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700399
Amar Singhal388b3f02016-02-10 13:37:18 -0800400 chan_enum++;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700401
402 if (!reset)
Amar Singhal388b3f02016-02-10 13:37:18 -0800403 hdd_modify_wiphy(wiphy, wiphy_chan);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700404
Amar Singhal388b3f02016-02-10 13:37:18 -0800405 if (wiphy_chan->flags & IEEE80211_CHAN_DISABLED) {
406 cds_chan->state = CHANNEL_STATE_DISABLE;
Amar Singhal18517882016-08-08 12:26:20 -0700407 } else if ((wiphy_chan->flags &
408 (IEEE80211_CHAN_RADAR |
409 IEEE80211_CHAN_PASSIVE_SCAN)) ||
410 ((hdd_ctx->config->indoor_channel_support
411 == false) &&
412 (wiphy_chan->flags &
413 IEEE80211_CHAN_INDOOR_ONLY))) {
414 if ((wiphy_chan->flags &
415 IEEE80211_CHAN_INDOOR_ONLY) &&
416 (false ==
417 hdd_ctx->config->indoor_channel_support))
Amar Singhal388b3f02016-02-10 13:37:18 -0800418 wiphy_chan->flags |=
Amar Singhale4f28ee2015-10-21 14:36:56 -0700419 IEEE80211_CHAN_PASSIVE_SCAN;
Amar Singhal388b3f02016-02-10 13:37:18 -0800420 cds_chan->state = CHANNEL_STATE_DFS;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700421 } else {
Amar Singhal388b3f02016-02-10 13:37:18 -0800422 cds_chan->state = CHANNEL_STATE_ENABLE;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700423 }
Amar Singhal388b3f02016-02-10 13:37:18 -0800424 cds_chan->pwr_limit = wiphy_chan->max_power;
425 cds_chan->flags = wiphy_chan->flags;
Amar Singhal1c944922016-03-23 18:46:49 -0700426
Amar Singhale4f28ee2015-10-21 14:36:56 -0700427 }
428 }
429
430 if (0 == (hdd_ctx->reg.eeprom_rd_ext &
431 (1 << WHAL_REG_EXT_FCC_CH_144))) {
Amar Singhal388b3f02016-02-10 13:37:18 -0800432 cds_chan = &(reg_channels[CHAN_ENUM_144]);
433 cds_chan->state = CHANNEL_STATE_DISABLE;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700434 if (NULL != wiphy_chan_144)
435 wiphy_chan_144->flags |= IEEE80211_CHAN_DISABLED;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700436 }
Amar Singhal6842e8f2016-02-23 16:30:32 -0800437
438 wlan_hdd_cfg80211_update_band(wiphy, band_capability);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700439}
440
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700441/**
442 * hdd_set_dfs_region() - set the dfs_region
443 * @dfs_region: the dfs_region to set
444 *
445 * Return: void
446 */
447#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
448static void hdd_set_dfs_region(hdd_context_t *hdd_ctx,
449 enum dfs_region dfs_reg)
450{
451 cds_put_dfs_region(dfs_reg);
452}
453#else
454static void hdd_set_dfs_region(hdd_context_t *hdd_ctx,
455 enum dfs_region dfs_reg)
456{
457
458 /* remap the ctl code to dfs region code */
459 switch (hdd_ctx->reg.ctl_5g) {
460 case FCC:
461 cds_put_dfs_region(DFS_FCC_REGION);
462 break;
463 case ETSI:
464 cds_put_dfs_region(DFS_ETSI_REGION);
465 break;
466 case MKK:
467 cds_put_dfs_region(DFS_MKK_REGION);
468 break;
469 default:
470 /* set default dfs_region to FCC */
471 cds_put_dfs_region(DFS_FCC_REGION);
472 break;
473 }
474
475}
476#endif
477
Amar Singhale4f28ee2015-10-21 14:36:56 -0700478
479/**
480 * hdd_regulatory_init() - regulatory_init
481 * @hdd_ctx: hdd context
482 * @wiphy: wiphy
483 *
484 * Return: int
485 */
486int hdd_regulatory_init(hdd_context_t *hdd_ctx, struct wiphy *wiphy)
487{
488 int ret_val;
489 struct regulatory *reg_info;
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700490 enum dfs_region dfs_reg;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700491
492 reg_info = &hdd_ctx->reg;
493
Amar Singhale4f28ee2015-10-21 14:36:56 -0700494 ret_val = cds_fill_some_regulatory_info(reg_info);
495 if (ret_val) {
496 hdd_err("incorrect BDF regulatory data");
497 return ret_val;
498 }
499
Dustin Brown38f2b552016-10-04 13:57:46 -0700500 hdd_regulatory_wiphy_init(hdd_ctx, reg_info, wiphy);
501
502 hdd_process_regulatory_data(hdd_ctx, wiphy, true);
503
504 reg_info->cc_src = SOURCE_DRIVER;
505
Amar Singhale4f28ee2015-10-21 14:36:56 -0700506 cds_put_default_country(reg_info->alpha2);
507
Amar Singhale4f28ee2015-10-21 14:36:56 -0700508 cds_fill_and_send_ctl_to_fw(reg_info);
509
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700510 hdd_set_dfs_region(hdd_ctx, DFS_FCC_REGION);
511 cds_get_dfs_region(&dfs_reg);
512 cds_set_wma_dfs_region(dfs_reg);
513
Amar Singhale4f28ee2015-10-21 14:36:56 -0700514 return 0;
515}
516
517/**
518 * hdd_program_country_code() - process channel information from country code
519 * @hdd_ctx: hddc context
520 *
521 * Return: void
522 */
523void hdd_program_country_code(hdd_context_t *hdd_ctx)
524{
525 struct wiphy *wiphy = hdd_ctx->wiphy;
526 uint8_t *country_alpha2 = hdd_ctx->reg.alpha2;
527
528 if (false == init_by_reg_core) {
529 init_by_driver = true;
530 if (('0' != country_alpha2[0]) ||
Amar Singhal38c5eeb2016-08-22 16:50:01 -0700531 ('0' != country_alpha2[1]))
Amar Singhale4f28ee2015-10-21 14:36:56 -0700532 regulatory_hint(wiphy, country_alpha2);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700533 }
534}
535
536
537/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700538 * hdd_restore_custom_reg_settings() - restore custom reg settings
539 * @wiphy: wiphy structure
540 * @country_alpha2: alpha2 of the country
541 * @reset: whether wiphy is reset
542 *
543 * Return: void
544 */
545#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
546static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
547 uint8_t *country_alpha2,
548 bool *reset)
549{
550}
551#else
552static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
553 uint8_t *country_alpha2,
554 bool *reset)
555{
556 struct ieee80211_supported_band *sband;
Dustin Browna30892e2016-10-12 17:28:36 -0700557 enum nl80211_band band;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700558 struct ieee80211_channel *chan;
559 int i;
560
561 if ((country_alpha2[0] == '0') &&
562 (country_alpha2[1] == '0') &&
563 (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) {
564
Dustin Browna30892e2016-10-12 17:28:36 -0700565 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700566 sband = wiphy->bands[band];
567 if (!sband)
568 continue;
569 for (i = 0; i < sband->n_channels; i++) {
570 chan = &sband->channels[i];
571 chan->flags = chan->orig_flags;
572 chan->max_antenna_gain = chan->orig_mag;
573 chan->max_power = chan->orig_mpwr;
574 }
575 }
576 *reset = true;
577 }
578}
579#endif
580
581
582/**
583 * hdd_restore_reg_flags() - restore regulatory flags
584 * @flags: regulatory flags
585 *
586 * Return: void
587 */
588#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
589static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
590{
591 wiphy->regulatory_flags = flags;
592}
593#else
594static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
595{
596 wiphy->flags = flags;
597}
598#endif
599
600
601/**
602 * hdd_reg_notifier() - regulatory notifier
603 * @wiphy: wiphy
604 * @request: regulatory request
605 *
606 * Return: void
607 */
608void hdd_reg_notifier(struct wiphy *wiphy,
609 struct regulatory_request *request)
610{
611 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700612 bool reset = false;
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700613 enum dfs_region dfs_reg;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700614
615 hdd_info("country: %c%c, initiator %d, dfs_region: %d",
616 request->alpha2[0],
617 request->alpha2[1],
618 request->initiator,
619 request->dfs_region);
620
621 if (NULL == hdd_ctx) {
622 hdd_err("invalid hdd_ctx pointer");
623 return;
624 }
625
626 if (cds_is_driver_unloading() || cds_is_driver_recovering()) {
627 hdd_err("%s: unloading or ssr in progress, ignore",
628 __func__);
629 return;
630 }
631
Mukul Sharma0c854a02016-10-20 15:36:20 +0530632 if (hdd_ctx->isWiphySuspended == true) {
633 hdd_err("%s: system/cfg80211 is already suspend", __func__);
634 return;
635 }
636
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700637 if (('K' == request->alpha2[0]) &&
638 ('R' == request->alpha2[1]))
639 request->dfs_region = DFS_KR_REGION;
640
641 if (('C' == request->alpha2[0]) &&
642 ('N' == request->alpha2[1]))
643 request->dfs_region = DFS_CN_REGION;
644
Amar Singhale4f28ee2015-10-21 14:36:56 -0700645 /* first check if this callback is in response to the driver callback */
646
647 switch (request->initiator) {
648 case NL80211_REGDOM_SET_BY_DRIVER:
649 case NL80211_REGDOM_SET_BY_CORE:
650 case NL80211_REGDOM_SET_BY_USER:
651
652 if ((false == init_by_driver) &&
653 (false == init_by_reg_core)) {
654
655 if (NL80211_REGDOM_SET_BY_CORE == request->initiator)
656 return;
657 init_by_reg_core = true;
658 }
659
660 if ((NL80211_REGDOM_SET_BY_DRIVER == request->initiator) &&
661 (true == init_by_driver)) {
662
663 /*
664 * restore the driver regulatory flags since
665 * regulatory_hint may have
666 * changed them
667 */
668 hdd_restore_reg_flags(wiphy, hdd_ctx->reg.reg_flags);
669 }
670
671 if (NL80211_REGDOM_SET_BY_CORE == request->initiator) {
672 hdd_ctx->reg.cc_src = SOURCE_CORE;
673 if (is_wiphy_custom_regulatory(wiphy))
674 reset = true;
675 } else if (NL80211_REGDOM_SET_BY_DRIVER == request->initiator)
676 hdd_ctx->reg.cc_src = SOURCE_DRIVER;
677 else {
678 hdd_ctx->reg.cc_src = SOURCE_USERSPACE;
679 hdd_restore_custom_reg_settings(wiphy,
680 request->alpha2,
681 &reset);
682 }
683
684 hdd_ctx->reg.alpha2[0] = request->alpha2[0];
685 hdd_ctx->reg.alpha2[1] = request->alpha2[1];
686
687 hdd_update_regulatory_info(hdd_ctx);
688
Amar Singhale4f28ee2015-10-21 14:36:56 -0700689 hdd_process_regulatory_data(hdd_ctx, wiphy, reset);
690
Amar Singhale4f28ee2015-10-21 14:36:56 -0700691 sme_generic_change_country_code(hdd_ctx->hHal,
692 hdd_ctx->reg.alpha2);
693
694 cds_fill_and_send_ctl_to_fw(&hdd_ctx->reg);
695
696 hdd_set_dfs_region(hdd_ctx, request->dfs_region);
697
698 cds_get_dfs_region(&dfs_reg);
699 cds_set_wma_dfs_region(dfs_reg);
700 break;
701
702 default:
703 break;
704 }
705}