blob: 75066e868f57d0c39365d485fc652452ae6551bc [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>
39#include <wlan_reg_services_api.h>
40#include "cds_reg_service.h"
Amar Singhale4f28ee2015-10-21 14:36:56 -070041
42#define REG_RULE_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
43
44#define REG_RULE_2467_2472 REG_RULE(2467-10, 2472+10, 40, 0, 20, \
Amar Singhale4f28ee2015-10-21 14:36:56 -070045 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
46
Amar Singhal1c944922016-03-23 18:46:49 -070047#define REG_RULE_2484 REG_RULE(2484-10, 2484+10, 20, 0, 20, \
48 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | \
49 NL80211_RRF_NO_OFDM)
50
51#define REG_RULE_5180_5320 REG_RULE(5180-10, 5320+10, 160, 0, 20, \
52 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
53
54#define REG_RULE_5500_5720 REG_RULE(5500-10, 5720+10, 160, 0, 20, \
Amar Singhale4f28ee2015-10-21 14:36:56 -070055 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
56
57#define REG_RULE_5745_5925 REG_RULE(5745-10, 5925+10, 80, 0, 20, \
58 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
59
60static bool init_by_driver;
61static bool init_by_reg_core;
62
63static const struct ieee80211_regdomain
64hdd_world_regrules_60_61_62 = {
65 .n_reg_rules = 6,
66 .alpha2 = "00",
67 .reg_rules = {
68 REG_RULE_2412_2462,
69 REG_RULE_2467_2472,
70 REG_RULE_2484,
71 REG_RULE_5180_5320,
72 REG_RULE_5500_5720,
73 REG_RULE_5745_5925,
74 }
75};
76
77static const struct ieee80211_regdomain
78hdd_world_regrules_63_65 = {
79 .n_reg_rules = 4,
80 .alpha2 = "00",
81 .reg_rules = {
82 REG_RULE_2412_2462,
83 REG_RULE_2467_2472,
84 REG_RULE_5180_5320,
85 REG_RULE_5745_5925,
86 }
87};
88
89static const struct ieee80211_regdomain
90hdd_world_regrules_64 = {
91 .n_reg_rules = 3,
92 .alpha2 = "00",
93 .reg_rules = {
94 REG_RULE_2412_2462,
95 REG_RULE_5180_5320,
96 REG_RULE_5745_5925,
97 }
98};
99
100static const struct ieee80211_regdomain
101hdd_world_regrules_66_69 = {
102 .n_reg_rules = 4,
103 .alpha2 = "00",
104 .reg_rules = {
105 REG_RULE_2412_2462,
106 REG_RULE_5180_5320,
107 REG_RULE_5500_5720,
108 REG_RULE_5745_5925,
109 }
110};
111
112static const struct ieee80211_regdomain
113hdd_world_regrules_67_68_6A_6C = {
114 .n_reg_rules = 5,
115 .alpha2 = "00",
116 .reg_rules = {
117 REG_RULE_2412_2462,
118 REG_RULE_2467_2472,
119 REG_RULE_5180_5320,
120 REG_RULE_5500_5720,
121 REG_RULE_5745_5925,
122 }
123};
124
125/**
126 * hdd_get_world_regrules() - get the appropriate world regrules
127 * @reg: regulatory data
128 *
129 * Return: regulatory rules ptr
130 */
131static const struct ieee80211_regdomain *hdd_get_world_regrules(
132struct regulatory *reg)
133{
Amar Singhal22995112016-01-22 10:42:33 -0800134 struct reg_dmn_pair *regpair =
135 (struct reg_dmn_pair *)reg->regpair;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700136
Amar Singhala7bb01b2016-01-27 11:31:59 -0800137 switch (regpair->reg_dmn_pair) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700138 case 0x60:
139 case 0x61:
140 case 0x62:
141 return &hdd_world_regrules_60_61_62;
142 case 0x63:
143 case 0x65:
144 return &hdd_world_regrules_63_65;
145 case 0x64:
146 return &hdd_world_regrules_64;
147 case 0x66:
148 case 0x69:
149 return &hdd_world_regrules_66_69;
150 case 0x67:
151 case 0x68:
152 case 0x6A:
153 case 0x6C:
154 return &hdd_world_regrules_67_68_6A_6C;
155 default:
156 hdd_warn("invalid world mode in BDF");
157 return &hdd_world_regrules_60_61_62;
158 }
159}
160
161/**
162 * hdd_is_world_regdomain() - whether world regdomain
163 * @reg_domain: integer regulatory domain
164 *
165 * Return: bool
166 */
Jeff Johnson87a24252016-10-05 16:20:52 -0700167static bool hdd_is_world_regdomain(uint32_t reg_domain)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700168{
Amar Singhal5f997862016-08-24 13:17:50 -0700169 uint32_t temp_regd = reg_domain & ~WORLD_ROAMING_FLAG;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700170
Amar Singhal5f997862016-08-24 13:17:50 -0700171 return ((temp_regd & CTRY_FLAG) != CTRY_FLAG) &&
172 ((temp_regd & WORLD_ROAMING_MASK) ==
173 WORLD_ROAMING_PREFIX);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700174}
175
Amar Singhale4f28ee2015-10-21 14:36:56 -0700176/**
177 * hdd_update_regulatory_info() - update regulatory info
178 * @hdd_ctx: hdd context
179 *
180 * Return: void
181 */
182static void hdd_update_regulatory_info(hdd_context_t *hdd_ctx)
183{
184 uint32_t country_code;
185
186 country_code = cds_get_country_from_alpha2(hdd_ctx->reg.alpha2);
187
Amar Singhal5f997862016-08-24 13:17:50 -0700188 hdd_ctx->reg.reg_domain = CTRY_FLAG;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700189 hdd_ctx->reg.reg_domain |= country_code;
190
191 cds_fill_some_regulatory_info(&hdd_ctx->reg);
192
193}
194
195/**
Abhishek Singh3e6172f2016-05-04 16:56:48 +0530196 * hdd_reset_global_reg_params - Reset global static reg params
197 *
198 * This function is helpful in static driver to reset
199 * the global params.
200 *
201 * Return: void
202 */
203void hdd_reset_global_reg_params(void)
204{
205 init_by_driver = false;
206 init_by_reg_core = false;
207}
208
Amar Singhal5cccafe2017-02-15 12:42:58 -0800209static void reg_program_config_vars(hdd_context_t *hdd_ctx,
210 struct reg_config_vars *config_vars)
211{
212 config_vars->enable_11d_support = hdd_ctx->config->Is11dSupportEnabled;
213 config_vars->userspace_ctry_priority =
214 hdd_ctx->config->fSupplicantCountryCodeHasPriority;
215 config_vars->dfs_enabled = hdd_ctx->config->enableDFSChnlScan;
216 config_vars->indoor_chan_enabled =
217 hdd_ctx->config->indoor_channel_support;
218 config_vars->band_capability = hdd_ctx->config->nBandCapability;
219}
220
221
Abhishek Singh3e6172f2016-05-04 16:56:48 +0530222/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700223 * hdd_regulatory_wiphy_init() - regulatory wiphy init
224 * @hdd_ctx: hdd context
225 * @reg: regulatory data
226 * @wiphy: wiphy structure
227 *
228 * Return: void
229 */
230#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
231static void hdd_regulatory_wiphy_init(hdd_context_t *hdd_ctx,
232 struct regulatory *reg,
233 struct wiphy *wiphy)
234{
235 const struct ieee80211_regdomain *reg_rules;
Amar Singhalb7fe2612016-10-19 10:49:58 -0700236 int chan_num;
Amar Singhal6fc66382016-11-09 13:33:33 -0800237 struct ieee80211_channel *chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700238
239 if (hdd_is_world_regdomain(reg->reg_domain)) {
240 reg_rules = hdd_get_world_regrules(reg);
241 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
242 } else if (hdd_ctx->config->fRegChangeDefCountry) {
243 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
244 reg_rules = &hdd_world_regrules_60_61_62;
245 } else {
246 wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
247 reg_rules = &hdd_world_regrules_60_61_62;
248 }
249
250 /*
251 * save the original driver regulatory flags
252 */
253 hdd_ctx->reg.reg_flags = wiphy->regulatory_flags;
254 wiphy_apply_custom_regulatory(wiphy, reg_rules);
255
256 /*
Amar Singhalb7fe2612016-10-19 10:49:58 -0700257 * disable 2.4 Ghz channels that dont have 20 mhz bw
258 */
259 for (chan_num = 0;
Dustin Brown67f16952017-02-03 15:37:53 -0800260 chan_num < wiphy->bands[NL80211_BAND_2GHZ]->n_channels;
Amar Singhalb7fe2612016-10-19 10:49:58 -0700261 chan_num++) {
Dustin Brown67f16952017-02-03 15:37:53 -0800262 chan = &(wiphy->bands[NL80211_BAND_2GHZ]->channels[chan_num]);
Amar Singhal6fc66382016-11-09 13:33:33 -0800263 if (chan->flags & IEEE80211_CHAN_NO_20MHZ)
264 chan->flags |= IEEE80211_CHAN_DISABLED;
Amar Singhalb7fe2612016-10-19 10:49:58 -0700265 }
266
267 /*
Amar Singhale4f28ee2015-10-21 14:36:56 -0700268 * restore the driver regulatory flags since
269 * wiphy_apply_custom_regulatory may have
270 * changed them
271 */
272 wiphy->regulatory_flags = hdd_ctx->reg.reg_flags;
273
274}
275#else
276static void hdd_regulatory_wiphy_init(hdd_context_t *hdd_ctx,
277 struct regulatory *reg,
278 struct wiphy *wiphy)
279{
280 const struct ieee80211_regdomain *reg_rules;
281
282 if (hdd_is_world_regdomain(reg->reg_domain)) {
283 reg_rules = hdd_get_world_regrules(reg);
284 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
285 } else if (hdd_ctx->config->fRegChangeDefCountry) {
286 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
287 reg_rules = &hdd_world_regrules_60_61_62;
288 } else {
289 wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
290 reg_rules = &hdd_world_regrules_60_61_62;
291 }
292
293 /*
294 * save the original driver regulatory flags
295 */
296 hdd_ctx->reg.reg_flags = wiphy->flags;
297 wiphy_apply_custom_regulatory(wiphy, reg_rules);
298
299 /*
300 * restore the driver regulatory flags since
301 * wiphy_apply_custom_regulatory may have
302 * changed them
303 */
304 wiphy->flags = hdd_ctx->reg.reg_flags;
305
306}
307#endif
308
309/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700310 * is_wiphy_custom_regulatory() - is custom regulatory defined
311 * @wiphy: wiphy
312 *
313 * Return: int
314 */
315#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
316static int is_wiphy_custom_regulatory(struct wiphy *wiphy)
317{
318
319 return wiphy->regulatory_flags & REGULATORY_CUSTOM_REG;
320}
321#else
322static int is_wiphy_custom_regulatory(struct wiphy *wiphy)
323{
324 return wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY;
325}
326#endif
327
Amar Singhale4f28ee2015-10-21 14:36:56 -0700328/**
329 * hdd_modify_wiphy() - modify wiphy
330 * @wiphy: wiphy
331 * @chan: channel structure
332 *
333 * Return: void
334 */
335static void hdd_modify_wiphy(struct wiphy *wiphy,
336 struct ieee80211_channel *chan)
337{
338 const struct ieee80211_reg_rule *reg_rule;
339
340 if (is_wiphy_custom_regulatory(wiphy)) {
341 reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
342 if (!IS_ERR(reg_rule)) {
343 chan->flags &= ~IEEE80211_CHAN_DISABLED;
344
345 if (!(reg_rule->flags & NL80211_RRF_DFS)) {
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530346 hdd_info("Remove dfs restriction for %u",
347 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700348 chan->flags &= ~IEEE80211_CHAN_RADAR;
349 }
350
351 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) {
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530352 hdd_info("Remove passive restriction for %u",
353 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700354 chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
355 }
356
357 if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) {
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530358 hdd_info("Remove no ibss restriction for %u",
359 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700360 chan->flags &= ~IEEE80211_CHAN_NO_IBSS;
361 }
362
363 chan->max_power =
364 MBM_TO_DBM(reg_rule->power_rule.max_eirp);
365 }
366 }
367}
368
369/**
370 * hdd_process_regulatory_data() - process regulatory data
371 * @hdd_ctx: hdd context
372 * @wiphy: wiphy
373 * @reset: whether to reset channel data
374 *
375 * Return: void
376 */
377static void hdd_process_regulatory_data(hdd_context_t *hdd_ctx,
378 struct wiphy *wiphy,
379 bool reset)
380{
Amar Singhal388b3f02016-02-10 13:37:18 -0800381 int band_num;
382 int chan_num;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700383 enum channel_enum chan_enum = CHAN_ENUM_1;
384 struct ieee80211_channel *wiphy_chan, *wiphy_chan_144 = NULL;
Amar Singhal388b3f02016-02-10 13:37:18 -0800385 struct regulatory_channel *cds_chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700386 uint8_t band_capability;
387
388 band_capability = hdd_ctx->config->nBandCapability;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700389
Dustin Browna30892e2016-10-12 17:28:36 -0700390 for (band_num = 0; band_num < NUM_NL80211_BANDS; band_num++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700391
Amar Singhal388b3f02016-02-10 13:37:18 -0800392 if (wiphy->bands[band_num] == NULL)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700393 continue;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700394
Amar Singhal388b3f02016-02-10 13:37:18 -0800395 for (chan_num = 0;
Manjeet Singhec402062016-10-27 15:58:01 +0530396 chan_num < wiphy->bands[band_num]->n_channels &&
397 chan_enum < NUM_CHANNELS;
Amar Singhal388b3f02016-02-10 13:37:18 -0800398 chan_num++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700399
Amar Singhal388b3f02016-02-10 13:37:18 -0800400 wiphy_chan =
401 &(wiphy->bands[band_num]->channels[chan_num]);
402 cds_chan = &(reg_channels[chan_enum]);
Amar Singhal5cccafe2017-02-15 12:42:58 -0800403 cds_chan->chan_flags = 0;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700404 if (CHAN_ENUM_144 == chan_enum)
405 wiphy_chan_144 = wiphy_chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700406
Amar Singhal388b3f02016-02-10 13:37:18 -0800407 chan_enum++;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700408
409 if (!reset)
Amar Singhal388b3f02016-02-10 13:37:18 -0800410 hdd_modify_wiphy(wiphy, wiphy_chan);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700411
Amar Singhal388b3f02016-02-10 13:37:18 -0800412 if (wiphy_chan->flags & IEEE80211_CHAN_DISABLED) {
413 cds_chan->state = CHANNEL_STATE_DISABLE;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800414 cds_chan->chan_flags |=
415 REGULATORY_CHAN_DISABLED;
Amar Singhal18517882016-08-08 12:26:20 -0700416 } else if ((wiphy_chan->flags &
417 (IEEE80211_CHAN_RADAR |
Amar Singhal5cccafe2017-02-15 12:42:58 -0800418 IEEE80211_CHAN_PASSIVE_SCAN |
Amar Singhal18517882016-08-08 12:26:20 -0700419 IEEE80211_CHAN_INDOOR_ONLY))) {
420 if ((wiphy_chan->flags &
421 IEEE80211_CHAN_INDOOR_ONLY) &&
422 (false ==
423 hdd_ctx->config->indoor_channel_support))
Amar Singhal388b3f02016-02-10 13:37:18 -0800424 wiphy_chan->flags |=
Amar Singhale4f28ee2015-10-21 14:36:56 -0700425 IEEE80211_CHAN_PASSIVE_SCAN;
Amar Singhal388b3f02016-02-10 13:37:18 -0800426 cds_chan->state = CHANNEL_STATE_DFS;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800427 if (wiphy_chan->flags & IEEE80211_CHAN_RADAR)
428 cds_chan->chan_flags |=
429 REGULATORY_CHAN_RADAR;
430 if (wiphy_chan->flags &
431 IEEE80211_CHAN_PASSIVE_SCAN)
432 cds_chan->chan_flags |=
433 REGULATORY_CHAN_NO_IR;
434 if (wiphy_chan->flags &
435 IEEE80211_CHAN_INDOOR_ONLY)
436 cds_chan->chan_flags |=
437 REGULATORY_CHAN_INDOOR_ONLY;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700438 } else {
Amar Singhal388b3f02016-02-10 13:37:18 -0800439 cds_chan->state = CHANNEL_STATE_ENABLE;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700440 }
Amar Singhal5cccafe2017-02-15 12:42:58 -0800441 cds_chan->tx_power = wiphy_chan->max_power;
442 if (wiphy_chan->flags & IEEE80211_CHAN_NO_10MHZ)
443 cds_chan->max_bw = 5;
444 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_20MHZ)
445 cds_chan->max_bw = 10;
446 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_HT40)
447 cds_chan->max_bw = 20;
448 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_80MHZ)
449 cds_chan->max_bw = 40;
450 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_160MHZ)
451 cds_chan->max_bw = 80;
452 else
453 cds_chan->max_bw = 160;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700454 }
455 }
456
457 if (0 == (hdd_ctx->reg.eeprom_rd_ext &
Sandeep Puligilla985d1ee2017-01-04 16:41:39 -0800458 (1 << WMI_REG_EXT_FCC_CH_144))) {
Amar Singhal388b3f02016-02-10 13:37:18 -0800459 cds_chan = &(reg_channels[CHAN_ENUM_144]);
460 cds_chan->state = CHANNEL_STATE_DISABLE;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700461 if (NULL != wiphy_chan_144)
462 wiphy_chan_144->flags |= IEEE80211_CHAN_DISABLED;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700463 }
Amar Singhal6842e8f2016-02-23 16:30:32 -0800464
465 wlan_hdd_cfg80211_update_band(wiphy, band_capability);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700466}
467
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700468/**
469 * hdd_set_dfs_region() - set the dfs_region
470 * @dfs_region: the dfs_region to set
471 *
472 * Return: void
473 */
474#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
475static void hdd_set_dfs_region(hdd_context_t *hdd_ctx,
Amar Singhal5cccafe2017-02-15 12:42:58 -0800476 enum dfs_reg dfs_reg)
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700477{
Amar Singhal5cccafe2017-02-15 12:42:58 -0800478 wlan_reg_set_dfs_region(hdd_ctx->hdd_psoc, dfs_reg);
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700479}
480#else
481static void hdd_set_dfs_region(hdd_context_t *hdd_ctx,
482 enum dfs_region dfs_reg)
483{
484
485 /* remap the ctl code to dfs region code */
486 switch (hdd_ctx->reg.ctl_5g) {
487 case FCC:
488 cds_put_dfs_region(DFS_FCC_REGION);
489 break;
490 case ETSI:
491 cds_put_dfs_region(DFS_ETSI_REGION);
492 break;
493 case MKK:
494 cds_put_dfs_region(DFS_MKK_REGION);
495 break;
496 default:
497 /* set default dfs_region to FCC */
498 cds_put_dfs_region(DFS_FCC_REGION);
499 break;
500 }
501
502}
503#endif
504
Amar Singhale4f28ee2015-10-21 14:36:56 -0700505/**
Amar Singhal5cccafe2017-02-15 12:42:58 -0800506 * hdd_regulatory_init_no_offload() - regulatory init
Amar Singhale4f28ee2015-10-21 14:36:56 -0700507 * @hdd_ctx: hdd context
508 * @wiphy: wiphy
509 *
510 * Return: int
511 */
Amar Singhal5cccafe2017-02-15 12:42:58 -0800512static int hdd_regulatory_init_no_offload(hdd_context_t *hdd_ctx,
513 struct wiphy *wiphy)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700514{
515 int ret_val;
516 struct regulatory *reg_info;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800517 enum dfs_reg dfs_reg;
518 struct reg_config_vars config_vars;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700519
520 reg_info = &hdd_ctx->reg;
521
Amar Singhale4f28ee2015-10-21 14:36:56 -0700522 ret_val = cds_fill_some_regulatory_info(reg_info);
523 if (ret_val) {
524 hdd_err("incorrect BDF regulatory data");
525 return ret_val;
526 }
527
Dustin Brown38f2b552016-10-04 13:57:46 -0700528 hdd_regulatory_wiphy_init(hdd_ctx, reg_info, wiphy);
529
530 hdd_process_regulatory_data(hdd_ctx, wiphy, true);
531
532 reg_info->cc_src = SOURCE_DRIVER;
533
Amar Singhale4f28ee2015-10-21 14:36:56 -0700534 cds_put_default_country(reg_info->alpha2);
535
Amar Singhale4f28ee2015-10-21 14:36:56 -0700536 cds_fill_and_send_ctl_to_fw(reg_info);
537
Amar Singhal5cccafe2017-02-15 12:42:58 -0800538 hdd_set_dfs_region(hdd_ctx, DFS_FCC_REG);
539 wlan_reg_get_dfs_region(hdd_ctx->hdd_psoc, &dfs_reg);
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700540 cds_set_wma_dfs_region(dfs_reg);
541
Amar Singhal5cccafe2017-02-15 12:42:58 -0800542 reg_program_config_vars(hdd_ctx, &config_vars);
543 ucfg_reg_set_config_vars(hdd_ctx->hdd_psoc, config_vars);
544 ucfg_reg_program_mas_chan_list(hdd_ctx->hdd_psoc,
545 reg_channels,
546 hdd_ctx->reg.alpha2,
547 dfs_reg);
548
Amar Singhale4f28ee2015-10-21 14:36:56 -0700549 return 0;
550}
551
552/**
553 * hdd_program_country_code() - process channel information from country code
554 * @hdd_ctx: hddc context
555 *
556 * Return: void
557 */
558void hdd_program_country_code(hdd_context_t *hdd_ctx)
559{
560 struct wiphy *wiphy = hdd_ctx->wiphy;
561 uint8_t *country_alpha2 = hdd_ctx->reg.alpha2;
562
Abhishek Singh897b27a2017-03-17 11:56:46 +0530563 if (!init_by_reg_core && !init_by_driver) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700564 init_by_driver = true;
565 if (('0' != country_alpha2[0]) ||
Amar Singhal38c5eeb2016-08-22 16:50:01 -0700566 ('0' != country_alpha2[1]))
Amar Singhale4f28ee2015-10-21 14:36:56 -0700567 regulatory_hint(wiphy, country_alpha2);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700568 }
569}
570
571
572/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700573 * hdd_restore_custom_reg_settings() - restore custom reg settings
574 * @wiphy: wiphy structure
575 * @country_alpha2: alpha2 of the country
576 * @reset: whether wiphy is reset
577 *
578 * Return: void
579 */
580#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
581static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
582 uint8_t *country_alpha2,
583 bool *reset)
584{
585}
586#else
587static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
588 uint8_t *country_alpha2,
589 bool *reset)
590{
591 struct ieee80211_supported_band *sband;
Dustin Browna30892e2016-10-12 17:28:36 -0700592 enum nl80211_band band;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700593 struct ieee80211_channel *chan;
594 int i;
595
596 if ((country_alpha2[0] == '0') &&
597 (country_alpha2[1] == '0') &&
598 (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) {
599
Dustin Browna30892e2016-10-12 17:28:36 -0700600 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700601 sband = wiphy->bands[band];
602 if (!sband)
603 continue;
604 for (i = 0; i < sband->n_channels; i++) {
605 chan = &sband->channels[i];
606 chan->flags = chan->orig_flags;
607 chan->max_antenna_gain = chan->orig_mag;
608 chan->max_power = chan->orig_mpwr;
609 }
610 }
611 *reset = true;
612 }
613}
614#endif
615
Amar Singhale4f28ee2015-10-21 14:36:56 -0700616/**
617 * hdd_restore_reg_flags() - restore regulatory flags
618 * @flags: regulatory flags
619 *
620 * Return: void
621 */
622#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
623static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
624{
625 wiphy->regulatory_flags = flags;
626}
627#else
628static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
629{
630 wiphy->flags = flags;
631}
632#endif
633
Amar Singhale4f28ee2015-10-21 14:36:56 -0700634/**
635 * hdd_reg_notifier() - regulatory notifier
636 * @wiphy: wiphy
637 * @request: regulatory request
638 *
639 * Return: void
640 */
641void hdd_reg_notifier(struct wiphy *wiphy,
642 struct regulatory_request *request)
643{
644 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700645 bool reset = false;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800646 enum dfs_reg dfs_reg;
647 struct reg_config_vars config_vars;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700648
649 hdd_info("country: %c%c, initiator %d, dfs_region: %d",
650 request->alpha2[0],
651 request->alpha2[1],
652 request->initiator,
653 request->dfs_region);
654
655 if (NULL == hdd_ctx) {
656 hdd_err("invalid hdd_ctx pointer");
657 return;
658 }
659
660 if (cds_is_driver_unloading() || cds_is_driver_recovering()) {
661 hdd_err("%s: unloading or ssr in progress, ignore",
662 __func__);
663 return;
664 }
665
Dustin Brownc0ad1ec2017-01-26 12:01:32 -0800666 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
667 hdd_err("Driver module is closed; dropping request");
668 return;
669 }
670
Mukul Sharma0c854a02016-10-20 15:36:20 +0530671 if (hdd_ctx->isWiphySuspended == true) {
672 hdd_err("%s: system/cfg80211 is already suspend", __func__);
673 return;
674 }
675
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700676 if (('K' == request->alpha2[0]) &&
677 ('R' == request->alpha2[1]))
Amar Singhal5cccafe2017-02-15 12:42:58 -0800678 request->dfs_region = DFS_KR_REG;
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700679
680 if (('C' == request->alpha2[0]) &&
681 ('N' == request->alpha2[1]))
Amar Singhal5cccafe2017-02-15 12:42:58 -0800682 request->dfs_region = DFS_CN_REG;
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700683
Amar Singhale4f28ee2015-10-21 14:36:56 -0700684 /* first check if this callback is in response to the driver callback */
685
686 switch (request->initiator) {
687 case NL80211_REGDOM_SET_BY_DRIVER:
688 case NL80211_REGDOM_SET_BY_CORE:
689 case NL80211_REGDOM_SET_BY_USER:
690
691 if ((false == init_by_driver) &&
692 (false == init_by_reg_core)) {
693
694 if (NL80211_REGDOM_SET_BY_CORE == request->initiator)
695 return;
696 init_by_reg_core = true;
697 }
698
699 if ((NL80211_REGDOM_SET_BY_DRIVER == request->initiator) &&
700 (true == init_by_driver)) {
701
702 /*
703 * restore the driver regulatory flags since
704 * regulatory_hint may have
705 * changed them
706 */
707 hdd_restore_reg_flags(wiphy, hdd_ctx->reg.reg_flags);
708 }
709
710 if (NL80211_REGDOM_SET_BY_CORE == request->initiator) {
711 hdd_ctx->reg.cc_src = SOURCE_CORE;
712 if (is_wiphy_custom_regulatory(wiphy))
713 reset = true;
Amar Singhal6edf9732016-11-20 21:43:40 -0800714 } else if (NL80211_REGDOM_SET_BY_DRIVER == request->initiator) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700715 hdd_ctx->reg.cc_src = SOURCE_DRIVER;
Amar Singhal6edf9732016-11-20 21:43:40 -0800716 sme_set_cc_src(hdd_ctx->hHal, SOURCE_DRIVER);
717 } else {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700718 hdd_ctx->reg.cc_src = SOURCE_USERSPACE;
719 hdd_restore_custom_reg_settings(wiphy,
720 request->alpha2,
721 &reset);
722 }
723
724 hdd_ctx->reg.alpha2[0] = request->alpha2[0];
725 hdd_ctx->reg.alpha2[1] = request->alpha2[1];
726
727 hdd_update_regulatory_info(hdd_ctx);
728
Amar Singhale4f28ee2015-10-21 14:36:56 -0700729 hdd_process_regulatory_data(hdd_ctx, wiphy, reset);
730
Amar Singhale4f28ee2015-10-21 14:36:56 -0700731 sme_generic_change_country_code(hdd_ctx->hHal,
732 hdd_ctx->reg.alpha2);
733
734 cds_fill_and_send_ctl_to_fw(&hdd_ctx->reg);
735
736 hdd_set_dfs_region(hdd_ctx, request->dfs_region);
Amar Singhal5cccafe2017-02-15 12:42:58 -0800737 wlan_reg_get_dfs_region(hdd_ctx->hdd_psoc, &dfs_reg);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700738 cds_set_wma_dfs_region(dfs_reg);
Amar Singhal5cccafe2017-02-15 12:42:58 -0800739
740 reg_program_config_vars(hdd_ctx, &config_vars);
741 ucfg_reg_set_config_vars(hdd_ctx->hdd_psoc, config_vars);
742 ucfg_reg_program_mas_chan_list(hdd_ctx->hdd_psoc,
743 reg_channels,
744 hdd_ctx->reg.alpha2,
745 dfs_reg);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700746 break;
747
748 default:
749 break;
750 }
751}
Amar Singhal5cccafe2017-02-15 12:42:58 -0800752
753
754#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
755static void fill_wiphy_channel(struct ieee80211_channel *wiphy_chan,
756 struct regulatory_channel *cur_chan)
757{
758
759 wiphy_chan->flags &= ~IEEE80211_CHAN_DISABLED;
760 wiphy_chan->max_power = cur_chan->tx_power;
761
762 if (cur_chan->chan_flags & REGULATORY_CHAN_DISABLED)
763 wiphy_chan->flags |= IEEE80211_CHAN_DISABLED;
764 if (cur_chan->chan_flags & REGULATORY_CHAN_NO_IR)
765 wiphy_chan->flags |= IEEE80211_CHAN_NO_IR;
766 if (cur_chan->chan_flags & REGULATORY_CHAN_RADAR)
767 wiphy_chan->flags |= IEEE80211_CHAN_RADAR;
768 if (cur_chan->chan_flags & REGULATORY_CHAN_NO_OFDM)
769 wiphy_chan->flags |= IEEE80211_CHAN_NO_OFDM;
770 if (cur_chan->chan_flags & REGULATORY_CHAN_INDOOR_ONLY)
771 wiphy_chan->flags |= IEEE80211_CHAN_INDOOR_ONLY;
772
773 if (cur_chan->max_bw < 10)
774 wiphy_chan->flags |= IEEE80211_CHAN_NO_10MHZ;
775 if (cur_chan->max_bw < 20)
776 wiphy_chan->flags |= IEEE80211_CHAN_NO_20MHZ;
777 if (cur_chan->max_bw < 40)
778 wiphy_chan->flags |= IEEE80211_CHAN_NO_HT40;
779 if (cur_chan->max_bw < 80)
780 wiphy_chan->flags |= IEEE80211_CHAN_NO_80MHZ;
781 if (cur_chan->max_bw < 160)
782 wiphy_chan->flags |= IEEE80211_CHAN_NO_160MHZ;
783}
784
785
786static void fill_wiphy_band_channels(struct wiphy *wiphy,
787 struct regulatory_channel *cur_chan_list,
788 uint8_t band_id)
789{
790 uint32_t wiphy_num_chan, wiphy_index;
791 uint32_t chan_cnt;
792 struct ieee80211_channel *wiphy_chan;
793
794 wiphy_num_chan = wiphy->bands[band_id]->n_channels;
795 wiphy_chan = wiphy->bands[band_id]->channels;
796
797 for (wiphy_index = 0; wiphy_index < wiphy_num_chan; wiphy_index++) {
798 for (chan_cnt = 0; chan_cnt < NUM_CHANNELS; chan_cnt++) {
799 if (wiphy_chan[wiphy_index].center_freq ==
800 cur_chan_list[chan_cnt].center_freq) {
801 fill_wiphy_channel(&(wiphy_chan[wiphy_index]),
802 &(cur_chan_list[chan_cnt]));
803 break;
804 }
805 }
806 }
807}
808
809
810/**
811 * hdd_regulatory_init_offload() - regulatory init
812 * @hdd_ctx: hdd context
813 * @wiphy: wiphy
814 *
815 * Return: int
816 */
817static int hdd_regulatory_init_offload(hdd_context_t *hdd_ctx,
818 struct wiphy *wiphy)
819{
820 struct reg_config_vars config_vars;
821 struct regulatory_channel cur_chan_list[NUM_CHANNELS];
822
823 config_vars.enable_11d_support = hdd_ctx->config->Is11dSupportEnabled;
824 config_vars.userspace_ctry_priority =
825 hdd_ctx->config->fSupplicantCountryCodeHasPriority;
826 config_vars.dfs_enabled = hdd_ctx->config->enableDFSChnlScan;
827 config_vars.indoor_chan_enabled =
828 hdd_ctx->config->indoor_channel_support;
829 config_vars.band_capability = hdd_ctx->config->nBandCapability;
830
831 reg_program_config_vars(hdd_ctx, &config_vars);
832 ucfg_reg_set_config_vars(hdd_ctx->hdd_psoc, config_vars);
833 ucfg_reg_get_current_chan_list(hdd_ctx->hdd_pdev, cur_chan_list);
834 fill_wiphy_band_channels(wiphy, cur_chan_list, NL80211_BAND_2GHZ);
835 fill_wiphy_band_channels(wiphy, cur_chan_list, NL80211_BAND_5GHZ);
836
837 return 0;
838}
839
840
841
842int hdd_regulatory_init(hdd_context_t *hdd_ctx, struct wiphy *wiphy)
843{
844 bool offload_enabled;
845 enum dfs_reg dfs_region;
846
847 offload_enabled = ucfg_reg_is_regdb_offloaded(hdd_ctx->hdd_psoc);
848
849 if (offload_enabled && hdd_ctx->config->reg_offload_enabled) {
850 hdd_ctx->reg_offload = true;
851 wiphy->reg_notifier = NULL;
852 wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
853 hdd_regulatory_init_offload(hdd_ctx, wiphy);
854
855 wlan_reg_get_dfs_region(hdd_ctx->hdd_psoc, &dfs_region);
856 cds_set_wma_dfs_region(dfs_region);
857 } else {
858 hdd_ctx->reg_offload = false;
859 wiphy->reg_notifier = hdd_reg_notifier;
860 wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
861 wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
862 hdd_regulatory_init_no_offload(hdd_ctx, wiphy);
863
864 }
865
866 return 0;
867}
868#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
869int hdd_regulatory_init(hdd_context_t *hdd_ctx, struct wiphy *wiphy)
870{
871 hdd_ctx->reg_offload = false;
872 wiphy->reg_notifier = hdd_reg_notifier;
873 wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
874 wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
875 hdd_regulatory_init_no_offload(hdd_ctx, wiphy);
876
877 return 0;
878}
879#else
880int hdd_regulatory_init(hdd_context_t *hdd_ctx, struct wiphy *wiphy)
881{
882 hdd_ctx->reg_offload = false;
883 wiphy->reg_notifier = hdd_reg_notifier;
884 wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS;
885 wiphy->country_ie_pref |= NL80211_COUNTRY_IE_IGNORE_CORE;
886 hdd_regulatory_init_no_offload(hdd_ctx, wiphy);
887
888 return 0;
889}
890#endif