blob: 433208ddcf00867aa3dd62d105b0ec0be83fdccd [file] [log] [blame]
Amar Singhale4f28ee2015-10-21 14:36:56 -07001/*
Sandeep Puligilla985d1ee2017-01-04 16:41:39 -08002 * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
Amar Singhale4f28ee2015-10-21 14:36:56 -07003 *
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 "wlan_hdd_main.h"
Amar Singhale4f28ee2015-10-21 14:36:56 -070037#include "wlan_hdd_regulatory.h"
Amar Singhal5cccafe2017-02-15 12:42:58 -080038#include <wlan_reg_ucfg_api.h>
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -070039#include "cds_regdomain.h"
Amar Singhale4f28ee2015-10-21 14:36:56 -070040
41#define REG_RULE_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
42
43#define REG_RULE_2467_2472 REG_RULE(2467-10, 2472+10, 40, 0, 20, \
Amar Singhale4f28ee2015-10-21 14:36:56 -070044 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
45
Amar Singhal1c944922016-03-23 18:46:49 -070046#define REG_RULE_2484 REG_RULE(2484-10, 2484+10, 20, 0, 20, \
47 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | \
48 NL80211_RRF_NO_OFDM)
49
50#define REG_RULE_5180_5320 REG_RULE(5180-10, 5320+10, 160, 0, 20, \
51 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
52
53#define REG_RULE_5500_5720 REG_RULE(5500-10, 5720+10, 160, 0, 20, \
Amar Singhale4f28ee2015-10-21 14:36:56 -070054 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
55
56#define REG_RULE_5745_5925 REG_RULE(5745-10, 5925+10, 80, 0, 20, \
57 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
58
59static bool init_by_driver;
60static bool init_by_reg_core;
61
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -070062struct regulatory_channel reg_channels[NUM_CHANNELS];
63
Amar Singhale4f28ee2015-10-21 14:36:56 -070064static const struct ieee80211_regdomain
65hdd_world_regrules_60_61_62 = {
66 .n_reg_rules = 6,
67 .alpha2 = "00",
68 .reg_rules = {
69 REG_RULE_2412_2462,
70 REG_RULE_2467_2472,
71 REG_RULE_2484,
72 REG_RULE_5180_5320,
73 REG_RULE_5500_5720,
74 REG_RULE_5745_5925,
75 }
76};
77
78static const struct ieee80211_regdomain
79hdd_world_regrules_63_65 = {
80 .n_reg_rules = 4,
81 .alpha2 = "00",
82 .reg_rules = {
83 REG_RULE_2412_2462,
84 REG_RULE_2467_2472,
85 REG_RULE_5180_5320,
86 REG_RULE_5745_5925,
87 }
88};
89
90static const struct ieee80211_regdomain
91hdd_world_regrules_64 = {
92 .n_reg_rules = 3,
93 .alpha2 = "00",
94 .reg_rules = {
95 REG_RULE_2412_2462,
96 REG_RULE_5180_5320,
97 REG_RULE_5745_5925,
98 }
99};
100
101static const struct ieee80211_regdomain
102hdd_world_regrules_66_69 = {
103 .n_reg_rules = 4,
104 .alpha2 = "00",
105 .reg_rules = {
106 REG_RULE_2412_2462,
107 REG_RULE_5180_5320,
108 REG_RULE_5500_5720,
109 REG_RULE_5745_5925,
110 }
111};
112
113static const struct ieee80211_regdomain
114hdd_world_regrules_67_68_6A_6C = {
115 .n_reg_rules = 5,
116 .alpha2 = "00",
117 .reg_rules = {
118 REG_RULE_2412_2462,
119 REG_RULE_2467_2472,
120 REG_RULE_5180_5320,
121 REG_RULE_5500_5720,
122 REG_RULE_5745_5925,
123 }
124};
125
126/**
127 * hdd_get_world_regrules() - get the appropriate world regrules
128 * @reg: regulatory data
129 *
130 * Return: regulatory rules ptr
131 */
132static const struct ieee80211_regdomain *hdd_get_world_regrules(
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -0700133 struct regulatory *reg)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700134{
Amar Singhal22995112016-01-22 10:42:33 -0800135 struct reg_dmn_pair *regpair =
136 (struct reg_dmn_pair *)reg->regpair;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700137
Amar Singhala7bb01b2016-01-27 11:31:59 -0800138 switch (regpair->reg_dmn_pair) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700139 case 0x60:
140 case 0x61:
141 case 0x62:
142 return &hdd_world_regrules_60_61_62;
143 case 0x63:
144 case 0x65:
145 return &hdd_world_regrules_63_65;
146 case 0x64:
147 return &hdd_world_regrules_64;
148 case 0x66:
149 case 0x69:
150 return &hdd_world_regrules_66_69;
151 case 0x67:
152 case 0x68:
153 case 0x6A:
154 case 0x6C:
155 return &hdd_world_regrules_67_68_6A_6C;
156 default:
157 hdd_warn("invalid world mode in BDF");
158 return &hdd_world_regrules_60_61_62;
159 }
160}
161
162/**
163 * hdd_is_world_regdomain() - whether world regdomain
164 * @reg_domain: integer regulatory domain
165 *
166 * Return: bool
167 */
Jeff Johnson87a24252016-10-05 16:20:52 -0700168static bool hdd_is_world_regdomain(uint32_t reg_domain)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700169{
Amar Singhal5f997862016-08-24 13:17:50 -0700170 uint32_t temp_regd = reg_domain & ~WORLD_ROAMING_FLAG;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700171
Amar Singhal5f997862016-08-24 13:17:50 -0700172 return ((temp_regd & CTRY_FLAG) != CTRY_FLAG) &&
173 ((temp_regd & WORLD_ROAMING_MASK) ==
174 WORLD_ROAMING_PREFIX);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700175}
176
Amar Singhale4f28ee2015-10-21 14:36:56 -0700177/**
178 * hdd_update_regulatory_info() - update regulatory info
179 * @hdd_ctx: hdd context
180 *
181 * Return: void
182 */
183static void hdd_update_regulatory_info(hdd_context_t *hdd_ctx)
184{
185 uint32_t country_code;
186
187 country_code = cds_get_country_from_alpha2(hdd_ctx->reg.alpha2);
188
Amar Singhal5f997862016-08-24 13:17:50 -0700189 hdd_ctx->reg.reg_domain = CTRY_FLAG;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700190 hdd_ctx->reg.reg_domain |= country_code;
191
192 cds_fill_some_regulatory_info(&hdd_ctx->reg);
193
194}
195
196/**
Abhishek Singh3e6172f2016-05-04 16:56:48 +0530197 * hdd_reset_global_reg_params - Reset global static reg params
198 *
199 * This function is helpful in static driver to reset
200 * the global params.
201 *
202 * Return: void
203 */
204void hdd_reset_global_reg_params(void)
205{
206 init_by_driver = false;
207 init_by_reg_core = false;
208}
209
Amar Singhal5cccafe2017-02-15 12:42:58 -0800210static void reg_program_config_vars(hdd_context_t *hdd_ctx,
211 struct reg_config_vars *config_vars)
212{
213 config_vars->enable_11d_support = hdd_ctx->config->Is11dSupportEnabled;
214 config_vars->userspace_ctry_priority =
215 hdd_ctx->config->fSupplicantCountryCodeHasPriority;
216 config_vars->dfs_enabled = hdd_ctx->config->enableDFSChnlScan;
217 config_vars->indoor_chan_enabled =
218 hdd_ctx->config->indoor_channel_support;
219 config_vars->band_capability = hdd_ctx->config->nBandCapability;
220}
221
222
Abhishek Singh3e6172f2016-05-04 16:56:48 +0530223/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700224 * hdd_regulatory_wiphy_init() - regulatory wiphy init
225 * @hdd_ctx: hdd context
226 * @reg: regulatory data
227 * @wiphy: wiphy structure
228 *
229 * Return: void
230 */
231#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
232static void hdd_regulatory_wiphy_init(hdd_context_t *hdd_ctx,
233 struct regulatory *reg,
234 struct wiphy *wiphy)
235{
236 const struct ieee80211_regdomain *reg_rules;
Amar Singhalb7fe2612016-10-19 10:49:58 -0700237 int chan_num;
Amar Singhal6fc66382016-11-09 13:33:33 -0800238 struct ieee80211_channel *chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700239
240 if (hdd_is_world_regdomain(reg->reg_domain)) {
241 reg_rules = hdd_get_world_regrules(reg);
242 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
243 } else if (hdd_ctx->config->fRegChangeDefCountry) {
244 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
245 reg_rules = &hdd_world_regrules_60_61_62;
246 } else {
247 wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
248 reg_rules = &hdd_world_regrules_60_61_62;
249 }
250
251 /*
252 * save the original driver regulatory flags
253 */
254 hdd_ctx->reg.reg_flags = wiphy->regulatory_flags;
255 wiphy_apply_custom_regulatory(wiphy, reg_rules);
256
257 /*
Amar Singhalb7fe2612016-10-19 10:49:58 -0700258 * disable 2.4 Ghz channels that dont have 20 mhz bw
259 */
260 for (chan_num = 0;
Dustin Brown67f16952017-02-03 15:37:53 -0800261 chan_num < wiphy->bands[NL80211_BAND_2GHZ]->n_channels;
Amar Singhalb7fe2612016-10-19 10:49:58 -0700262 chan_num++) {
Dustin Brown67f16952017-02-03 15:37:53 -0800263 chan = &(wiphy->bands[NL80211_BAND_2GHZ]->channels[chan_num]);
Amar Singhal6fc66382016-11-09 13:33:33 -0800264 if (chan->flags & IEEE80211_CHAN_NO_20MHZ)
265 chan->flags |= IEEE80211_CHAN_DISABLED;
Amar Singhalb7fe2612016-10-19 10:49:58 -0700266 }
267
268 /*
Amar Singhale4f28ee2015-10-21 14:36:56 -0700269 * restore the driver regulatory flags since
270 * wiphy_apply_custom_regulatory may have
271 * changed them
272 */
273 wiphy->regulatory_flags = hdd_ctx->reg.reg_flags;
274
275}
276#else
277static void hdd_regulatory_wiphy_init(hdd_context_t *hdd_ctx,
278 struct regulatory *reg,
279 struct wiphy *wiphy)
280{
281 const struct ieee80211_regdomain *reg_rules;
282
283 if (hdd_is_world_regdomain(reg->reg_domain)) {
284 reg_rules = hdd_get_world_regrules(reg);
285 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
286 } else if (hdd_ctx->config->fRegChangeDefCountry) {
287 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
288 reg_rules = &hdd_world_regrules_60_61_62;
289 } else {
290 wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
291 reg_rules = &hdd_world_regrules_60_61_62;
292 }
293
294 /*
295 * save the original driver regulatory flags
296 */
297 hdd_ctx->reg.reg_flags = wiphy->flags;
298 wiphy_apply_custom_regulatory(wiphy, reg_rules);
299
300 /*
301 * restore the driver regulatory flags since
302 * wiphy_apply_custom_regulatory may have
303 * changed them
304 */
305 wiphy->flags = hdd_ctx->reg.reg_flags;
306
307}
308#endif
309
310/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700311 * 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
Amar Singhale4f28ee2015-10-21 14:36:56 -0700329/**
330 * hdd_modify_wiphy() - modify wiphy
331 * @wiphy: wiphy
332 * @chan: channel structure
333 *
334 * Return: void
335 */
336static void hdd_modify_wiphy(struct wiphy *wiphy,
337 struct ieee80211_channel *chan)
338{
339 const struct ieee80211_reg_rule *reg_rule;
340
341 if (is_wiphy_custom_regulatory(wiphy)) {
342 reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
343 if (!IS_ERR(reg_rule)) {
344 chan->flags &= ~IEEE80211_CHAN_DISABLED;
345
346 if (!(reg_rule->flags & NL80211_RRF_DFS)) {
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530347 hdd_info("Remove dfs restriction for %u",
348 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700349 chan->flags &= ~IEEE80211_CHAN_RADAR;
350 }
351
352 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) {
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530353 hdd_info("Remove passive restriction for %u",
354 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700355 chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
356 }
357
358 if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) {
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530359 hdd_info("Remove no ibss restriction for %u",
360 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700361 chan->flags &= ~IEEE80211_CHAN_NO_IBSS;
362 }
363
364 chan->max_power =
365 MBM_TO_DBM(reg_rule->power_rule.max_eirp);
366 }
367 }
368}
369
370/**
371 * hdd_process_regulatory_data() - process regulatory data
372 * @hdd_ctx: hdd context
373 * @wiphy: wiphy
374 * @reset: whether to reset channel data
375 *
376 * Return: void
377 */
378static void hdd_process_regulatory_data(hdd_context_t *hdd_ctx,
379 struct wiphy *wiphy,
380 bool reset)
381{
Amar Singhal388b3f02016-02-10 13:37:18 -0800382 int band_num;
383 int chan_num;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700384 enum channel_enum chan_enum = CHAN_ENUM_1;
385 struct ieee80211_channel *wiphy_chan, *wiphy_chan_144 = NULL;
Amar Singhal388b3f02016-02-10 13:37:18 -0800386 struct regulatory_channel *cds_chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700387 uint8_t band_capability;
388
389 band_capability = hdd_ctx->config->nBandCapability;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700390
Dustin Browna30892e2016-10-12 17:28:36 -0700391 for (band_num = 0; band_num < NUM_NL80211_BANDS; band_num++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700392
Amar Singhal388b3f02016-02-10 13:37:18 -0800393 if (wiphy->bands[band_num] == NULL)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700394 continue;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700395
Amar Singhal388b3f02016-02-10 13:37:18 -0800396 for (chan_num = 0;
Manjeet Singhec402062016-10-27 15:58:01 +0530397 chan_num < wiphy->bands[band_num]->n_channels &&
398 chan_enum < NUM_CHANNELS;
Amar Singhal388b3f02016-02-10 13:37:18 -0800399 chan_num++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700400
Amar Singhal388b3f02016-02-10 13:37:18 -0800401 wiphy_chan =
402 &(wiphy->bands[band_num]->channels[chan_num]);
403 cds_chan = &(reg_channels[chan_enum]);
Amar Singhal5cccafe2017-02-15 12:42:58 -0800404 cds_chan->chan_flags = 0;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700405 if (CHAN_ENUM_144 == chan_enum)
406 wiphy_chan_144 = wiphy_chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700407
Amar Singhal388b3f02016-02-10 13:37:18 -0800408 chan_enum++;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700409
410 if (!reset)
Amar Singhal388b3f02016-02-10 13:37:18 -0800411 hdd_modify_wiphy(wiphy, wiphy_chan);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700412
Amar Singhal388b3f02016-02-10 13:37:18 -0800413 if (wiphy_chan->flags & IEEE80211_CHAN_DISABLED) {
414 cds_chan->state = CHANNEL_STATE_DISABLE;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800415 cds_chan->chan_flags |=
416 REGULATORY_CHAN_DISABLED;
Amar Singhal18517882016-08-08 12:26:20 -0700417 } else if ((wiphy_chan->flags &
418 (IEEE80211_CHAN_RADAR |
Amar Singhal5cccafe2017-02-15 12:42:58 -0800419 IEEE80211_CHAN_PASSIVE_SCAN |
Amar Singhal18517882016-08-08 12:26:20 -0700420 IEEE80211_CHAN_INDOOR_ONLY))) {
421 if ((wiphy_chan->flags &
422 IEEE80211_CHAN_INDOOR_ONLY) &&
423 (false ==
424 hdd_ctx->config->indoor_channel_support))
Amar Singhal388b3f02016-02-10 13:37:18 -0800425 wiphy_chan->flags |=
Amar Singhale4f28ee2015-10-21 14:36:56 -0700426 IEEE80211_CHAN_PASSIVE_SCAN;
Amar Singhal388b3f02016-02-10 13:37:18 -0800427 cds_chan->state = CHANNEL_STATE_DFS;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800428 if (wiphy_chan->flags & IEEE80211_CHAN_RADAR)
429 cds_chan->chan_flags |=
430 REGULATORY_CHAN_RADAR;
431 if (wiphy_chan->flags &
432 IEEE80211_CHAN_PASSIVE_SCAN)
433 cds_chan->chan_flags |=
434 REGULATORY_CHAN_NO_IR;
435 if (wiphy_chan->flags &
436 IEEE80211_CHAN_INDOOR_ONLY)
437 cds_chan->chan_flags |=
438 REGULATORY_CHAN_INDOOR_ONLY;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700439 } else {
Amar Singhal388b3f02016-02-10 13:37:18 -0800440 cds_chan->state = CHANNEL_STATE_ENABLE;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700441 }
Amar Singhal5cccafe2017-02-15 12:42:58 -0800442 cds_chan->tx_power = wiphy_chan->max_power;
443 if (wiphy_chan->flags & IEEE80211_CHAN_NO_10MHZ)
444 cds_chan->max_bw = 5;
445 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_20MHZ)
446 cds_chan->max_bw = 10;
Krunal Soni408690d2017-05-03 18:32:35 -0700447 /*
448 * IEEE80211_CHAN_NO_HT40 is defined as 0x30 in kernel
449 * 4th BIT representing IEEE80211_CHAN_NO_HT40PLUS
450 * 5th BIT representing IEEE80211_CHAN_NO_HT40MINUS
451 *
452 * In order to claim no 40Mhz support value of
453 * wiphy_chan->flags needs to be 0x30.
454 * 0x20 and 0x10 values shows that either HT40+ or
455 * HT40- is not supported based on BIT set but they
456 * can support 40Mhz Operation.
457 */
458 else if ((wiphy_chan->flags & IEEE80211_CHAN_NO_HT40) ==
459 IEEE80211_CHAN_NO_HT40)
Amar Singhal5cccafe2017-02-15 12:42:58 -0800460 cds_chan->max_bw = 20;
461 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_80MHZ)
462 cds_chan->max_bw = 40;
463 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_160MHZ)
464 cds_chan->max_bw = 80;
465 else
466 cds_chan->max_bw = 160;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700467 }
468 }
469
470 if (0 == (hdd_ctx->reg.eeprom_rd_ext &
Sandeep Puligilla985d1ee2017-01-04 16:41:39 -0800471 (1 << WMI_REG_EXT_FCC_CH_144))) {
Amar Singhal388b3f02016-02-10 13:37:18 -0800472 cds_chan = &(reg_channels[CHAN_ENUM_144]);
473 cds_chan->state = CHANNEL_STATE_DISABLE;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700474 if (NULL != wiphy_chan_144)
475 wiphy_chan_144->flags |= IEEE80211_CHAN_DISABLED;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700476 }
Amar Singhal6842e8f2016-02-23 16:30:32 -0800477
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -0700478 wlan_hdd_cfg80211_update_band(hdd_ctx, wiphy, band_capability);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700479}
480
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700481/**
482 * hdd_set_dfs_region() - set the dfs_region
483 * @dfs_region: the dfs_region to set
484 *
485 * Return: void
486 */
487#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
488static void hdd_set_dfs_region(hdd_context_t *hdd_ctx,
Amar Singhal5cccafe2017-02-15 12:42:58 -0800489 enum dfs_reg dfs_reg)
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700490{
Amar Singhal5cccafe2017-02-15 12:42:58 -0800491 wlan_reg_set_dfs_region(hdd_ctx->hdd_psoc, dfs_reg);
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700492}
493#else
494static void hdd_set_dfs_region(hdd_context_t *hdd_ctx,
495 enum dfs_region dfs_reg)
496{
497
498 /* remap the ctl code to dfs region code */
499 switch (hdd_ctx->reg.ctl_5g) {
500 case FCC:
501 cds_put_dfs_region(DFS_FCC_REGION);
502 break;
503 case ETSI:
504 cds_put_dfs_region(DFS_ETSI_REGION);
505 break;
506 case MKK:
507 cds_put_dfs_region(DFS_MKK_REGION);
508 break;
509 default:
510 /* set default dfs_region to FCC */
511 cds_put_dfs_region(DFS_FCC_REGION);
512 break;
513 }
514
515}
516#endif
517
Amar Singhale4f28ee2015-10-21 14:36:56 -0700518/**
Amar Singhal5cccafe2017-02-15 12:42:58 -0800519 * hdd_regulatory_init_no_offload() - regulatory init
Amar Singhale4f28ee2015-10-21 14:36:56 -0700520 * @hdd_ctx: hdd context
521 * @wiphy: wiphy
522 *
523 * Return: int
524 */
Amar Singhal5cccafe2017-02-15 12:42:58 -0800525static int hdd_regulatory_init_no_offload(hdd_context_t *hdd_ctx,
526 struct wiphy *wiphy)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700527{
528 int ret_val;
529 struct regulatory *reg_info;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800530 enum dfs_reg dfs_reg;
531 struct reg_config_vars config_vars;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700532
533 reg_info = &hdd_ctx->reg;
534
Amar Singhale4f28ee2015-10-21 14:36:56 -0700535 ret_val = cds_fill_some_regulatory_info(reg_info);
536 if (ret_val) {
537 hdd_err("incorrect BDF regulatory data");
538 return ret_val;
539 }
540
Dustin Brown38f2b552016-10-04 13:57:46 -0700541 hdd_regulatory_wiphy_init(hdd_ctx, reg_info, wiphy);
542
543 hdd_process_regulatory_data(hdd_ctx, wiphy, true);
544
545 reg_info->cc_src = SOURCE_DRIVER;
546
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -0700547 ucfg_reg_set_default_country(hdd_ctx->hdd_psoc, reg_info->alpha2);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700548
Amar Singhale4f28ee2015-10-21 14:36:56 -0700549 cds_fill_and_send_ctl_to_fw(reg_info);
550
Amar Singhal5cccafe2017-02-15 12:42:58 -0800551 hdd_set_dfs_region(hdd_ctx, DFS_FCC_REG);
552 wlan_reg_get_dfs_region(hdd_ctx->hdd_psoc, &dfs_reg);
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700553
Amar Singhal5cccafe2017-02-15 12:42:58 -0800554 reg_program_config_vars(hdd_ctx, &config_vars);
555 ucfg_reg_set_config_vars(hdd_ctx->hdd_psoc, config_vars);
556 ucfg_reg_program_mas_chan_list(hdd_ctx->hdd_psoc,
557 reg_channels,
558 hdd_ctx->reg.alpha2,
559 dfs_reg);
560
Amar Singhale4f28ee2015-10-21 14:36:56 -0700561 return 0;
562}
563
564/**
565 * hdd_program_country_code() - process channel information from country code
566 * @hdd_ctx: hddc context
567 *
568 * Return: void
569 */
570void hdd_program_country_code(hdd_context_t *hdd_ctx)
571{
572 struct wiphy *wiphy = hdd_ctx->wiphy;
573 uint8_t *country_alpha2 = hdd_ctx->reg.alpha2;
574
Abhishek Singh897b27a2017-03-17 11:56:46 +0530575 if (!init_by_reg_core && !init_by_driver) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700576 init_by_driver = true;
577 if (('0' != country_alpha2[0]) ||
Amar Singhal38c5eeb2016-08-22 16:50:01 -0700578 ('0' != country_alpha2[1]))
Amar Singhale4f28ee2015-10-21 14:36:56 -0700579 regulatory_hint(wiphy, country_alpha2);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700580 }
581}
582
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -0700583int hdd_reg_set_country(hdd_context_t *hdd_ctx, char *country_code)
584{
585 int err;
586 QDF_STATUS status;
587
588 /* validation */
589 err = wlan_hdd_validate_context(hdd_ctx);
590 if (err)
591 return err;
592
593 if (!country_code) {
594 hdd_err("country_code is null");
595 return -EINVAL;
596 }
597
598 /* call regulatory set_country api */
599 status = ucfg_reg_set_country(hdd_ctx->hdd_pdev, country_code);
600 if (QDF_IS_STATUS_ERROR(status))
601 hdd_err("Failed to set country");
602
603 return qdf_status_to_os_return(status);
604}
Amar Singhale4f28ee2015-10-21 14:36:56 -0700605
606/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700607 * hdd_restore_custom_reg_settings() - restore custom reg settings
608 * @wiphy: wiphy structure
609 * @country_alpha2: alpha2 of the country
610 * @reset: whether wiphy is reset
611 *
612 * Return: void
613 */
614#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
615static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
616 uint8_t *country_alpha2,
617 bool *reset)
618{
619}
620#else
621static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
622 uint8_t *country_alpha2,
623 bool *reset)
624{
625 struct ieee80211_supported_band *sband;
Dustin Browna30892e2016-10-12 17:28:36 -0700626 enum nl80211_band band;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700627 struct ieee80211_channel *chan;
628 int i;
629
630 if ((country_alpha2[0] == '0') &&
631 (country_alpha2[1] == '0') &&
632 (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) {
633
Dustin Browna30892e2016-10-12 17:28:36 -0700634 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700635 sband = wiphy->bands[band];
636 if (!sband)
637 continue;
638 for (i = 0; i < sband->n_channels; i++) {
639 chan = &sband->channels[i];
640 chan->flags = chan->orig_flags;
641 chan->max_antenna_gain = chan->orig_mag;
642 chan->max_power = chan->orig_mpwr;
643 }
644 }
645 *reset = true;
646 }
647}
648#endif
649
Amar Singhale4f28ee2015-10-21 14:36:56 -0700650/**
651 * hdd_restore_reg_flags() - restore regulatory flags
652 * @flags: regulatory flags
653 *
654 * Return: void
655 */
656#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
657static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
658{
659 wiphy->regulatory_flags = flags;
660}
661#else
662static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
663{
664 wiphy->flags = flags;
665}
666#endif
667
Amar Singhale4f28ee2015-10-21 14:36:56 -0700668/**
669 * hdd_reg_notifier() - regulatory notifier
670 * @wiphy: wiphy
671 * @request: regulatory request
672 *
673 * Return: void
674 */
675void hdd_reg_notifier(struct wiphy *wiphy,
676 struct regulatory_request *request)
677{
678 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700679 bool reset = false;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800680 enum dfs_reg dfs_reg;
681 struct reg_config_vars config_vars;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700682
683 hdd_info("country: %c%c, initiator %d, dfs_region: %d",
684 request->alpha2[0],
685 request->alpha2[1],
686 request->initiator,
687 request->dfs_region);
688
689 if (NULL == hdd_ctx) {
690 hdd_err("invalid hdd_ctx pointer");
691 return;
692 }
693
694 if (cds_is_driver_unloading() || cds_is_driver_recovering()) {
695 hdd_err("%s: unloading or ssr in progress, ignore",
696 __func__);
697 return;
698 }
699
Dustin Brownc0ad1ec2017-01-26 12:01:32 -0800700 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
701 hdd_err("Driver module is closed; dropping request");
702 return;
703 }
704
Mukul Sharma0c854a02016-10-20 15:36:20 +0530705 if (hdd_ctx->isWiphySuspended == true) {
706 hdd_err("%s: system/cfg80211 is already suspend", __func__);
707 return;
708 }
709
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700710 if (('K' == request->alpha2[0]) &&
711 ('R' == request->alpha2[1]))
Amar Singhal5cccafe2017-02-15 12:42:58 -0800712 request->dfs_region = DFS_KR_REG;
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700713
714 if (('C' == request->alpha2[0]) &&
715 ('N' == request->alpha2[1]))
Amar Singhal5cccafe2017-02-15 12:42:58 -0800716 request->dfs_region = DFS_CN_REG;
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700717
Amar Singhale4f28ee2015-10-21 14:36:56 -0700718 /* first check if this callback is in response to the driver callback */
719
720 switch (request->initiator) {
721 case NL80211_REGDOM_SET_BY_DRIVER:
722 case NL80211_REGDOM_SET_BY_CORE:
723 case NL80211_REGDOM_SET_BY_USER:
724
725 if ((false == init_by_driver) &&
726 (false == init_by_reg_core)) {
727
728 if (NL80211_REGDOM_SET_BY_CORE == request->initiator)
729 return;
730 init_by_reg_core = true;
731 }
732
733 if ((NL80211_REGDOM_SET_BY_DRIVER == request->initiator) &&
734 (true == init_by_driver)) {
735
736 /*
737 * restore the driver regulatory flags since
738 * regulatory_hint may have
739 * changed them
740 */
741 hdd_restore_reg_flags(wiphy, hdd_ctx->reg.reg_flags);
742 }
743
744 if (NL80211_REGDOM_SET_BY_CORE == request->initiator) {
745 hdd_ctx->reg.cc_src = SOURCE_CORE;
746 if (is_wiphy_custom_regulatory(wiphy))
747 reset = true;
Amar Singhal6edf9732016-11-20 21:43:40 -0800748 } else if (NL80211_REGDOM_SET_BY_DRIVER == request->initiator) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700749 hdd_ctx->reg.cc_src = SOURCE_DRIVER;
Amar Singhal6edf9732016-11-20 21:43:40 -0800750 sme_set_cc_src(hdd_ctx->hHal, SOURCE_DRIVER);
751 } else {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700752 hdd_ctx->reg.cc_src = SOURCE_USERSPACE;
753 hdd_restore_custom_reg_settings(wiphy,
754 request->alpha2,
755 &reset);
756 }
757
758 hdd_ctx->reg.alpha2[0] = request->alpha2[0];
759 hdd_ctx->reg.alpha2[1] = request->alpha2[1];
760
761 hdd_update_regulatory_info(hdd_ctx);
762
Amar Singhale4f28ee2015-10-21 14:36:56 -0700763 hdd_process_regulatory_data(hdd_ctx, wiphy, reset);
764
Amar Singhale4f28ee2015-10-21 14:36:56 -0700765 sme_generic_change_country_code(hdd_ctx->hHal,
766 hdd_ctx->reg.alpha2);
767
768 cds_fill_and_send_ctl_to_fw(&hdd_ctx->reg);
769
770 hdd_set_dfs_region(hdd_ctx, request->dfs_region);
Amar Singhal5cccafe2017-02-15 12:42:58 -0800771 wlan_reg_get_dfs_region(hdd_ctx->hdd_psoc, &dfs_reg);
Amar Singhal5cccafe2017-02-15 12:42:58 -0800772
773 reg_program_config_vars(hdd_ctx, &config_vars);
774 ucfg_reg_set_config_vars(hdd_ctx->hdd_psoc, config_vars);
775 ucfg_reg_program_mas_chan_list(hdd_ctx->hdd_psoc,
776 reg_channels,
777 hdd_ctx->reg.alpha2,
778 dfs_reg);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700779 break;
780
781 default:
782 break;
783 }
784}
Amar Singhal5cccafe2017-02-15 12:42:58 -0800785
786
787#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
788static void fill_wiphy_channel(struct ieee80211_channel *wiphy_chan,
789 struct regulatory_channel *cur_chan)
790{
791
792 wiphy_chan->flags &= ~IEEE80211_CHAN_DISABLED;
793 wiphy_chan->max_power = cur_chan->tx_power;
794
795 if (cur_chan->chan_flags & REGULATORY_CHAN_DISABLED)
796 wiphy_chan->flags |= IEEE80211_CHAN_DISABLED;
797 if (cur_chan->chan_flags & REGULATORY_CHAN_NO_IR)
798 wiphy_chan->flags |= IEEE80211_CHAN_NO_IR;
799 if (cur_chan->chan_flags & REGULATORY_CHAN_RADAR)
800 wiphy_chan->flags |= IEEE80211_CHAN_RADAR;
801 if (cur_chan->chan_flags & REGULATORY_CHAN_NO_OFDM)
802 wiphy_chan->flags |= IEEE80211_CHAN_NO_OFDM;
803 if (cur_chan->chan_flags & REGULATORY_CHAN_INDOOR_ONLY)
804 wiphy_chan->flags |= IEEE80211_CHAN_INDOOR_ONLY;
805
806 if (cur_chan->max_bw < 10)
807 wiphy_chan->flags |= IEEE80211_CHAN_NO_10MHZ;
808 if (cur_chan->max_bw < 20)
809 wiphy_chan->flags |= IEEE80211_CHAN_NO_20MHZ;
810 if (cur_chan->max_bw < 40)
811 wiphy_chan->flags |= IEEE80211_CHAN_NO_HT40;
812 if (cur_chan->max_bw < 80)
813 wiphy_chan->flags |= IEEE80211_CHAN_NO_80MHZ;
814 if (cur_chan->max_bw < 160)
815 wiphy_chan->flags |= IEEE80211_CHAN_NO_160MHZ;
816}
817
818
819static void fill_wiphy_band_channels(struct wiphy *wiphy,
820 struct regulatory_channel *cur_chan_list,
821 uint8_t band_id)
822{
823 uint32_t wiphy_num_chan, wiphy_index;
824 uint32_t chan_cnt;
825 struct ieee80211_channel *wiphy_chan;
826
827 wiphy_num_chan = wiphy->bands[band_id]->n_channels;
828 wiphy_chan = wiphy->bands[band_id]->channels;
829
830 for (wiphy_index = 0; wiphy_index < wiphy_num_chan; wiphy_index++) {
831 for (chan_cnt = 0; chan_cnt < NUM_CHANNELS; chan_cnt++) {
832 if (wiphy_chan[wiphy_index].center_freq ==
833 cur_chan_list[chan_cnt].center_freq) {
834 fill_wiphy_channel(&(wiphy_chan[wiphy_index]),
835 &(cur_chan_list[chan_cnt]));
836 break;
837 }
838 }
839 }
840}
841
842
843/**
844 * hdd_regulatory_init_offload() - regulatory init
845 * @hdd_ctx: hdd context
846 * @wiphy: wiphy
847 *
848 * Return: int
849 */
850static int hdd_regulatory_init_offload(hdd_context_t *hdd_ctx,
851 struct wiphy *wiphy)
852{
853 struct reg_config_vars config_vars;
854 struct regulatory_channel cur_chan_list[NUM_CHANNELS];
855
856 config_vars.enable_11d_support = hdd_ctx->config->Is11dSupportEnabled;
857 config_vars.userspace_ctry_priority =
858 hdd_ctx->config->fSupplicantCountryCodeHasPriority;
859 config_vars.dfs_enabled = hdd_ctx->config->enableDFSChnlScan;
860 config_vars.indoor_chan_enabled =
861 hdd_ctx->config->indoor_channel_support;
862 config_vars.band_capability = hdd_ctx->config->nBandCapability;
863
864 reg_program_config_vars(hdd_ctx, &config_vars);
865 ucfg_reg_set_config_vars(hdd_ctx->hdd_psoc, config_vars);
866 ucfg_reg_get_current_chan_list(hdd_ctx->hdd_pdev, cur_chan_list);
867 fill_wiphy_band_channels(wiphy, cur_chan_list, NL80211_BAND_2GHZ);
868 fill_wiphy_band_channels(wiphy, cur_chan_list, NL80211_BAND_5GHZ);
869
870 return 0;
871}
872
873
874
875int hdd_regulatory_init(hdd_context_t *hdd_ctx, struct wiphy *wiphy)
876{
877 bool offload_enabled;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800878
879 offload_enabled = ucfg_reg_is_regdb_offloaded(hdd_ctx->hdd_psoc);
880
881 if (offload_enabled && hdd_ctx->config->reg_offload_enabled) {
882 hdd_ctx->reg_offload = true;
883 wiphy->reg_notifier = NULL;
884 wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
885 hdd_regulatory_init_offload(hdd_ctx, wiphy);
Amar Singhal5cccafe2017-02-15 12:42:58 -0800886 } else {
887 hdd_ctx->reg_offload = false;
888 wiphy->reg_notifier = hdd_reg_notifier;
889 wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
890 wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
891 hdd_regulatory_init_no_offload(hdd_ctx, wiphy);
892
893 }
894
895 return 0;
896}
897#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
898int hdd_regulatory_init(hdd_context_t *hdd_ctx, struct wiphy *wiphy)
899{
900 hdd_ctx->reg_offload = false;
901 wiphy->reg_notifier = hdd_reg_notifier;
902 wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
903 wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
904 hdd_regulatory_init_no_offload(hdd_ctx, wiphy);
905
906 return 0;
907}
908#else
909int hdd_regulatory_init(hdd_context_t *hdd_ctx, struct wiphy *wiphy)
910{
911 hdd_ctx->reg_offload = false;
912 wiphy->reg_notifier = hdd_reg_notifier;
913 wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS;
914 wiphy->country_ie_pref |= NL80211_COUNTRY_IE_IGNORE_CORE;
915 hdd_regulatory_init_no_offload(hdd_ctx, wiphy);
916
917 return 0;
918}
919#endif