blob: 0ec4f6fbc7a6e9ed06f26a2933d45d7d09f25652 [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;
447 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_HT40)
448 cds_chan->max_bw = 20;
449 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_80MHZ)
450 cds_chan->max_bw = 40;
451 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_160MHZ)
452 cds_chan->max_bw = 80;
453 else
454 cds_chan->max_bw = 160;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700455 }
456 }
457
458 if (0 == (hdd_ctx->reg.eeprom_rd_ext &
Sandeep Puligilla985d1ee2017-01-04 16:41:39 -0800459 (1 << WMI_REG_EXT_FCC_CH_144))) {
Amar Singhal388b3f02016-02-10 13:37:18 -0800460 cds_chan = &(reg_channels[CHAN_ENUM_144]);
461 cds_chan->state = CHANNEL_STATE_DISABLE;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700462 if (NULL != wiphy_chan_144)
463 wiphy_chan_144->flags |= IEEE80211_CHAN_DISABLED;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700464 }
Amar Singhal6842e8f2016-02-23 16:30:32 -0800465
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -0700466 wlan_hdd_cfg80211_update_band(hdd_ctx, wiphy, band_capability);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700467}
468
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700469/**
470 * hdd_set_dfs_region() - set the dfs_region
471 * @dfs_region: the dfs_region to set
472 *
473 * Return: void
474 */
475#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
476static void hdd_set_dfs_region(hdd_context_t *hdd_ctx,
Amar Singhal5cccafe2017-02-15 12:42:58 -0800477 enum dfs_reg dfs_reg)
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700478{
Amar Singhal5cccafe2017-02-15 12:42:58 -0800479 wlan_reg_set_dfs_region(hdd_ctx->hdd_psoc, dfs_reg);
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700480}
481#else
482static void hdd_set_dfs_region(hdd_context_t *hdd_ctx,
483 enum dfs_region dfs_reg)
484{
485
486 /* remap the ctl code to dfs region code */
487 switch (hdd_ctx->reg.ctl_5g) {
488 case FCC:
489 cds_put_dfs_region(DFS_FCC_REGION);
490 break;
491 case ETSI:
492 cds_put_dfs_region(DFS_ETSI_REGION);
493 break;
494 case MKK:
495 cds_put_dfs_region(DFS_MKK_REGION);
496 break;
497 default:
498 /* set default dfs_region to FCC */
499 cds_put_dfs_region(DFS_FCC_REGION);
500 break;
501 }
502
503}
504#endif
505
Amar Singhale4f28ee2015-10-21 14:36:56 -0700506/**
Amar Singhal5cccafe2017-02-15 12:42:58 -0800507 * hdd_regulatory_init_no_offload() - regulatory init
Amar Singhale4f28ee2015-10-21 14:36:56 -0700508 * @hdd_ctx: hdd context
509 * @wiphy: wiphy
510 *
511 * Return: int
512 */
Amar Singhal5cccafe2017-02-15 12:42:58 -0800513static int hdd_regulatory_init_no_offload(hdd_context_t *hdd_ctx,
514 struct wiphy *wiphy)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700515{
516 int ret_val;
517 struct regulatory *reg_info;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800518 enum dfs_reg dfs_reg;
519 struct reg_config_vars config_vars;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700520
521 reg_info = &hdd_ctx->reg;
522
Amar Singhale4f28ee2015-10-21 14:36:56 -0700523 ret_val = cds_fill_some_regulatory_info(reg_info);
524 if (ret_val) {
525 hdd_err("incorrect BDF regulatory data");
526 return ret_val;
527 }
528
Dustin Brown38f2b552016-10-04 13:57:46 -0700529 hdd_regulatory_wiphy_init(hdd_ctx, reg_info, wiphy);
530
531 hdd_process_regulatory_data(hdd_ctx, wiphy, true);
532
533 reg_info->cc_src = SOURCE_DRIVER;
534
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -0700535 wlan_reg_set_default_country(hdd_ctx->hdd_psoc, reg_info->alpha2);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700536
Amar Singhale4f28ee2015-10-21 14:36:56 -0700537 cds_fill_and_send_ctl_to_fw(reg_info);
538
Amar Singhal5cccafe2017-02-15 12:42:58 -0800539 hdd_set_dfs_region(hdd_ctx, DFS_FCC_REG);
540 wlan_reg_get_dfs_region(hdd_ctx->hdd_psoc, &dfs_reg);
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700541 cds_set_wma_dfs_region(dfs_reg);
542
Amar Singhal5cccafe2017-02-15 12:42:58 -0800543 reg_program_config_vars(hdd_ctx, &config_vars);
544 ucfg_reg_set_config_vars(hdd_ctx->hdd_psoc, config_vars);
545 ucfg_reg_program_mas_chan_list(hdd_ctx->hdd_psoc,
546 reg_channels,
547 hdd_ctx->reg.alpha2,
548 dfs_reg);
549
Amar Singhale4f28ee2015-10-21 14:36:56 -0700550 return 0;
551}
552
553/**
554 * hdd_program_country_code() - process channel information from country code
555 * @hdd_ctx: hddc context
556 *
557 * Return: void
558 */
559void hdd_program_country_code(hdd_context_t *hdd_ctx)
560{
561 struct wiphy *wiphy = hdd_ctx->wiphy;
562 uint8_t *country_alpha2 = hdd_ctx->reg.alpha2;
563
Abhishek Singh897b27a2017-03-17 11:56:46 +0530564 if (!init_by_reg_core && !init_by_driver) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700565 init_by_driver = true;
566 if (('0' != country_alpha2[0]) ||
Amar Singhal38c5eeb2016-08-22 16:50:01 -0700567 ('0' != country_alpha2[1]))
Amar Singhale4f28ee2015-10-21 14:36:56 -0700568 regulatory_hint(wiphy, country_alpha2);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700569 }
570}
571
572
573/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700574 * hdd_restore_custom_reg_settings() - restore custom reg settings
575 * @wiphy: wiphy structure
576 * @country_alpha2: alpha2 of the country
577 * @reset: whether wiphy is reset
578 *
579 * Return: void
580 */
581#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
582static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
583 uint8_t *country_alpha2,
584 bool *reset)
585{
586}
587#else
588static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
589 uint8_t *country_alpha2,
590 bool *reset)
591{
592 struct ieee80211_supported_band *sband;
Dustin Browna30892e2016-10-12 17:28:36 -0700593 enum nl80211_band band;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700594 struct ieee80211_channel *chan;
595 int i;
596
597 if ((country_alpha2[0] == '0') &&
598 (country_alpha2[1] == '0') &&
599 (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) {
600
Dustin Browna30892e2016-10-12 17:28:36 -0700601 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700602 sband = wiphy->bands[band];
603 if (!sband)
604 continue;
605 for (i = 0; i < sband->n_channels; i++) {
606 chan = &sband->channels[i];
607 chan->flags = chan->orig_flags;
608 chan->max_antenna_gain = chan->orig_mag;
609 chan->max_power = chan->orig_mpwr;
610 }
611 }
612 *reset = true;
613 }
614}
615#endif
616
Amar Singhale4f28ee2015-10-21 14:36:56 -0700617/**
618 * hdd_restore_reg_flags() - restore regulatory flags
619 * @flags: regulatory flags
620 *
621 * Return: void
622 */
623#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
624static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
625{
626 wiphy->regulatory_flags = flags;
627}
628#else
629static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
630{
631 wiphy->flags = flags;
632}
633#endif
634
Amar Singhale4f28ee2015-10-21 14:36:56 -0700635/**
636 * hdd_reg_notifier() - regulatory notifier
637 * @wiphy: wiphy
638 * @request: regulatory request
639 *
640 * Return: void
641 */
642void hdd_reg_notifier(struct wiphy *wiphy,
643 struct regulatory_request *request)
644{
645 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700646 bool reset = false;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800647 enum dfs_reg dfs_reg;
648 struct reg_config_vars config_vars;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700649
650 hdd_info("country: %c%c, initiator %d, dfs_region: %d",
651 request->alpha2[0],
652 request->alpha2[1],
653 request->initiator,
654 request->dfs_region);
655
656 if (NULL == hdd_ctx) {
657 hdd_err("invalid hdd_ctx pointer");
658 return;
659 }
660
661 if (cds_is_driver_unloading() || cds_is_driver_recovering()) {
662 hdd_err("%s: unloading or ssr in progress, ignore",
663 __func__);
664 return;
665 }
666
Dustin Brownc0ad1ec2017-01-26 12:01:32 -0800667 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
668 hdd_err("Driver module is closed; dropping request");
669 return;
670 }
671
Mukul Sharma0c854a02016-10-20 15:36:20 +0530672 if (hdd_ctx->isWiphySuspended == true) {
673 hdd_err("%s: system/cfg80211 is already suspend", __func__);
674 return;
675 }
676
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700677 if (('K' == request->alpha2[0]) &&
678 ('R' == request->alpha2[1]))
Amar Singhal5cccafe2017-02-15 12:42:58 -0800679 request->dfs_region = DFS_KR_REG;
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700680
681 if (('C' == request->alpha2[0]) &&
682 ('N' == request->alpha2[1]))
Amar Singhal5cccafe2017-02-15 12:42:58 -0800683 request->dfs_region = DFS_CN_REG;
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700684
Amar Singhale4f28ee2015-10-21 14:36:56 -0700685 /* first check if this callback is in response to the driver callback */
686
687 switch (request->initiator) {
688 case NL80211_REGDOM_SET_BY_DRIVER:
689 case NL80211_REGDOM_SET_BY_CORE:
690 case NL80211_REGDOM_SET_BY_USER:
691
692 if ((false == init_by_driver) &&
693 (false == init_by_reg_core)) {
694
695 if (NL80211_REGDOM_SET_BY_CORE == request->initiator)
696 return;
697 init_by_reg_core = true;
698 }
699
700 if ((NL80211_REGDOM_SET_BY_DRIVER == request->initiator) &&
701 (true == init_by_driver)) {
702
703 /*
704 * restore the driver regulatory flags since
705 * regulatory_hint may have
706 * changed them
707 */
708 hdd_restore_reg_flags(wiphy, hdd_ctx->reg.reg_flags);
709 }
710
711 if (NL80211_REGDOM_SET_BY_CORE == request->initiator) {
712 hdd_ctx->reg.cc_src = SOURCE_CORE;
713 if (is_wiphy_custom_regulatory(wiphy))
714 reset = true;
Amar Singhal6edf9732016-11-20 21:43:40 -0800715 } else if (NL80211_REGDOM_SET_BY_DRIVER == request->initiator) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700716 hdd_ctx->reg.cc_src = SOURCE_DRIVER;
Amar Singhal6edf9732016-11-20 21:43:40 -0800717 sme_set_cc_src(hdd_ctx->hHal, SOURCE_DRIVER);
718 } else {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700719 hdd_ctx->reg.cc_src = SOURCE_USERSPACE;
720 hdd_restore_custom_reg_settings(wiphy,
721 request->alpha2,
722 &reset);
723 }
724
725 hdd_ctx->reg.alpha2[0] = request->alpha2[0];
726 hdd_ctx->reg.alpha2[1] = request->alpha2[1];
727
728 hdd_update_regulatory_info(hdd_ctx);
729
Amar Singhale4f28ee2015-10-21 14:36:56 -0700730 hdd_process_regulatory_data(hdd_ctx, wiphy, reset);
731
Amar Singhale4f28ee2015-10-21 14:36:56 -0700732 sme_generic_change_country_code(hdd_ctx->hHal,
733 hdd_ctx->reg.alpha2);
734
735 cds_fill_and_send_ctl_to_fw(&hdd_ctx->reg);
736
737 hdd_set_dfs_region(hdd_ctx, request->dfs_region);
Amar Singhal5cccafe2017-02-15 12:42:58 -0800738 wlan_reg_get_dfs_region(hdd_ctx->hdd_psoc, &dfs_reg);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700739 cds_set_wma_dfs_region(dfs_reg);
Amar Singhal5cccafe2017-02-15 12:42:58 -0800740
741 reg_program_config_vars(hdd_ctx, &config_vars);
742 ucfg_reg_set_config_vars(hdd_ctx->hdd_psoc, config_vars);
743 ucfg_reg_program_mas_chan_list(hdd_ctx->hdd_psoc,
744 reg_channels,
745 hdd_ctx->reg.alpha2,
746 dfs_reg);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700747 break;
748
749 default:
750 break;
751 }
752}
Amar Singhal5cccafe2017-02-15 12:42:58 -0800753
754
755#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
756static void fill_wiphy_channel(struct ieee80211_channel *wiphy_chan,
757 struct regulatory_channel *cur_chan)
758{
759
760 wiphy_chan->flags &= ~IEEE80211_CHAN_DISABLED;
761 wiphy_chan->max_power = cur_chan->tx_power;
762
763 if (cur_chan->chan_flags & REGULATORY_CHAN_DISABLED)
764 wiphy_chan->flags |= IEEE80211_CHAN_DISABLED;
765 if (cur_chan->chan_flags & REGULATORY_CHAN_NO_IR)
766 wiphy_chan->flags |= IEEE80211_CHAN_NO_IR;
767 if (cur_chan->chan_flags & REGULATORY_CHAN_RADAR)
768 wiphy_chan->flags |= IEEE80211_CHAN_RADAR;
769 if (cur_chan->chan_flags & REGULATORY_CHAN_NO_OFDM)
770 wiphy_chan->flags |= IEEE80211_CHAN_NO_OFDM;
771 if (cur_chan->chan_flags & REGULATORY_CHAN_INDOOR_ONLY)
772 wiphy_chan->flags |= IEEE80211_CHAN_INDOOR_ONLY;
773
774 if (cur_chan->max_bw < 10)
775 wiphy_chan->flags |= IEEE80211_CHAN_NO_10MHZ;
776 if (cur_chan->max_bw < 20)
777 wiphy_chan->flags |= IEEE80211_CHAN_NO_20MHZ;
778 if (cur_chan->max_bw < 40)
779 wiphy_chan->flags |= IEEE80211_CHAN_NO_HT40;
780 if (cur_chan->max_bw < 80)
781 wiphy_chan->flags |= IEEE80211_CHAN_NO_80MHZ;
782 if (cur_chan->max_bw < 160)
783 wiphy_chan->flags |= IEEE80211_CHAN_NO_160MHZ;
784}
785
786
787static void fill_wiphy_band_channels(struct wiphy *wiphy,
788 struct regulatory_channel *cur_chan_list,
789 uint8_t band_id)
790{
791 uint32_t wiphy_num_chan, wiphy_index;
792 uint32_t chan_cnt;
793 struct ieee80211_channel *wiphy_chan;
794
795 wiphy_num_chan = wiphy->bands[band_id]->n_channels;
796 wiphy_chan = wiphy->bands[band_id]->channels;
797
798 for (wiphy_index = 0; wiphy_index < wiphy_num_chan; wiphy_index++) {
799 for (chan_cnt = 0; chan_cnt < NUM_CHANNELS; chan_cnt++) {
800 if (wiphy_chan[wiphy_index].center_freq ==
801 cur_chan_list[chan_cnt].center_freq) {
802 fill_wiphy_channel(&(wiphy_chan[wiphy_index]),
803 &(cur_chan_list[chan_cnt]));
804 break;
805 }
806 }
807 }
808}
809
810
811/**
812 * hdd_regulatory_init_offload() - regulatory init
813 * @hdd_ctx: hdd context
814 * @wiphy: wiphy
815 *
816 * Return: int
817 */
818static int hdd_regulatory_init_offload(hdd_context_t *hdd_ctx,
819 struct wiphy *wiphy)
820{
821 struct reg_config_vars config_vars;
822 struct regulatory_channel cur_chan_list[NUM_CHANNELS];
823
824 config_vars.enable_11d_support = hdd_ctx->config->Is11dSupportEnabled;
825 config_vars.userspace_ctry_priority =
826 hdd_ctx->config->fSupplicantCountryCodeHasPriority;
827 config_vars.dfs_enabled = hdd_ctx->config->enableDFSChnlScan;
828 config_vars.indoor_chan_enabled =
829 hdd_ctx->config->indoor_channel_support;
830 config_vars.band_capability = hdd_ctx->config->nBandCapability;
831
832 reg_program_config_vars(hdd_ctx, &config_vars);
833 ucfg_reg_set_config_vars(hdd_ctx->hdd_psoc, config_vars);
834 ucfg_reg_get_current_chan_list(hdd_ctx->hdd_pdev, cur_chan_list);
835 fill_wiphy_band_channels(wiphy, cur_chan_list, NL80211_BAND_2GHZ);
836 fill_wiphy_band_channels(wiphy, cur_chan_list, NL80211_BAND_5GHZ);
837
838 return 0;
839}
840
841
842
843int hdd_regulatory_init(hdd_context_t *hdd_ctx, struct wiphy *wiphy)
844{
845 bool offload_enabled;
846 enum dfs_reg dfs_region;
847
848 offload_enabled = ucfg_reg_is_regdb_offloaded(hdd_ctx->hdd_psoc);
849
850 if (offload_enabled && hdd_ctx->config->reg_offload_enabled) {
851 hdd_ctx->reg_offload = true;
852 wiphy->reg_notifier = NULL;
853 wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
854 hdd_regulatory_init_offload(hdd_ctx, wiphy);
855
856 wlan_reg_get_dfs_region(hdd_ctx->hdd_psoc, &dfs_region);
857 cds_set_wma_dfs_region(dfs_region);
858 } else {
859 hdd_ctx->reg_offload = false;
860 wiphy->reg_notifier = hdd_reg_notifier;
861 wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
862 wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
863 hdd_regulatory_init_no_offload(hdd_ctx, wiphy);
864
865 }
866
867 return 0;
868}
869#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
870int hdd_regulatory_init(hdd_context_t *hdd_ctx, struct wiphy *wiphy)
871{
872 hdd_ctx->reg_offload = false;
873 wiphy->reg_notifier = hdd_reg_notifier;
874 wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
875 wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
876 hdd_regulatory_init_no_offload(hdd_ctx, wiphy);
877
878 return 0;
879}
880#else
881int hdd_regulatory_init(hdd_context_t *hdd_ctx, struct wiphy *wiphy)
882{
883 hdd_ctx->reg_offload = false;
884 wiphy->reg_notifier = hdd_reg_notifier;
885 wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS;
886 wiphy->country_ie_pref |= NL80211_COUNTRY_IE_IGNORE_CORE;
887 hdd_regulatory_init_no_offload(hdd_ctx, wiphy);
888
889 return 0;
890}
891#endif