blob: ac7ea8c6cd77c8c8f2660771c6f4ca3cb0b46b1f [file] [log] [blame]
Amar Singhale4f28ee2015-10-21 14:36:56 -07001/*
Will Huang93bc1372018-01-08 18:16:17 +08002 * Copyright (c) 2014-2018 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 Singhal6f8592b2017-04-26 14:31:58 -070037#include <wlan_osif_priv.h>
Amar Singhale4f28ee2015-10-21 14:36:56 -070038#include "wlan_hdd_regulatory.h"
Amar Singhal5cccafe2017-02-15 12:42:58 -080039#include <wlan_reg_ucfg_api.h>
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -070040#include "cds_regdomain.h"
Kiran Kumar Lokere48795792017-07-07 15:34:29 -070041#include "pld_common.h"
Amar Singhale4f28ee2015-10-21 14:36:56 -070042
43#define REG_RULE_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
44
45#define REG_RULE_2467_2472 REG_RULE(2467-10, 2472+10, 40, 0, 20, \
Amar Singhale4f28ee2015-10-21 14:36:56 -070046 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
47
Amar Singhal1c944922016-03-23 18:46:49 -070048#define REG_RULE_2484 REG_RULE(2484-10, 2484+10, 20, 0, 20, \
49 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | \
50 NL80211_RRF_NO_OFDM)
51
52#define REG_RULE_5180_5320 REG_RULE(5180-10, 5320+10, 160, 0, 20, \
53 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
54
55#define REG_RULE_5500_5720 REG_RULE(5500-10, 5720+10, 160, 0, 20, \
Amar Singhale4f28ee2015-10-21 14:36:56 -070056 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
57
58#define REG_RULE_5745_5925 REG_RULE(5745-10, 5925+10, 80, 0, 20, \
59 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
60
61static bool init_by_driver;
62static bool init_by_reg_core;
63
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -070064struct regulatory_channel reg_channels[NUM_CHANNELS];
65
Amar Singhale4f28ee2015-10-21 14:36:56 -070066static const struct ieee80211_regdomain
67hdd_world_regrules_60_61_62 = {
68 .n_reg_rules = 6,
69 .alpha2 = "00",
70 .reg_rules = {
71 REG_RULE_2412_2462,
72 REG_RULE_2467_2472,
73 REG_RULE_2484,
74 REG_RULE_5180_5320,
75 REG_RULE_5500_5720,
76 REG_RULE_5745_5925,
77 }
78};
79
80static const struct ieee80211_regdomain
81hdd_world_regrules_63_65 = {
82 .n_reg_rules = 4,
83 .alpha2 = "00",
84 .reg_rules = {
85 REG_RULE_2412_2462,
86 REG_RULE_2467_2472,
87 REG_RULE_5180_5320,
88 REG_RULE_5745_5925,
89 }
90};
91
92static const struct ieee80211_regdomain
93hdd_world_regrules_64 = {
94 .n_reg_rules = 3,
95 .alpha2 = "00",
96 .reg_rules = {
97 REG_RULE_2412_2462,
98 REG_RULE_5180_5320,
99 REG_RULE_5745_5925,
100 }
101};
102
103static const struct ieee80211_regdomain
104hdd_world_regrules_66_69 = {
105 .n_reg_rules = 4,
106 .alpha2 = "00",
107 .reg_rules = {
108 REG_RULE_2412_2462,
109 REG_RULE_5180_5320,
110 REG_RULE_5500_5720,
111 REG_RULE_5745_5925,
112 }
113};
114
115static const struct ieee80211_regdomain
116hdd_world_regrules_67_68_6A_6C = {
117 .n_reg_rules = 5,
118 .alpha2 = "00",
119 .reg_rules = {
120 REG_RULE_2412_2462,
121 REG_RULE_2467_2472,
122 REG_RULE_5180_5320,
123 REG_RULE_5500_5720,
124 REG_RULE_5745_5925,
125 }
126};
127
128/**
129 * hdd_get_world_regrules() - get the appropriate world regrules
130 * @reg: regulatory data
131 *
132 * Return: regulatory rules ptr
133 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800134#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0))
Amar Singhale4f28ee2015-10-21 14:36:56 -0700135static const struct ieee80211_regdomain *hdd_get_world_regrules(
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -0700136 struct regulatory *reg)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700137{
Amar Singhal22995112016-01-22 10:42:33 -0800138 struct reg_dmn_pair *regpair =
139 (struct reg_dmn_pair *)reg->regpair;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700140
Amar Singhala7bb01b2016-01-27 11:31:59 -0800141 switch (regpair->reg_dmn_pair) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700142 case 0x60:
143 case 0x61:
144 case 0x62:
145 return &hdd_world_regrules_60_61_62;
146 case 0x63:
147 case 0x65:
148 return &hdd_world_regrules_63_65;
149 case 0x64:
150 return &hdd_world_regrules_64;
151 case 0x66:
152 case 0x69:
153 return &hdd_world_regrules_66_69;
154 case 0x67:
155 case 0x68:
156 case 0x6A:
157 case 0x6C:
158 return &hdd_world_regrules_67_68_6A_6C;
159 default:
160 hdd_warn("invalid world mode in BDF");
161 return &hdd_world_regrules_60_61_62;
162 }
163}
164
165/**
166 * hdd_is_world_regdomain() - whether world regdomain
167 * @reg_domain: integer regulatory domain
168 *
169 * Return: bool
170 */
Jeff Johnson87a24252016-10-05 16:20:52 -0700171static bool hdd_is_world_regdomain(uint32_t reg_domain)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700172{
Amar Singhal5f997862016-08-24 13:17:50 -0700173 uint32_t temp_regd = reg_domain & ~WORLD_ROAMING_FLAG;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700174
Amar Singhal5f997862016-08-24 13:17:50 -0700175 return ((temp_regd & CTRY_FLAG) != CTRY_FLAG) &&
176 ((temp_regd & WORLD_ROAMING_MASK) ==
177 WORLD_ROAMING_PREFIX);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700178}
179
Amar Singhale4f28ee2015-10-21 14:36:56 -0700180/**
181 * hdd_update_regulatory_info() - update regulatory info
182 * @hdd_ctx: hdd context
183 *
Kiran Kumar Lokerea6e01c02017-11-17 18:59:44 -0800184 * Return: Error Code
Amar Singhale4f28ee2015-10-21 14:36:56 -0700185 */
Kiran Kumar Lokerea6e01c02017-11-17 18:59:44 -0800186static int hdd_update_regulatory_info(struct hdd_context *hdd_ctx)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700187{
188 uint32_t country_code;
189
190 country_code = cds_get_country_from_alpha2(hdd_ctx->reg.alpha2);
191
Amar Singhal5f997862016-08-24 13:17:50 -0700192 hdd_ctx->reg.reg_domain = CTRY_FLAG;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700193 hdd_ctx->reg.reg_domain |= country_code;
194
Kiran Kumar Lokerea6e01c02017-11-17 18:59:44 -0800195 return cds_fill_some_regulatory_info(&hdd_ctx->reg);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700196
197}
Paul Zhanga05a0252018-01-22 11:08:21 +0800198#endif
Amar Singhale4f28ee2015-10-21 14:36:56 -0700199
200/**
Abhishek Singh3e6172f2016-05-04 16:56:48 +0530201 * hdd_reset_global_reg_params - Reset global static reg params
202 *
203 * This function is helpful in static driver to reset
204 * the global params.
205 *
206 * Return: void
207 */
208void hdd_reset_global_reg_params(void)
209{
210 init_by_driver = false;
211 init_by_reg_core = false;
212}
213
Jeff Johnson4af78662017-08-28 11:44:08 -0700214static void reg_program_config_vars(struct hdd_context *hdd_ctx,
Amar Singhal5cccafe2017-02-15 12:42:58 -0800215 struct reg_config_vars *config_vars)
216{
217 config_vars->enable_11d_support = hdd_ctx->config->Is11dSupportEnabled;
Amar Singhale4a2dd52017-08-07 13:59:05 -0700218 config_vars->scan_11d_interval = hdd_ctx->config->scan_11d_interval;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800219 config_vars->userspace_ctry_priority =
220 hdd_ctx->config->fSupplicantCountryCodeHasPriority;
221 config_vars->dfs_enabled = hdd_ctx->config->enableDFSChnlScan;
222 config_vars->indoor_chan_enabled =
223 hdd_ctx->config->indoor_channel_support;
224 config_vars->band_capability = hdd_ctx->config->nBandCapability;
Tushnim Bhattacharyya3efa49a2017-07-18 15:43:09 -0700225 config_vars->restart_beaconing = hdd_ctx->config->
226 restart_beaconing_on_chan_avoid_event;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800227}
228
229
Abhishek Singh3e6172f2016-05-04 16:56:48 +0530230/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700231 * hdd_regulatory_wiphy_init() - regulatory wiphy init
232 * @hdd_ctx: hdd context
233 * @reg: regulatory data
234 * @wiphy: wiphy structure
235 *
236 * Return: void
237 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800238#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
239#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
Jeff Johnson4af78662017-08-28 11:44:08 -0700240static void hdd_regulatory_wiphy_init(struct hdd_context *hdd_ctx,
Amar Singhale4f28ee2015-10-21 14:36:56 -0700241 struct regulatory *reg,
242 struct wiphy *wiphy)
243{
244 const struct ieee80211_regdomain *reg_rules;
Amar Singhalb7fe2612016-10-19 10:49:58 -0700245 int chan_num;
Amar Singhal6fc66382016-11-09 13:33:33 -0800246 struct ieee80211_channel *chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700247
248 if (hdd_is_world_regdomain(reg->reg_domain)) {
249 reg_rules = hdd_get_world_regrules(reg);
250 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
251 } else if (hdd_ctx->config->fRegChangeDefCountry) {
252 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
253 reg_rules = &hdd_world_regrules_60_61_62;
254 } else {
255 wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
256 reg_rules = &hdd_world_regrules_60_61_62;
257 }
258
259 /*
260 * save the original driver regulatory flags
261 */
262 hdd_ctx->reg.reg_flags = wiphy->regulatory_flags;
263 wiphy_apply_custom_regulatory(wiphy, reg_rules);
264
265 /*
Amar Singhalb7fe2612016-10-19 10:49:58 -0700266 * disable 2.4 Ghz channels that dont have 20 mhz bw
267 */
268 for (chan_num = 0;
Srinivas Girigowda11c28e02017-06-27 20:06:21 -0700269 chan_num < wiphy->bands[HDD_NL80211_BAND_2GHZ]->n_channels;
Amar Singhalb7fe2612016-10-19 10:49:58 -0700270 chan_num++) {
Srinivas Girigowda11c28e02017-06-27 20:06:21 -0700271 chan = &(wiphy->bands[HDD_NL80211_BAND_2GHZ]->channels[chan_num]);
Amar Singhal6fc66382016-11-09 13:33:33 -0800272 if (chan->flags & IEEE80211_CHAN_NO_20MHZ)
273 chan->flags |= IEEE80211_CHAN_DISABLED;
Amar Singhalb7fe2612016-10-19 10:49:58 -0700274 }
275
276 /*
Amar Singhale4f28ee2015-10-21 14:36:56 -0700277 * restore the driver regulatory flags since
278 * wiphy_apply_custom_regulatory may have
279 * changed them
280 */
281 wiphy->regulatory_flags = hdd_ctx->reg.reg_flags;
282
283}
284#else
Jeff Johnson4af78662017-08-28 11:44:08 -0700285static void hdd_regulatory_wiphy_init(struct hdd_context *hdd_ctx,
Amar Singhale4f28ee2015-10-21 14:36:56 -0700286 struct regulatory *reg,
287 struct wiphy *wiphy)
288{
289 const struct ieee80211_regdomain *reg_rules;
290
291 if (hdd_is_world_regdomain(reg->reg_domain)) {
292 reg_rules = hdd_get_world_regrules(reg);
293 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
294 } else if (hdd_ctx->config->fRegChangeDefCountry) {
295 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
296 reg_rules = &hdd_world_regrules_60_61_62;
297 } else {
298 wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
299 reg_rules = &hdd_world_regrules_60_61_62;
300 }
301
302 /*
303 * save the original driver regulatory flags
304 */
305 hdd_ctx->reg.reg_flags = wiphy->flags;
306 wiphy_apply_custom_regulatory(wiphy, reg_rules);
307
308 /*
309 * restore the driver regulatory flags since
310 * wiphy_apply_custom_regulatory may have
311 * changed them
312 */
313 wiphy->flags = hdd_ctx->reg.reg_flags;
314
315}
316#endif
317
318/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700319 * is_wiphy_custom_regulatory() - is custom regulatory defined
320 * @wiphy: wiphy
321 *
322 * Return: int
323 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800324#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
325#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700326static int is_wiphy_custom_regulatory(struct wiphy *wiphy)
327{
328
329 return wiphy->regulatory_flags & REGULATORY_CUSTOM_REG;
330}
331#else
332static int is_wiphy_custom_regulatory(struct wiphy *wiphy)
333{
334 return wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY;
335}
336#endif
337
Amar Singhale4f28ee2015-10-21 14:36:56 -0700338/**
339 * hdd_modify_wiphy() - modify wiphy
340 * @wiphy: wiphy
341 * @chan: channel structure
342 *
343 * Return: void
344 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800345#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0))
Amar Singhale4f28ee2015-10-21 14:36:56 -0700346static void hdd_modify_wiphy(struct wiphy *wiphy,
347 struct ieee80211_channel *chan)
348{
349 const struct ieee80211_reg_rule *reg_rule;
350
351 if (is_wiphy_custom_regulatory(wiphy)) {
352 reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
353 if (!IS_ERR(reg_rule)) {
354 chan->flags &= ~IEEE80211_CHAN_DISABLED;
355
356 if (!(reg_rule->flags & NL80211_RRF_DFS)) {
Arunk Khandavalliae44d892017-06-29 15:28:24 +0530357 hdd_debug("Remove dfs restriction for %u",
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530358 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700359 chan->flags &= ~IEEE80211_CHAN_RADAR;
360 }
361
362 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) {
Arunk Khandavalliae44d892017-06-29 15:28:24 +0530363 hdd_debug("Remove passive restriction for %u",
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530364 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700365 chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
366 }
367
368 if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) {
Arunk Khandavalliae44d892017-06-29 15:28:24 +0530369 hdd_debug("Remove no ibss restriction for %u",
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530370 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700371 chan->flags &= ~IEEE80211_CHAN_NO_IBSS;
372 }
373
374 chan->max_power =
375 MBM_TO_DBM(reg_rule->power_rule.max_eirp);
376 }
377 }
378}
Paul Zhanga05a0252018-01-22 11:08:21 +0800379#endif
380
381/**
382 * hdd_set_dfs_region() - set the dfs_region
383 * @dfs_region: the dfs_region to set
384 *
385 * Return: void
386 */
387#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
388#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
389static void hdd_set_dfs_region(struct hdd_context *hdd_ctx,
390 enum dfs_reg dfs_reg)
391{
392 wlan_reg_set_dfs_region(hdd_ctx->hdd_pdev, dfs_reg);
393}
394#else
395static void hdd_set_dfs_region(struct hdd_context *hdd_ctx,
396 enum dfs_region dfs_reg)
397{
398 /* remap the ctl code to dfs region code */
399 switch (hdd_ctx->reg.ctl_5g) {
400 case FCC:
401 cds_put_dfs_region(DFS_FCC_REGION);
402 break;
403 case ETSI:
404 cds_put_dfs_region(DFS_ETSI_REGION);
405 break;
406 case MKK:
407 cds_put_dfs_region(DFS_MKK_REGION);
408 break;
409 default:
410 /* set default dfs_region to FCC */
411 cds_put_dfs_region(DFS_FCC_REGION);
412 break;
413 }
414}
415#endif
Amar Singhale4f28ee2015-10-21 14:36:56 -0700416
417/**
418 * hdd_process_regulatory_data() - process regulatory data
419 * @hdd_ctx: hdd context
420 * @wiphy: wiphy
421 * @reset: whether to reset channel data
422 *
423 * Return: void
424 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800425#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0))
Jeff Johnson4af78662017-08-28 11:44:08 -0700426static void hdd_process_regulatory_data(struct hdd_context *hdd_ctx,
Amar Singhale4f28ee2015-10-21 14:36:56 -0700427 struct wiphy *wiphy,
428 bool reset)
429{
Amar Singhal388b3f02016-02-10 13:37:18 -0800430 int band_num;
431 int chan_num;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700432 enum channel_enum chan_enum = CHAN_ENUM_1;
433 struct ieee80211_channel *wiphy_chan, *wiphy_chan_144 = NULL;
Amar Singhal388b3f02016-02-10 13:37:18 -0800434 struct regulatory_channel *cds_chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700435 uint8_t band_capability;
436
Amar Singhal58b45ef2017-08-01 13:43:54 -0700437 band_capability = hdd_ctx->curr_band;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700438
Srinivas Girigowda5da651b2017-08-04 11:22:54 -0700439 for (band_num = 0; band_num < HDD_NUM_NL80211_BANDS; band_num++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700440
Amar Singhal388b3f02016-02-10 13:37:18 -0800441 if (wiphy->bands[band_num] == NULL)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700442 continue;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700443
Amar Singhal388b3f02016-02-10 13:37:18 -0800444 for (chan_num = 0;
Manjeet Singhec402062016-10-27 15:58:01 +0530445 chan_num < wiphy->bands[band_num]->n_channels &&
446 chan_enum < NUM_CHANNELS;
Amar Singhal388b3f02016-02-10 13:37:18 -0800447 chan_num++) {
Amar Singhal388b3f02016-02-10 13:37:18 -0800448 wiphy_chan =
449 &(wiphy->bands[band_num]->channels[chan_num]);
450 cds_chan = &(reg_channels[chan_enum]);
Amar Singhal5cccafe2017-02-15 12:42:58 -0800451 cds_chan->chan_flags = 0;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700452 if (CHAN_ENUM_144 == chan_enum)
453 wiphy_chan_144 = wiphy_chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700454
Amar Singhal388b3f02016-02-10 13:37:18 -0800455 chan_enum++;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700456
457 if (!reset)
Amar Singhal388b3f02016-02-10 13:37:18 -0800458 hdd_modify_wiphy(wiphy, wiphy_chan);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700459
Amar Singhal388b3f02016-02-10 13:37:18 -0800460 if (wiphy_chan->flags & IEEE80211_CHAN_DISABLED) {
461 cds_chan->state = CHANNEL_STATE_DISABLE;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800462 cds_chan->chan_flags |=
463 REGULATORY_CHAN_DISABLED;
Amar Singhal6f8592b2017-04-26 14:31:58 -0700464 } else if (wiphy_chan->flags &
Amar Singhal18517882016-08-08 12:26:20 -0700465 (IEEE80211_CHAN_RADAR |
Amar Singhal6f8592b2017-04-26 14:31:58 -0700466 IEEE80211_CHAN_PASSIVE_SCAN)) {
Amar Singhal388b3f02016-02-10 13:37:18 -0800467 cds_chan->state = CHANNEL_STATE_DFS;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800468 if (wiphy_chan->flags & IEEE80211_CHAN_RADAR)
469 cds_chan->chan_flags |=
470 REGULATORY_CHAN_RADAR;
471 if (wiphy_chan->flags &
472 IEEE80211_CHAN_PASSIVE_SCAN)
473 cds_chan->chan_flags |=
474 REGULATORY_CHAN_NO_IR;
Amar Singhal6f8592b2017-04-26 14:31:58 -0700475 } else if (wiphy_chan->flags &
476 IEEE80211_CHAN_INDOOR_ONLY) {
477 cds_chan->chan_flags |=
478 REGULATORY_CHAN_INDOOR_ONLY;
479 if (hdd_ctx->config->indoor_channel_support
480 == false) {
481 cds_chan->state = CHANNEL_STATE_DFS;
482 wiphy_chan->flags |=
483 IEEE80211_CHAN_PASSIVE_SCAN;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800484 cds_chan->chan_flags |=
Amar Singhal6f8592b2017-04-26 14:31:58 -0700485 REGULATORY_CHAN_NO_IR;
486 } else
487 cds_chan->state = CHANNEL_STATE_ENABLE;
488 } else
Amar Singhal388b3f02016-02-10 13:37:18 -0800489 cds_chan->state = CHANNEL_STATE_ENABLE;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800490 cds_chan->tx_power = wiphy_chan->max_power;
491 if (wiphy_chan->flags & IEEE80211_CHAN_NO_10MHZ)
492 cds_chan->max_bw = 5;
493 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_20MHZ)
494 cds_chan->max_bw = 10;
Krunal Soni408690d2017-05-03 18:32:35 -0700495 /*
496 * IEEE80211_CHAN_NO_HT40 is defined as 0x30 in kernel
497 * 4th BIT representing IEEE80211_CHAN_NO_HT40PLUS
498 * 5th BIT representing IEEE80211_CHAN_NO_HT40MINUS
499 *
500 * In order to claim no 40Mhz support value of
501 * wiphy_chan->flags needs to be 0x30.
502 * 0x20 and 0x10 values shows that either HT40+ or
503 * HT40- is not supported based on BIT set but they
504 * can support 40Mhz Operation.
505 */
506 else if ((wiphy_chan->flags & IEEE80211_CHAN_NO_HT40) ==
507 IEEE80211_CHAN_NO_HT40)
Amar Singhal5cccafe2017-02-15 12:42:58 -0800508 cds_chan->max_bw = 20;
509 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_80MHZ)
510 cds_chan->max_bw = 40;
511 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_160MHZ)
512 cds_chan->max_bw = 80;
513 else
514 cds_chan->max_bw = 160;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700515 }
516 }
517
518 if (0 == (hdd_ctx->reg.eeprom_rd_ext &
Sandeep Puligilla985d1ee2017-01-04 16:41:39 -0800519 (1 << WMI_REG_EXT_FCC_CH_144))) {
Amar Singhal388b3f02016-02-10 13:37:18 -0800520 cds_chan = &(reg_channels[CHAN_ENUM_144]);
521 cds_chan->state = CHANNEL_STATE_DISABLE;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700522 if (NULL != wiphy_chan_144)
523 wiphy_chan_144->flags |= IEEE80211_CHAN_DISABLED;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700524 }
Amar Singhal6842e8f2016-02-23 16:30:32 -0800525
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -0700526 wlan_hdd_cfg80211_update_band(hdd_ctx, wiphy, band_capability);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700527}
528
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700529
Amar Singhale4f28ee2015-10-21 14:36:56 -0700530/**
Amar Singhal5cccafe2017-02-15 12:42:58 -0800531 * hdd_regulatory_init_no_offload() - regulatory init
Amar Singhale4f28ee2015-10-21 14:36:56 -0700532 * @hdd_ctx: hdd context
533 * @wiphy: wiphy
534 *
535 * Return: int
536 */
Jeff Johnson4af78662017-08-28 11:44:08 -0700537static int hdd_regulatory_init_no_offload(struct hdd_context *hdd_ctx,
Amar Singhal5cccafe2017-02-15 12:42:58 -0800538 struct wiphy *wiphy)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700539{
540 int ret_val;
541 struct regulatory *reg_info;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800542 enum dfs_reg dfs_reg;
543 struct reg_config_vars config_vars;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700544
545 reg_info = &hdd_ctx->reg;
546
Amar Singhale4f28ee2015-10-21 14:36:56 -0700547 ret_val = cds_fill_some_regulatory_info(reg_info);
548 if (ret_val) {
549 hdd_err("incorrect BDF regulatory data");
550 return ret_val;
551 }
552
Amar Singhal52385672017-09-01 14:26:40 -0700553 hdd_set_dfs_region(hdd_ctx, DFS_FCC_REG);
554
Dustin Brown38f2b552016-10-04 13:57:46 -0700555 hdd_regulatory_wiphy_init(hdd_ctx, reg_info, wiphy);
556
557 hdd_process_regulatory_data(hdd_ctx, wiphy, true);
558
559 reg_info->cc_src = SOURCE_DRIVER;
560
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -0700561 ucfg_reg_set_default_country(hdd_ctx->hdd_psoc, reg_info->alpha2);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700562
Amar Singhale4f28ee2015-10-21 14:36:56 -0700563 cds_fill_and_send_ctl_to_fw(reg_info);
564
Amar Singhal7f55e342017-05-24 15:23:06 -0700565 wlan_reg_get_dfs_region(hdd_ctx->hdd_pdev, &dfs_reg);
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700566
Amar Singhal5cccafe2017-02-15 12:42:58 -0800567 reg_program_config_vars(hdd_ctx, &config_vars);
568 ucfg_reg_set_config_vars(hdd_ctx->hdd_psoc, config_vars);
569 ucfg_reg_program_mas_chan_list(hdd_ctx->hdd_psoc,
570 reg_channels,
571 hdd_ctx->reg.alpha2,
572 dfs_reg);
573
Amar Singhale4f28ee2015-10-21 14:36:56 -0700574 return 0;
575}
Paul Zhanga05a0252018-01-22 11:08:21 +0800576#endif
Amar Singhale4f28ee2015-10-21 14:36:56 -0700577
578/**
579 * hdd_program_country_code() - process channel information from country code
580 * @hdd_ctx: hddc context
581 *
582 * Return: void
583 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800584#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
585void hdd_program_country_code(struct hdd_context *hdd_ctx)
586{
587}
588#else
Jeff Johnson4af78662017-08-28 11:44:08 -0700589void hdd_program_country_code(struct hdd_context *hdd_ctx)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700590{
591 struct wiphy *wiphy = hdd_ctx->wiphy;
592 uint8_t *country_alpha2 = hdd_ctx->reg.alpha2;
593
Abhishek Singh897b27a2017-03-17 11:56:46 +0530594 if (!init_by_reg_core && !init_by_driver) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700595 init_by_driver = true;
596 if (('0' != country_alpha2[0]) ||
Amar Singhal38c5eeb2016-08-22 16:50:01 -0700597 ('0' != country_alpha2[1]))
Amar Singhale4f28ee2015-10-21 14:36:56 -0700598 regulatory_hint(wiphy, country_alpha2);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700599 }
600}
Paul Zhanga05a0252018-01-22 11:08:21 +0800601#endif
Amar Singhale4f28ee2015-10-21 14:36:56 -0700602
Jeff Johnson4af78662017-08-28 11:44:08 -0700603int hdd_reg_set_country(struct hdd_context *hdd_ctx, char *country_code)
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -0700604{
605 int err;
Amar Singhal6f8592b2017-04-26 14:31:58 -0700606 QDF_STATUS status = QDF_STATUS_SUCCESS;
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -0700607
608 /* validation */
609 err = wlan_hdd_validate_context(hdd_ctx);
610 if (err)
611 return err;
612
613 if (!country_code) {
614 hdd_err("country_code is null");
615 return -EINVAL;
616 }
617
Paul Zhanga05a0252018-01-22 11:08:21 +0800618 status = ucfg_reg_set_country(hdd_ctx->hdd_pdev, country_code);
Amar Singhal6f8592b2017-04-26 14:31:58 -0700619
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -0700620 if (QDF_IS_STATUS_ERROR(status))
621 hdd_err("Failed to set country");
622
623 return qdf_status_to_os_return(status);
624}
Amar Singhale4f28ee2015-10-21 14:36:56 -0700625
626/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700627 * hdd_restore_custom_reg_settings() - restore custom reg settings
628 * @wiphy: wiphy structure
629 * @country_alpha2: alpha2 of the country
630 * @reset: whether wiphy is reset
631 *
632 * Return: void
633 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800634#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
635#elif (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700636static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
637 uint8_t *country_alpha2,
638 bool *reset)
639{
640}
641#else
642static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
643 uint8_t *country_alpha2,
644 bool *reset)
645{
646 struct ieee80211_supported_band *sband;
Dustin Browna30892e2016-10-12 17:28:36 -0700647 enum nl80211_band band;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700648 struct ieee80211_channel *chan;
649 int i;
650
651 if ((country_alpha2[0] == '0') &&
652 (country_alpha2[1] == '0') &&
653 (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) {
654
Srinivas Girigowda5da651b2017-08-04 11:22:54 -0700655 for (band = 0; band < HDD_NUM_NL80211_BANDS; band++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700656 sband = wiphy->bands[band];
657 if (!sband)
658 continue;
659 for (i = 0; i < sband->n_channels; i++) {
660 chan = &sband->channels[i];
661 chan->flags = chan->orig_flags;
662 chan->max_antenna_gain = chan->orig_mag;
663 chan->max_power = chan->orig_mpwr;
664 }
665 }
666 *reset = true;
667 }
668}
669#endif
670
Amar Singhale4f28ee2015-10-21 14:36:56 -0700671/**
672 * hdd_restore_reg_flags() - restore regulatory flags
673 * @flags: regulatory flags
674 *
675 * Return: void
676 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800677#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
678#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700679static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
680{
681 wiphy->regulatory_flags = flags;
682}
683#else
684static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
685{
686 wiphy->flags = flags;
687}
688#endif
689
Amar Singhale4f28ee2015-10-21 14:36:56 -0700690/**
691 * hdd_reg_notifier() - regulatory notifier
692 * @wiphy: wiphy
693 * @request: regulatory request
694 *
695 * Return: void
696 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800697#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
698void hdd_reg_notifier(struct wiphy *wiphy,
699 struct regulatory_request *request)
700{
701 QDF_STATUS status = QDF_STATUS_SUCCESS;
702 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
703
704 hdd_debug("country: %c%c, initiator %d, dfs_region: %d",
705 request->alpha2[0],
706 request->alpha2[1],
707 request->initiator,
708 request->dfs_region);
709
710 switch (request->initiator) {
Paul Zhanga05a0252018-01-22 11:08:21 +0800711 case NL80211_REGDOM_SET_BY_CORE:
Amar Singhal2d812012018-02-03 15:06:47 +0800712 if (pld_get_driver_load_cnt(hdd_ctx->parent_dev) == 0) {
713 hdd_debug("ignore the 1st time notifier from CORE");
714 return;
715 }
716 /* fall through to set country */
717 case NL80211_REGDOM_SET_BY_USER:
Paul Zhanga05a0252018-01-22 11:08:21 +0800718 status = ucfg_reg_set_country(hdd_ctx->hdd_pdev,
719 request->alpha2);
720 break;
721 case NL80211_REGDOM_SET_BY_COUNTRY_IE:
722 case NL80211_REGDOM_SET_BY_DRIVER:
723 default:
724 break;
725 }
726
727 if (QDF_IS_STATUS_ERROR(status))
728 hdd_err("Failed to set country");
729}
730#else
Amar Singhale4f28ee2015-10-21 14:36:56 -0700731void hdd_reg_notifier(struct wiphy *wiphy,
732 struct regulatory_request *request)
733{
Jeff Johnson4af78662017-08-28 11:44:08 -0700734 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700735 bool reset = false;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800736 enum dfs_reg dfs_reg;
737 struct reg_config_vars config_vars;
Kiran Kumar Lokerea6e01c02017-11-17 18:59:44 -0800738 int ret_val;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700739
Yeshwanth Sriram Guntuka52bc6bb2017-05-02 16:57:13 +0530740 hdd_debug("country: %c%c, initiator %d, dfs_region: %d",
Amar Singhale4f28ee2015-10-21 14:36:56 -0700741 request->alpha2[0],
742 request->alpha2[1],
743 request->initiator,
744 request->dfs_region);
745
746 if (NULL == hdd_ctx) {
747 hdd_err("invalid hdd_ctx pointer");
748 return;
749 }
750
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +0530751 if (cds_is_driver_unloading() || cds_is_driver_recovering() ||
752 cds_is_driver_in_bad_state()) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700753 hdd_err("%s: unloading or ssr in progress, ignore",
754 __func__);
755 return;
756 }
757
Dustin Brownc0ad1ec2017-01-26 12:01:32 -0800758 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
759 hdd_err("Driver module is closed; dropping request");
760 return;
761 }
762
Jeff Johnson214671b2017-10-30 19:45:23 -0700763 if (hdd_ctx->is_wiphy_suspended == true) {
Mukul Sharma0c854a02016-10-20 15:36:20 +0530764 hdd_err("%s: system/cfg80211 is already suspend", __func__);
765 return;
766 }
767
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700768 if (('K' == request->alpha2[0]) &&
769 ('R' == request->alpha2[1]))
Srinivas Girigowdad06f2cf2017-06-14 13:32:00 -0700770 request->dfs_region = (enum nl80211_dfs_regions) DFS_KR_REG;
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700771
772 if (('C' == request->alpha2[0]) &&
773 ('N' == request->alpha2[1]))
Srinivas Girigowdad06f2cf2017-06-14 13:32:00 -0700774 request->dfs_region = (enum nl80211_dfs_regions) DFS_CN_REG;
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700775
Amar Singhale4f28ee2015-10-21 14:36:56 -0700776 /* first check if this callback is in response to the driver callback */
777
778 switch (request->initiator) {
779 case NL80211_REGDOM_SET_BY_DRIVER:
780 case NL80211_REGDOM_SET_BY_CORE:
781 case NL80211_REGDOM_SET_BY_USER:
782
783 if ((false == init_by_driver) &&
784 (false == init_by_reg_core)) {
785
786 if (NL80211_REGDOM_SET_BY_CORE == request->initiator)
787 return;
788 init_by_reg_core = true;
789 }
790
791 if ((NL80211_REGDOM_SET_BY_DRIVER == request->initiator) &&
792 (true == init_by_driver)) {
793
794 /*
795 * restore the driver regulatory flags since
796 * regulatory_hint may have
797 * changed them
798 */
799 hdd_restore_reg_flags(wiphy, hdd_ctx->reg.reg_flags);
800 }
801
802 if (NL80211_REGDOM_SET_BY_CORE == request->initiator) {
803 hdd_ctx->reg.cc_src = SOURCE_CORE;
804 if (is_wiphy_custom_regulatory(wiphy))
805 reset = true;
Amar Singhal6edf9732016-11-20 21:43:40 -0800806 } else if (NL80211_REGDOM_SET_BY_DRIVER == request->initiator) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700807 hdd_ctx->reg.cc_src = SOURCE_DRIVER;
Amar Singhal6edf9732016-11-20 21:43:40 -0800808 sme_set_cc_src(hdd_ctx->hHal, SOURCE_DRIVER);
809 } else {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700810 hdd_ctx->reg.cc_src = SOURCE_USERSPACE;
811 hdd_restore_custom_reg_settings(wiphy,
812 request->alpha2,
813 &reset);
814 }
815
816 hdd_ctx->reg.alpha2[0] = request->alpha2[0];
817 hdd_ctx->reg.alpha2[1] = request->alpha2[1];
818
Kiran Kumar Lokerea6e01c02017-11-17 18:59:44 -0800819 ret_val = hdd_update_regulatory_info(hdd_ctx);
820 if (ret_val) {
821 hdd_err("invalid reg info, do not process");
822 return;
823 }
Amar Singhale4f28ee2015-10-21 14:36:56 -0700824
Amar Singhale4f28ee2015-10-21 14:36:56 -0700825 hdd_process_regulatory_data(hdd_ctx, wiphy, reset);
826
Amar Singhale4f28ee2015-10-21 14:36:56 -0700827 sme_generic_change_country_code(hdd_ctx->hHal,
828 hdd_ctx->reg.alpha2);
829
830 cds_fill_and_send_ctl_to_fw(&hdd_ctx->reg);
831
832 hdd_set_dfs_region(hdd_ctx, request->dfs_region);
Amar Singhal7f55e342017-05-24 15:23:06 -0700833 wlan_reg_get_dfs_region(hdd_ctx->hdd_pdev, &dfs_reg);
Amar Singhal5cccafe2017-02-15 12:42:58 -0800834
835 reg_program_config_vars(hdd_ctx, &config_vars);
836 ucfg_reg_set_config_vars(hdd_ctx->hdd_psoc, config_vars);
837 ucfg_reg_program_mas_chan_list(hdd_ctx->hdd_psoc,
838 reg_channels,
839 hdd_ctx->reg.alpha2,
840 dfs_reg);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700841 break;
842
843 default:
844 break;
845 }
846}
Paul Zhanga05a0252018-01-22 11:08:21 +0800847#endif
Amar Singhal5cccafe2017-02-15 12:42:58 -0800848
849#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
850static void fill_wiphy_channel(struct ieee80211_channel *wiphy_chan,
851 struct regulatory_channel *cur_chan)
852{
853
Paul Zhanga05a0252018-01-22 11:08:21 +0800854 wiphy_chan->flags = 0;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800855 wiphy_chan->max_power = cur_chan->tx_power;
856
857 if (cur_chan->chan_flags & REGULATORY_CHAN_DISABLED)
858 wiphy_chan->flags |= IEEE80211_CHAN_DISABLED;
859 if (cur_chan->chan_flags & REGULATORY_CHAN_NO_IR)
860 wiphy_chan->flags |= IEEE80211_CHAN_NO_IR;
861 if (cur_chan->chan_flags & REGULATORY_CHAN_RADAR)
862 wiphy_chan->flags |= IEEE80211_CHAN_RADAR;
863 if (cur_chan->chan_flags & REGULATORY_CHAN_NO_OFDM)
864 wiphy_chan->flags |= IEEE80211_CHAN_NO_OFDM;
865 if (cur_chan->chan_flags & REGULATORY_CHAN_INDOOR_ONLY)
866 wiphy_chan->flags |= IEEE80211_CHAN_INDOOR_ONLY;
867
868 if (cur_chan->max_bw < 10)
869 wiphy_chan->flags |= IEEE80211_CHAN_NO_10MHZ;
870 if (cur_chan->max_bw < 20)
871 wiphy_chan->flags |= IEEE80211_CHAN_NO_20MHZ;
872 if (cur_chan->max_bw < 40)
873 wiphy_chan->flags |= IEEE80211_CHAN_NO_HT40;
874 if (cur_chan->max_bw < 80)
875 wiphy_chan->flags |= IEEE80211_CHAN_NO_80MHZ;
876 if (cur_chan->max_bw < 160)
877 wiphy_chan->flags |= IEEE80211_CHAN_NO_160MHZ;
878}
879
880
881static void fill_wiphy_band_channels(struct wiphy *wiphy,
882 struct regulatory_channel *cur_chan_list,
883 uint8_t band_id)
884{
885 uint32_t wiphy_num_chan, wiphy_index;
886 uint32_t chan_cnt;
887 struct ieee80211_channel *wiphy_chan;
888
Amar Singhal5e2d5f02017-10-06 10:56:49 -0700889 if (wiphy->bands[band_id] == NULL)
890 return;
891
Amar Singhal5cccafe2017-02-15 12:42:58 -0800892 wiphy_num_chan = wiphy->bands[band_id]->n_channels;
893 wiphy_chan = wiphy->bands[band_id]->channels;
894
895 for (wiphy_index = 0; wiphy_index < wiphy_num_chan; wiphy_index++) {
896 for (chan_cnt = 0; chan_cnt < NUM_CHANNELS; chan_cnt++) {
897 if (wiphy_chan[wiphy_index].center_freq ==
898 cur_chan_list[chan_cnt].center_freq) {
899 fill_wiphy_channel(&(wiphy_chan[wiphy_index]),
900 &(cur_chan_list[chan_cnt]));
901 break;
902 }
903 }
904 }
905}
906
Kiran Kumar Lokere48795792017-07-07 15:34:29 -0700907/**
908 * hdd_ch_avoid_ind() - Avoid notified channels from FW handler
909 * @adapter: HDD adapter pointer
910 * @indParam: Channel avoid notification parameter
911 *
912 * Avoid channel notification from FW handler.
913 * FW will send un-safe channel list to avoid over wrapping.
914 * hostapd should not use notified channel
915 *
916 * Return: None
917 */
Jeff Johnson4af78662017-08-28 11:44:08 -0700918void hdd_ch_avoid_ind(struct hdd_context *hdd_ctxt,
Kiran Kumar Lokere48795792017-07-07 15:34:29 -0700919 struct unsafe_ch_list *unsafe_chan_list,
920 struct ch_avoid_ind_type *avoid_freq_list)
921{
Liangwei Dong6e1a2092017-08-30 16:29:06 +0800922 uint16_t *local_unsafe_list;
923 uint16_t local_unsafe_list_count;
Kiran Kumar Lokere48795792017-07-07 15:34:29 -0700924
925 /* Basic sanity */
926 if (!hdd_ctxt) {
927 hdd_err("Invalid arguments");
928 return;
929 }
930
931 mutex_lock(&hdd_ctxt->avoid_freq_lock);
932 qdf_mem_copy(&hdd_ctxt->coex_avoid_freq_list, avoid_freq_list,
933 sizeof(struct ch_avoid_ind_type));
934 mutex_unlock(&hdd_ctxt->avoid_freq_lock);
935
Liangwei Dong6e1a2092017-08-30 16:29:06 +0800936 if (hdd_clone_local_unsafe_chan(hdd_ctxt,
937 &local_unsafe_list,
938 &local_unsafe_list_count) != 0) {
939 hdd_err("failed to clone cur unsafe chan list");
940 return;
941 }
942
Kiran Kumar Lokere48795792017-07-07 15:34:29 -0700943 /* clear existing unsafe channel cache */
944 hdd_ctxt->unsafe_channel_count = 0;
945 qdf_mem_zero(hdd_ctxt->unsafe_channel_list,
946 sizeof(hdd_ctxt->unsafe_channel_list));
947
948 hdd_ctxt->unsafe_channel_count = unsafe_chan_list->ch_cnt;
949
950 qdf_mem_copy(hdd_ctxt->unsafe_channel_list, unsafe_chan_list->ch_list,
951 sizeof(hdd_ctxt->unsafe_channel_list));
952 hdd_debug("number of unsafe channels is %d ",
953 hdd_ctxt->unsafe_channel_count);
954
955 if (pld_set_wlan_unsafe_channel(hdd_ctxt->parent_dev,
956 hdd_ctxt->unsafe_channel_list,
957 hdd_ctxt->unsafe_channel_count)) {
958 hdd_err("Failed to set unsafe channel");
959
960 /* clear existing unsafe channel cache */
961 hdd_ctxt->unsafe_channel_count = 0;
962 qdf_mem_zero(hdd_ctxt->unsafe_channel_list,
963 sizeof(hdd_ctxt->unsafe_channel_list));
Liangwei Dong6e1a2092017-08-30 16:29:06 +0800964 qdf_mem_free(local_unsafe_list);
Kiran Kumar Lokere48795792017-07-07 15:34:29 -0700965 return;
966 }
967
968 mutex_lock(&hdd_ctxt->avoid_freq_lock);
969 if (hdd_ctxt->dnbs_avoid_freq_list.ch_avoid_range_cnt)
970 if (wlan_hdd_merge_avoid_freqs(avoid_freq_list,
971 &hdd_ctxt->dnbs_avoid_freq_list)) {
972 mutex_unlock(&hdd_ctxt->avoid_freq_lock);
973 hdd_debug("unable to merge avoid freqs");
Liangwei Dong6e1a2092017-08-30 16:29:06 +0800974 qdf_mem_free(local_unsafe_list);
Kiran Kumar Lokere48795792017-07-07 15:34:29 -0700975 return;
976 }
977 mutex_unlock(&hdd_ctxt->avoid_freq_lock);
978 /*
979 * first update the unsafe channel list to the platform driver and
980 * send the avoid freq event to the application
981 */
982 wlan_hdd_send_avoid_freq_event(hdd_ctxt, avoid_freq_list);
983
984 if (!hdd_ctxt->unsafe_channel_count) {
985 hdd_debug("no unsafe channels - not restarting SAP");
Liangwei Dong6e1a2092017-08-30 16:29:06 +0800986 qdf_mem_free(local_unsafe_list);
Kiran Kumar Lokere48795792017-07-07 15:34:29 -0700987 return;
988 }
Liangwei Dong6e1a2092017-08-30 16:29:06 +0800989 if (hdd_local_unsafe_channel_updated(hdd_ctxt,
990 local_unsafe_list,
991 local_unsafe_list_count))
992 hdd_unsafe_channel_restart_sap(hdd_ctxt);
993 qdf_mem_free(local_unsafe_list);
994
Kiran Kumar Lokere48795792017-07-07 15:34:29 -0700995}
996
Amar Singhal5cccafe2017-02-15 12:42:58 -0800997
Amar Singhal6f8592b2017-04-26 14:31:58 -0700998static void hdd_regulatory_dyn_cbk(struct wlan_objmgr_psoc *psoc,
999 struct wlan_objmgr_pdev *pdev,
1000 struct regulatory_channel *chan_list,
Kiran Kumar Lokere48795792017-07-07 15:34:29 -07001001 struct avoid_freq_ind_data *avoid_freq_ind,
Amar Singhal6f8592b2017-04-26 14:31:58 -07001002 void *arg)
1003{
1004 struct wiphy *wiphy;
1005 struct pdev_osif_priv *pdev_priv;
Jeff Johnson4af78662017-08-28 11:44:08 -07001006 struct hdd_context *hdd_ctx;
Amar Singhal6f8592b2017-04-26 14:31:58 -07001007 enum country_src cc_src;
1008 uint8_t alpha2[REG_ALPHA2_LEN + 1];
1009
1010 pdev_priv = wlan_pdev_get_ospriv(pdev);
1011 wiphy = pdev_priv->wiphy;
1012 hdd_ctx = wiphy_priv(wiphy);
1013
Paul Zhang3d026fb2018-02-03 15:46:29 +08001014 hdd_debug("process channel list update from regulatory");
Amar Singhal6f8592b2017-04-26 14:31:58 -07001015
1016 fill_wiphy_band_channels(wiphy, chan_list, NL80211_BAND_2GHZ);
1017 fill_wiphy_band_channels(wiphy, chan_list, NL80211_BAND_5GHZ);
1018
1019 cc_src = ucfg_reg_get_cc_and_src(hdd_ctx->hdd_psoc, alpha2);
1020 qdf_mem_copy(hdd_ctx->reg.alpha2, alpha2, REG_ALPHA2_LEN + 1);
1021 sme_set_cc_src(hdd_ctx->hHal, cc_src);
1022
1023 sme_generic_change_country_code(hdd_ctx->hHal,
1024 hdd_ctx->reg.alpha2);
Kiran Kumar Lokere48795792017-07-07 15:34:29 -07001025 if (avoid_freq_ind)
1026 hdd_ch_avoid_ind(hdd_ctx, &avoid_freq_ind->chan_list,
1027 &avoid_freq_ind->freq_list);
Amar Singhal6f8592b2017-04-26 14:31:58 -07001028}
1029
Paul Zhanga05a0252018-01-22 11:08:21 +08001030int hdd_regulatory_init(struct hdd_context *hdd_ctx, struct wiphy *wiphy)
Will Huang93bc1372018-01-08 18:16:17 +08001031{
Paul Zhanga05a0252018-01-22 11:08:21 +08001032 bool offload_enabled;
Amar Singhal5cccafe2017-02-15 12:42:58 -08001033 struct reg_config_vars config_vars;
1034 struct regulatory_channel cur_chan_list[NUM_CHANNELS];
Amar Singhal6f8592b2017-04-26 14:31:58 -07001035 enum country_src cc_src;
1036 uint8_t alpha2[REG_ALPHA2_LEN + 1];
Amar Singhal5cccafe2017-02-15 12:42:58 -08001037
1038 reg_program_config_vars(hdd_ctx, &config_vars);
1039 ucfg_reg_set_config_vars(hdd_ctx->hdd_psoc, config_vars);
Amar Singhal6f8592b2017-04-26 14:31:58 -07001040
Amar Singhal6f8592b2017-04-26 14:31:58 -07001041 ucfg_reg_register_chan_change_callback(hdd_ctx->hdd_psoc,
1042 hdd_regulatory_dyn_cbk,
1043 NULL);
Amar Singhal5cccafe2017-02-15 12:42:58 -08001044
Paul Zhanga05a0252018-01-22 11:08:21 +08001045 wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
1046 wiphy->reg_notifier = hdd_reg_notifier;
Amar Singhal5cccafe2017-02-15 12:42:58 -08001047 offload_enabled = ucfg_reg_is_regdb_offloaded(hdd_ctx->hdd_psoc);
Paul Zhanga05a0252018-01-22 11:08:21 +08001048 if (offload_enabled) {
Amar Singhal5cccafe2017-02-15 12:42:58 -08001049 hdd_ctx->reg_offload = true;
Paul Zhanga05a0252018-01-22 11:08:21 +08001050 ucfg_reg_get_current_chan_list(hdd_ctx->hdd_pdev,
1051 cur_chan_list);
1052 fill_wiphy_band_channels(wiphy, cur_chan_list,
1053 NL80211_BAND_2GHZ);
1054 fill_wiphy_band_channels(wiphy, cur_chan_list,
1055 NL80211_BAND_5GHZ);
1056
1057 cc_src = ucfg_reg_get_cc_and_src(hdd_ctx->hdd_psoc, alpha2);
1058 qdf_mem_copy(hdd_ctx->reg.alpha2, alpha2, REG_ALPHA2_LEN + 1);
1059 sme_set_cc_src(hdd_ctx->hHal, cc_src);
Amar Singhal5cccafe2017-02-15 12:42:58 -08001060 } else {
1061 hdd_ctx->reg_offload = false;
Paul Zhanga05a0252018-01-22 11:08:21 +08001062 ucfg_reg_program_default_cc(hdd_ctx->hdd_pdev,
1063 hdd_ctx->reg.reg_domain);
Amar Singhal5cccafe2017-02-15 12:42:58 -08001064 }
1065
1066 return 0;
1067}
Amar Singhal6f8592b2017-04-26 14:31:58 -07001068
Amar Singhal5cccafe2017-02-15 12:42:58 -08001069#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
Jeff Johnson4af78662017-08-28 11:44:08 -07001070int hdd_regulatory_init(struct hdd_context *hdd_ctx, struct wiphy *wiphy)
Amar Singhal5cccafe2017-02-15 12:42:58 -08001071{
1072 hdd_ctx->reg_offload = false;
1073 wiphy->reg_notifier = hdd_reg_notifier;
1074 wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
1075 wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
1076 hdd_regulatory_init_no_offload(hdd_ctx, wiphy);
1077
1078 return 0;
1079}
Amar Singhal6f8592b2017-04-26 14:31:58 -07001080
Amar Singhal5cccafe2017-02-15 12:42:58 -08001081#else
Jeff Johnson4af78662017-08-28 11:44:08 -07001082int hdd_regulatory_init(struct hdd_context *hdd_ctx, struct wiphy *wiphy)
Amar Singhal5cccafe2017-02-15 12:42:58 -08001083{
1084 hdd_ctx->reg_offload = false;
1085 wiphy->reg_notifier = hdd_reg_notifier;
1086 wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS;
1087 wiphy->country_ie_pref |= NL80211_COUNTRY_IE_IGNORE_CORE;
1088 hdd_regulatory_init_no_offload(hdd_ctx, wiphy);
1089
1090 return 0;
1091}
1092#endif