blob: 508269b13c4568ee680cb11756d9afc6aad9755c [file] [log] [blame]
Amar Singhale4f28ee2015-10-21 14:36:56 -07001/*
lifengcaa45ef2019-01-10 10:42:10 +08002 * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
Amar Singhale4f28ee2015-10-21 14:36:56 -07003 *
Amar Singhale4f28ee2015-10-21 14:36:56 -07004 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
Amar Singhale4f28ee2015-10-21 14:36:56 -070019/**
20 * DOC: wlan_hdd_regulatory.c
21 *
22 * hdd regulatory implementation
23 */
24
25#include "qdf_types.h"
Amar Singhal5f997862016-08-24 13:17:50 -070026#include "qdf_trace.h"
Amar Singhale4f28ee2015-10-21 14:36:56 -070027#include "wlan_hdd_main.h"
Amar Singhal6f8592b2017-04-26 14:31:58 -070028#include <wlan_osif_priv.h>
Amar Singhale4f28ee2015-10-21 14:36:56 -070029#include "wlan_hdd_regulatory.h"
Amar Singhal5cccafe2017-02-15 12:42:58 -080030#include <wlan_reg_ucfg_api.h>
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -070031#include "cds_regdomain.h"
Jeff Johnsonb9d65f22018-04-23 16:21:00 -070032#include "cds_utils.h"
Kiran Kumar Lokere48795792017-07-07 15:34:29 -070033#include "pld_common.h"
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -070034#include <net/cfg80211.h>
Krunal Sonidf29bc42018-11-15 13:26:29 -080035#include "wlan_policy_mgr_ucfg.h"
Amar Singhale4f28ee2015-10-21 14:36:56 -070036
37#define REG_RULE_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
38
39#define REG_RULE_2467_2472 REG_RULE(2467-10, 2472+10, 40, 0, 20, \
Amar Singhale4f28ee2015-10-21 14:36:56 -070040 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
41
Amar Singhal1c944922016-03-23 18:46:49 -070042#define REG_RULE_2484 REG_RULE(2484-10, 2484+10, 20, 0, 20, \
43 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | \
44 NL80211_RRF_NO_OFDM)
45
46#define REG_RULE_5180_5320 REG_RULE(5180-10, 5320+10, 160, 0, 20, \
47 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
48
49#define REG_RULE_5500_5720 REG_RULE(5500-10, 5720+10, 160, 0, 20, \
Amar Singhale4f28ee2015-10-21 14:36:56 -070050 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
51
52#define REG_RULE_5745_5925 REG_RULE(5745-10, 5925+10, 80, 0, 20, \
53 NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
54
55static bool init_by_driver;
56static bool init_by_reg_core;
57
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -070058struct regulatory_channel reg_channels[NUM_CHANNELS];
59
Amar Singhale4f28ee2015-10-21 14:36:56 -070060static const struct ieee80211_regdomain
61hdd_world_regrules_60_61_62 = {
62 .n_reg_rules = 6,
63 .alpha2 = "00",
64 .reg_rules = {
65 REG_RULE_2412_2462,
66 REG_RULE_2467_2472,
67 REG_RULE_2484,
68 REG_RULE_5180_5320,
69 REG_RULE_5500_5720,
70 REG_RULE_5745_5925,
71 }
72};
73
74static const struct ieee80211_regdomain
75hdd_world_regrules_63_65 = {
76 .n_reg_rules = 4,
77 .alpha2 = "00",
78 .reg_rules = {
79 REG_RULE_2412_2462,
80 REG_RULE_2467_2472,
81 REG_RULE_5180_5320,
82 REG_RULE_5745_5925,
83 }
84};
85
86static const struct ieee80211_regdomain
87hdd_world_regrules_64 = {
88 .n_reg_rules = 3,
89 .alpha2 = "00",
90 .reg_rules = {
91 REG_RULE_2412_2462,
92 REG_RULE_5180_5320,
93 REG_RULE_5745_5925,
94 }
95};
96
97static const struct ieee80211_regdomain
98hdd_world_regrules_66_69 = {
99 .n_reg_rules = 4,
100 .alpha2 = "00",
101 .reg_rules = {
102 REG_RULE_2412_2462,
103 REG_RULE_5180_5320,
104 REG_RULE_5500_5720,
105 REG_RULE_5745_5925,
106 }
107};
108
109static const struct ieee80211_regdomain
110hdd_world_regrules_67_68_6A_6C = {
111 .n_reg_rules = 5,
112 .alpha2 = "00",
113 .reg_rules = {
114 REG_RULE_2412_2462,
115 REG_RULE_2467_2472,
116 REG_RULE_5180_5320,
117 REG_RULE_5500_5720,
118 REG_RULE_5745_5925,
119 }
120};
121
122/**
123 * hdd_get_world_regrules() - get the appropriate world regrules
124 * @reg: regulatory data
125 *
126 * Return: regulatory rules ptr
127 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800128#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0))
Amar Singhale4f28ee2015-10-21 14:36:56 -0700129static const struct ieee80211_regdomain *hdd_get_world_regrules(
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -0700130 struct regulatory *reg)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700131{
Amar Singhal22995112016-01-22 10:42:33 -0800132 struct reg_dmn_pair *regpair =
133 (struct reg_dmn_pair *)reg->regpair;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700134
Amar Singhala7bb01b2016-01-27 11:31:59 -0800135 switch (regpair->reg_dmn_pair) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700136 case 0x60:
137 case 0x61:
138 case 0x62:
139 return &hdd_world_regrules_60_61_62;
140 case 0x63:
141 case 0x65:
142 return &hdd_world_regrules_63_65;
143 case 0x64:
144 return &hdd_world_regrules_64;
145 case 0x66:
146 case 0x69:
147 return &hdd_world_regrules_66_69;
148 case 0x67:
149 case 0x68:
150 case 0x6A:
151 case 0x6C:
152 return &hdd_world_regrules_67_68_6A_6C;
153 default:
154 hdd_warn("invalid world mode in BDF");
155 return &hdd_world_regrules_60_61_62;
156 }
157}
158
159/**
160 * hdd_is_world_regdomain() - whether world regdomain
161 * @reg_domain: integer regulatory domain
162 *
163 * Return: bool
164 */
Jeff Johnson87a24252016-10-05 16:20:52 -0700165static bool hdd_is_world_regdomain(uint32_t reg_domain)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700166{
Amar Singhal5f997862016-08-24 13:17:50 -0700167 uint32_t temp_regd = reg_domain & ~WORLD_ROAMING_FLAG;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700168
Amar Singhal5f997862016-08-24 13:17:50 -0700169 return ((temp_regd & CTRY_FLAG) != CTRY_FLAG) &&
170 ((temp_regd & WORLD_ROAMING_MASK) ==
171 WORLD_ROAMING_PREFIX);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700172}
173
Amar Singhale4f28ee2015-10-21 14:36:56 -0700174/**
175 * hdd_update_regulatory_info() - update regulatory info
176 * @hdd_ctx: hdd context
177 *
Kiran Kumar Lokerea6e01c02017-11-17 18:59:44 -0800178 * Return: Error Code
Amar Singhale4f28ee2015-10-21 14:36:56 -0700179 */
Kiran Kumar Lokerea6e01c02017-11-17 18:59:44 -0800180static int hdd_update_regulatory_info(struct hdd_context *hdd_ctx)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700181{
182 uint32_t country_code;
183
184 country_code = cds_get_country_from_alpha2(hdd_ctx->reg.alpha2);
185
Amar Singhal5f997862016-08-24 13:17:50 -0700186 hdd_ctx->reg.reg_domain = CTRY_FLAG;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700187 hdd_ctx->reg.reg_domain |= country_code;
188
Kiran Kumar Lokerea6e01c02017-11-17 18:59:44 -0800189 return cds_fill_some_regulatory_info(&hdd_ctx->reg);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700190
191}
Paul Zhanga05a0252018-01-22 11:08:21 +0800192#endif
Amar Singhale4f28ee2015-10-21 14:36:56 -0700193
194/**
Abhishek Singh3e6172f2016-05-04 16:56:48 +0530195 * hdd_reset_global_reg_params - Reset global static reg params
196 *
197 * This function is helpful in static driver to reset
198 * the global params.
199 *
200 * Return: void
201 */
202void hdd_reset_global_reg_params(void)
203{
204 init_by_driver = false;
205 init_by_reg_core = false;
206}
207
Jeff Johnson4af78662017-08-28 11:44:08 -0700208static void reg_program_config_vars(struct hdd_context *hdd_ctx,
Amar Singhal5cccafe2017-02-15 12:42:58 -0800209 struct reg_config_vars *config_vars)
210{
Krunal Sonidf29bc42018-11-15 13:26:29 -0800211 uint8_t band_capability = 0, indoor_chnl_marking = 0;
lifeng0b46ae52018-12-13 09:42:27 +0800212 uint32_t scan_11d_interval = 0;
213 bool indoor_chan_enabled = false;
214 uint32_t restart_beaconing = 0;
215 bool enable_srd_chan = false;
Vignesh Viswanathanf97cc112018-10-03 19:17:07 +0530216 QDF_STATUS status;
Bala Venkatesh46e29032018-11-14 18:24:55 +0530217 bool country_priority = 0;
Abhinav Kumard4d6eb72018-12-04 20:30:37 +0530218 bool value = false;
gaurank kathpalia97c070b2019-01-07 17:23:06 +0530219 bool enable_dfs_scan = true;
Vignesh Viswanathanf97cc112018-10-03 19:17:07 +0530220
221 status = ucfg_mlme_get_band_capability(hdd_ctx->psoc, &band_capability);
222 if (QDF_IS_STATUS_ERROR(status))
223 hdd_err("Failed to get MLME band cap, defaulting to BAND_ALL");
224
Krunal Sonidf29bc42018-11-15 13:26:29 -0800225 status = ucfg_policy_mgr_get_indoor_chnl_marking(hdd_ctx->psoc,
226 &indoor_chnl_marking);
227 if (QDF_STATUS_SUCCESS != status)
228 hdd_err("can't get indoor channel marking, using default");
229
Abhinav Kumard4d6eb72018-12-04 20:30:37 +0530230 status = ucfg_mlme_is_11d_enabled(hdd_ctx->psoc, &value);
231 if (!QDF_IS_STATUS_SUCCESS(status))
232 hdd_err("Invalid 11d_enable flag");
233 config_vars->enable_11d_support = value;
234
lifeng0b46ae52018-12-13 09:42:27 +0800235 ucfg_mlme_get_scan_11d_interval(hdd_ctx->psoc, &scan_11d_interval);
236 config_vars->scan_11d_interval = scan_11d_interval;
237
Bala Venkatesh46e29032018-11-14 18:24:55 +0530238 ucfg_mlme_get_sap_country_priority(hdd_ctx->psoc,
239 &country_priority);
240 config_vars->userspace_ctry_priority = country_priority;
lifeng0b46ae52018-12-13 09:42:27 +0800241
gaurank kathpalia97c070b2019-01-07 17:23:06 +0530242 ucfg_scan_cfg_get_dfs_chan_scan_allowed(hdd_ctx->psoc,
243 &enable_dfs_scan);
244
245 config_vars->dfs_enabled = enable_dfs_scan;
lifeng0b46ae52018-12-13 09:42:27 +0800246
247 ucfg_mlme_get_indoor_channel_support(hdd_ctx->psoc,
248 &indoor_chan_enabled);
249 config_vars->indoor_chan_enabled = indoor_chan_enabled;
250
Krunal Sonidf29bc42018-11-15 13:26:29 -0800251 config_vars->force_ssc_disable_indoor_channel = indoor_chnl_marking;
Vignesh Viswanathanf97cc112018-10-03 19:17:07 +0530252 config_vars->band_capability = band_capability;
lifeng0b46ae52018-12-13 09:42:27 +0800253
254 ucfg_mlme_get_restart_beaconing_on_ch_avoid(hdd_ctx->psoc,
255 &restart_beaconing);
256 config_vars->restart_beaconing = restart_beaconing;
257
258 ucfg_mlme_get_etsi13_srd_chan_in_master_mode(hdd_ctx->psoc,
259 &enable_srd_chan);
260 config_vars->enable_srd_chan_in_master_mode = enable_srd_chan;
261
gaurank kathpaliaba22ef22019-02-05 17:04:08 +0530262 ucfg_mlme_get_11d_in_world_mode(hdd_ctx->psoc,
263 &config_vars->enable_11d_in_world_mode);
Amar Singhal5cccafe2017-02-15 12:42:58 -0800264}
265
Abhishek Singh3e6172f2016-05-04 16:56:48 +0530266/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700267 * hdd_regulatory_wiphy_init() - regulatory wiphy init
268 * @hdd_ctx: hdd context
269 * @reg: regulatory data
270 * @wiphy: wiphy structure
271 *
272 * Return: void
273 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800274#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
275#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
Jeff Johnson4af78662017-08-28 11:44:08 -0700276static void hdd_regulatory_wiphy_init(struct hdd_context *hdd_ctx,
Amar Singhale4f28ee2015-10-21 14:36:56 -0700277 struct regulatory *reg,
278 struct wiphy *wiphy)
279{
280 const struct ieee80211_regdomain *reg_rules;
Amar Singhalb7fe2612016-10-19 10:49:58 -0700281 int chan_num;
Amar Singhal6fc66382016-11-09 13:33:33 -0800282 struct ieee80211_channel *chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700283
284 if (hdd_is_world_regdomain(reg->reg_domain)) {
285 reg_rules = hdd_get_world_regrules(reg);
286 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700287 } else {
288 wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
289 reg_rules = &hdd_world_regrules_60_61_62;
290 }
291
292 /*
293 * save the original driver regulatory flags
294 */
295 hdd_ctx->reg.reg_flags = wiphy->regulatory_flags;
296 wiphy_apply_custom_regulatory(wiphy, reg_rules);
297
298 /*
Amar Singhalb7fe2612016-10-19 10:49:58 -0700299 * disable 2.4 Ghz channels that dont have 20 mhz bw
300 */
301 for (chan_num = 0;
Srinivas Girigowda11c28e02017-06-27 20:06:21 -0700302 chan_num < wiphy->bands[HDD_NL80211_BAND_2GHZ]->n_channels;
Amar Singhalb7fe2612016-10-19 10:49:58 -0700303 chan_num++) {
Srinivas Girigowda11c28e02017-06-27 20:06:21 -0700304 chan = &(wiphy->bands[HDD_NL80211_BAND_2GHZ]->channels[chan_num]);
Amar Singhal6fc66382016-11-09 13:33:33 -0800305 if (chan->flags & IEEE80211_CHAN_NO_20MHZ)
306 chan->flags |= IEEE80211_CHAN_DISABLED;
Amar Singhalb7fe2612016-10-19 10:49:58 -0700307 }
308
309 /*
Amar Singhale4f28ee2015-10-21 14:36:56 -0700310 * restore the driver regulatory flags since
311 * wiphy_apply_custom_regulatory may have
312 * changed them
313 */
314 wiphy->regulatory_flags = hdd_ctx->reg.reg_flags;
315
316}
317#else
Jeff Johnson4af78662017-08-28 11:44:08 -0700318static void hdd_regulatory_wiphy_init(struct hdd_context *hdd_ctx,
Amar Singhale4f28ee2015-10-21 14:36:56 -0700319 struct regulatory *reg,
320 struct wiphy *wiphy)
321{
322 const struct ieee80211_regdomain *reg_rules;
323
324 if (hdd_is_world_regdomain(reg->reg_domain)) {
325 reg_rules = hdd_get_world_regrules(reg);
326 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700327 } else {
328 wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
329 reg_rules = &hdd_world_regrules_60_61_62;
330 }
331
332 /*
333 * save the original driver regulatory flags
334 */
335 hdd_ctx->reg.reg_flags = wiphy->flags;
336 wiphy_apply_custom_regulatory(wiphy, reg_rules);
337
338 /*
339 * restore the driver regulatory flags since
340 * wiphy_apply_custom_regulatory may have
341 * changed them
342 */
343 wiphy->flags = hdd_ctx->reg.reg_flags;
344
345}
346#endif
347
348/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700349 * is_wiphy_custom_regulatory() - is custom regulatory defined
350 * @wiphy: wiphy
351 *
352 * Return: int
353 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800354#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
355#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700356static int is_wiphy_custom_regulatory(struct wiphy *wiphy)
357{
358
359 return wiphy->regulatory_flags & REGULATORY_CUSTOM_REG;
360}
361#else
362static int is_wiphy_custom_regulatory(struct wiphy *wiphy)
363{
364 return wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY;
365}
366#endif
367
Amar Singhale4f28ee2015-10-21 14:36:56 -0700368/**
369 * hdd_modify_wiphy() - modify wiphy
370 * @wiphy: wiphy
371 * @chan: channel structure
372 *
373 * Return: void
374 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800375#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0))
Amar Singhale4f28ee2015-10-21 14:36:56 -0700376static void hdd_modify_wiphy(struct wiphy *wiphy,
377 struct ieee80211_channel *chan)
378{
379 const struct ieee80211_reg_rule *reg_rule;
380
381 if (is_wiphy_custom_regulatory(wiphy)) {
382 reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
383 if (!IS_ERR(reg_rule)) {
384 chan->flags &= ~IEEE80211_CHAN_DISABLED;
385
386 if (!(reg_rule->flags & NL80211_RRF_DFS)) {
Arunk Khandavalliae44d892017-06-29 15:28:24 +0530387 hdd_debug("Remove dfs restriction for %u",
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530388 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700389 chan->flags &= ~IEEE80211_CHAN_RADAR;
390 }
391
392 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) {
Arunk Khandavalliae44d892017-06-29 15:28:24 +0530393 hdd_debug("Remove passive restriction for %u",
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530394 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700395 chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
396 }
397
398 if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) {
Arunk Khandavalliae44d892017-06-29 15:28:24 +0530399 hdd_debug("Remove no ibss restriction for %u",
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530400 chan->center_freq);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700401 chan->flags &= ~IEEE80211_CHAN_NO_IBSS;
402 }
403
404 chan->max_power =
405 MBM_TO_DBM(reg_rule->power_rule.max_eirp);
406 }
407 }
408}
Paul Zhanga05a0252018-01-22 11:08:21 +0800409#endif
410
411/**
412 * hdd_set_dfs_region() - set the dfs_region
413 * @dfs_region: the dfs_region to set
414 *
415 * Return: void
416 */
417#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
418#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
419static void hdd_set_dfs_region(struct hdd_context *hdd_ctx,
420 enum dfs_reg dfs_reg)
421{
Dustin Brown07901ec2018-09-07 11:02:41 -0700422 wlan_reg_set_dfs_region(hdd_ctx->pdev, dfs_reg);
Paul Zhanga05a0252018-01-22 11:08:21 +0800423}
Paul Zhanga05a0252018-01-22 11:08:21 +0800424#endif
Amar Singhale4f28ee2015-10-21 14:36:56 -0700425
426/**
427 * hdd_process_regulatory_data() - process regulatory data
428 * @hdd_ctx: hdd context
429 * @wiphy: wiphy
430 * @reset: whether to reset channel data
431 *
432 * Return: void
433 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800434#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0))
Jeff Johnson4af78662017-08-28 11:44:08 -0700435static void hdd_process_regulatory_data(struct hdd_context *hdd_ctx,
Amar Singhale4f28ee2015-10-21 14:36:56 -0700436 struct wiphy *wiphy,
437 bool reset)
438{
Amar Singhal388b3f02016-02-10 13:37:18 -0800439 int band_num;
440 int chan_num;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700441 enum channel_enum chan_enum = CHAN_ENUM_1;
442 struct ieee80211_channel *wiphy_chan, *wiphy_chan_144 = NULL;
Amar Singhal388b3f02016-02-10 13:37:18 -0800443 struct regulatory_channel *cds_chan;
Krunal Sonidf29bc42018-11-15 13:26:29 -0800444 uint8_t band_capability, indoor_chnl_marking = 0;
lifeng0b46ae52018-12-13 09:42:27 +0800445 bool indoor;
Krunal Sonidf29bc42018-11-15 13:26:29 -0800446 QDF_STATUS status;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700447
Amar Singhal58b45ef2017-08-01 13:43:54 -0700448 band_capability = hdd_ctx->curr_band;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700449
Krunal Sonidf29bc42018-11-15 13:26:29 -0800450 status = ucfg_policy_mgr_get_indoor_chnl_marking(hdd_ctx->psoc,
451 &indoor_chnl_marking);
452 if (QDF_STATUS_SUCCESS != status)
453 hdd_err("can't get indoor channel marking, using default");
454
Srinivas Girigowda5da651b2017-08-04 11:22:54 -0700455 for (band_num = 0; band_num < HDD_NUM_NL80211_BANDS; band_num++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700456
Jeff Johnsond36fa332019-03-18 13:42:25 -0700457 if (!wiphy->bands[band_num])
Amar Singhale4f28ee2015-10-21 14:36:56 -0700458 continue;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700459
Amar Singhal388b3f02016-02-10 13:37:18 -0800460 for (chan_num = 0;
Manjeet Singhec402062016-10-27 15:58:01 +0530461 chan_num < wiphy->bands[band_num]->n_channels &&
462 chan_enum < NUM_CHANNELS;
Amar Singhal388b3f02016-02-10 13:37:18 -0800463 chan_num++) {
Amar Singhal388b3f02016-02-10 13:37:18 -0800464 wiphy_chan =
465 &(wiphy->bands[band_num]->channels[chan_num]);
466 cds_chan = &(reg_channels[chan_enum]);
Amar Singhal5cccafe2017-02-15 12:42:58 -0800467 cds_chan->chan_flags = 0;
Amar Singhalb2cb3002016-08-11 16:10:36 -0700468 if (CHAN_ENUM_144 == chan_enum)
469 wiphy_chan_144 = wiphy_chan;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700470
Amar Singhal388b3f02016-02-10 13:37:18 -0800471 chan_enum++;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700472
473 if (!reset)
Amar Singhal388b3f02016-02-10 13:37:18 -0800474 hdd_modify_wiphy(wiphy, wiphy_chan);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700475
Krunal Sonidf29bc42018-11-15 13:26:29 -0800476 if (indoor_chnl_marking &&
477 (wiphy_chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
Mukul Sharmaecf8e092017-12-19 22:36:31 +0530478 cds_chan->chan_flags |=
479 REGULATORY_CHAN_INDOOR_ONLY;
480
Amar Singhal388b3f02016-02-10 13:37:18 -0800481 if (wiphy_chan->flags & IEEE80211_CHAN_DISABLED) {
482 cds_chan->state = CHANNEL_STATE_DISABLE;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800483 cds_chan->chan_flags |=
484 REGULATORY_CHAN_DISABLED;
Amar Singhal6f8592b2017-04-26 14:31:58 -0700485 } else if (wiphy_chan->flags &
Amar Singhal18517882016-08-08 12:26:20 -0700486 (IEEE80211_CHAN_RADAR |
Amar Singhal6f8592b2017-04-26 14:31:58 -0700487 IEEE80211_CHAN_PASSIVE_SCAN)) {
Amar Singhal388b3f02016-02-10 13:37:18 -0800488 cds_chan->state = CHANNEL_STATE_DFS;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800489 if (wiphy_chan->flags & IEEE80211_CHAN_RADAR)
490 cds_chan->chan_flags |=
491 REGULATORY_CHAN_RADAR;
492 if (wiphy_chan->flags &
493 IEEE80211_CHAN_PASSIVE_SCAN)
494 cds_chan->chan_flags |=
495 REGULATORY_CHAN_NO_IR;
Amar Singhal6f8592b2017-04-26 14:31:58 -0700496 } else if (wiphy_chan->flags &
497 IEEE80211_CHAN_INDOOR_ONLY) {
498 cds_chan->chan_flags |=
Mukul Sharmaecf8e092017-12-19 22:36:31 +0530499 REGULATORY_CHAN_INDOOR_ONLY;
lifeng0b46ae52018-12-13 09:42:27 +0800500
lifengcaa45ef2019-01-10 10:42:10 +0800501 ucfg_mlme_get_indoor_channel_support(
502 hdd_ctx->psoc,
503 &indoor);
lifeng0b46ae52018-12-13 09:42:27 +0800504 if (!indoor) {
Amar Singhal6f8592b2017-04-26 14:31:58 -0700505 cds_chan->state = CHANNEL_STATE_DFS;
506 wiphy_chan->flags |=
507 IEEE80211_CHAN_PASSIVE_SCAN;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800508 cds_chan->chan_flags |=
Amar Singhal6f8592b2017-04-26 14:31:58 -0700509 REGULATORY_CHAN_NO_IR;
510 } else
511 cds_chan->state = CHANNEL_STATE_ENABLE;
512 } else
Amar Singhal388b3f02016-02-10 13:37:18 -0800513 cds_chan->state = CHANNEL_STATE_ENABLE;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800514 cds_chan->tx_power = wiphy_chan->max_power;
515 if (wiphy_chan->flags & IEEE80211_CHAN_NO_10MHZ)
516 cds_chan->max_bw = 5;
517 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_20MHZ)
518 cds_chan->max_bw = 10;
Krunal Soni408690d2017-05-03 18:32:35 -0700519 /*
520 * IEEE80211_CHAN_NO_HT40 is defined as 0x30 in kernel
521 * 4th BIT representing IEEE80211_CHAN_NO_HT40PLUS
522 * 5th BIT representing IEEE80211_CHAN_NO_HT40MINUS
523 *
524 * In order to claim no 40Mhz support value of
525 * wiphy_chan->flags needs to be 0x30.
526 * 0x20 and 0x10 values shows that either HT40+ or
527 * HT40- is not supported based on BIT set but they
528 * can support 40Mhz Operation.
529 */
530 else if ((wiphy_chan->flags & IEEE80211_CHAN_NO_HT40) ==
531 IEEE80211_CHAN_NO_HT40)
Amar Singhal5cccafe2017-02-15 12:42:58 -0800532 cds_chan->max_bw = 20;
533 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_80MHZ)
534 cds_chan->max_bw = 40;
535 else if (wiphy_chan->flags & IEEE80211_CHAN_NO_160MHZ)
536 cds_chan->max_bw = 80;
537 else
538 cds_chan->max_bw = 160;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700539 }
540 }
541
542 if (0 == (hdd_ctx->reg.eeprom_rd_ext &
Sandeep Puligilla985d1ee2017-01-04 16:41:39 -0800543 (1 << WMI_REG_EXT_FCC_CH_144))) {
Amar Singhal388b3f02016-02-10 13:37:18 -0800544 cds_chan = &(reg_channels[CHAN_ENUM_144]);
545 cds_chan->state = CHANNEL_STATE_DISABLE;
Jeff Johnsond36fa332019-03-18 13:42:25 -0700546 if (wiphy_chan_144)
Amar Singhalb2cb3002016-08-11 16:10:36 -0700547 wiphy_chan_144->flags |= IEEE80211_CHAN_DISABLED;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700548 }
Amar Singhal6842e8f2016-02-23 16:30:32 -0800549
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -0700550 wlan_hdd_cfg80211_update_band(hdd_ctx, wiphy, band_capability);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700551}
552
Amar Singhale4f28ee2015-10-21 14:36:56 -0700553/**
Amar Singhal5cccafe2017-02-15 12:42:58 -0800554 * hdd_regulatory_init_no_offload() - regulatory init
Amar Singhale4f28ee2015-10-21 14:36:56 -0700555 * @hdd_ctx: hdd context
556 * @wiphy: wiphy
557 *
558 * Return: int
559 */
Jeff Johnson4af78662017-08-28 11:44:08 -0700560static int hdd_regulatory_init_no_offload(struct hdd_context *hdd_ctx,
Amar Singhal5cccafe2017-02-15 12:42:58 -0800561 struct wiphy *wiphy)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700562{
563 int ret_val;
564 struct regulatory *reg_info;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800565 enum dfs_reg dfs_reg;
566 struct reg_config_vars config_vars;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700567
568 reg_info = &hdd_ctx->reg;
569
Amar Singhale4f28ee2015-10-21 14:36:56 -0700570 ret_val = cds_fill_some_regulatory_info(reg_info);
571 if (ret_val) {
572 hdd_err("incorrect BDF regulatory data");
573 return ret_val;
574 }
575
Kiran Kumar Lokeree37c8552018-08-21 11:36:34 -0700576 hdd_set_dfs_region(hdd_ctx, DFS_FCC_REGION);
Amar Singhal52385672017-09-01 14:26:40 -0700577
Dustin Brown38f2b552016-10-04 13:57:46 -0700578 hdd_regulatory_wiphy_init(hdd_ctx, reg_info, wiphy);
579
580 hdd_process_regulatory_data(hdd_ctx, wiphy, true);
581
582 reg_info->cc_src = SOURCE_DRIVER;
583
Dustin Brown05d81302018-09-11 16:49:22 -0700584 ucfg_reg_set_default_country(hdd_ctx->psoc, reg_info->alpha2);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700585
Amar Singhale4f28ee2015-10-21 14:36:56 -0700586 cds_fill_and_send_ctl_to_fw(reg_info);
587
Dustin Brown07901ec2018-09-07 11:02:41 -0700588 wlan_reg_get_dfs_region(hdd_ctx->pdev, &dfs_reg);
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700589
Amar Singhal5cccafe2017-02-15 12:42:58 -0800590 reg_program_config_vars(hdd_ctx, &config_vars);
Dustin Brown05d81302018-09-11 16:49:22 -0700591 ucfg_reg_set_config_vars(hdd_ctx->psoc, config_vars);
592 ucfg_reg_program_mas_chan_list(hdd_ctx->psoc,
Amar Singhal5cccafe2017-02-15 12:42:58 -0800593 reg_channels,
594 hdd_ctx->reg.alpha2,
595 dfs_reg);
596
Amar Singhale4f28ee2015-10-21 14:36:56 -0700597 return 0;
598}
Paul Zhanga05a0252018-01-22 11:08:21 +0800599#endif
Amar Singhale4f28ee2015-10-21 14:36:56 -0700600
601/**
Mukul Sharmaecf8e092017-12-19 22:36:31 +0530602 * hdd_modify_indoor_channel_state_flags() - modify wiphy flags and cds state
603 * @wiphy_chan: wiphy channel number
604 * @cds_chan: cds channel structure
605 * @disable: Disable/enable the flags
606 *
607 * Modify wiphy flags and cds state if channel is indoor.
608 *
609 * Return: void
610 */
611void hdd_modify_indoor_channel_state_flags(
612 struct hdd_context *hdd_ctx,
613 struct ieee80211_channel *wiphy_chan,
614 struct regulatory_channel *cds_chan,
615 enum channel_enum chan_enum, int chan_num, bool disable)
616{
lifeng0b46ae52018-12-13 09:42:27 +0800617 bool indoor_support;
618
619 ucfg_mlme_get_indoor_channel_support(hdd_ctx->psoc, &indoor_support);
Mukul Sharmaecf8e092017-12-19 22:36:31 +0530620
621 /* Mark indoor channel to disable in wiphy and cds */
622 if (disable) {
623 if (wiphy_chan->flags & IEEE80211_CHAN_INDOOR_ONLY) {
624 wiphy_chan->flags |=
625 IEEE80211_CHAN_DISABLED;
626 hdd_info("Mark indoor channel %d as disable",
627 cds_chan->center_freq);
628 cds_chan->state =
629 CHANNEL_STATE_DISABLE;
630 }
631 } else {
632 if (wiphy_chan->flags & IEEE80211_CHAN_INDOOR_ONLY) {
633 wiphy_chan->flags &=
634 ~IEEE80211_CHAN_DISABLED;
635 /*
636 * Indoor channels may be marked as dfs / enable
637 * during regulatory processing
638 */
639 if ((wiphy_chan->flags &
640 (IEEE80211_CHAN_RADAR |
641 IEEE80211_CHAN_PASSIVE_SCAN)) ||
642 ((indoor_support == false) &&
643 (wiphy_chan->flags &
644 IEEE80211_CHAN_INDOOR_ONLY)))
645 cds_chan->state =
646 CHANNEL_STATE_DFS;
647 else
648 cds_chan->state =
649 CHANNEL_STATE_ENABLE;
650 hdd_debug("Mark indoor channel %d as cds_chan state %d",
651 cds_chan->chan_num, cds_chan->state);
652 }
653 }
654
655}
656
657void hdd_update_indoor_channel(struct hdd_context *hdd_ctx,
658 bool disable)
659{
660 int band_num;
661 int chan_num;
Amar Singhal2e4cccc2019-08-06 12:47:18 -0700662 enum channel_enum chan_enum = CHAN_ENUM_2412;
Mukul Sharmaecf8e092017-12-19 22:36:31 +0530663 struct ieee80211_channel *wiphy_chan, *wiphy_chan_144 = NULL;
664 struct regulatory_channel *cds_chan;
665 uint8_t band_capability;
666 struct wiphy *wiphy = hdd_ctx->wiphy;
667
Dustin Brown491d54b2018-03-14 12:39:11 -0700668 hdd_enter();
Mukul Sharmaecf8e092017-12-19 22:36:31 +0530669 hdd_debug("mark indoor channel disable: %d", disable);
670
671 band_capability = hdd_ctx->curr_band;
672 for (band_num = 0; band_num < HDD_NUM_NL80211_BANDS; band_num++) {
673
Jeff Johnsond36fa332019-03-18 13:42:25 -0700674 if (!wiphy->bands[band_num])
Mukul Sharmaecf8e092017-12-19 22:36:31 +0530675 continue;
676
677 for (chan_num = 0;
678 chan_num < wiphy->bands[band_num]->n_channels &&
679 chan_enum < NUM_CHANNELS;
680 chan_num++) {
681
682 wiphy_chan =
683 &(wiphy->bands[band_num]->channels[chan_num]);
684 cds_chan = &(reg_channels[chan_enum]);
Amar Singhal2e4cccc2019-08-06 12:47:18 -0700685 if (chan_enum == CHAN_ENUM_5720)
Mukul Sharmaecf8e092017-12-19 22:36:31 +0530686 wiphy_chan_144 = wiphy_chan;
687
688 chan_enum++;
689 hdd_modify_indoor_channel_state_flags(hdd_ctx,
690 wiphy_chan, cds_chan,
691 chan_enum, chan_num, disable);
692 }
693 }
694
695 /* Notify the regulatory domain to update the channel list */
Dustin Brown07901ec2018-09-07 11:02:41 -0700696 if (QDF_IS_STATUS_ERROR(ucfg_reg_notify_sap_event(hdd_ctx->pdev,
697 disable))) {
Mukul Sharmaecf8e092017-12-19 22:36:31 +0530698 hdd_err("Failed to notify sap event");
699 }
Dustin Browne74003f2018-03-14 12:51:58 -0700700 hdd_exit();
Mukul Sharmaecf8e092017-12-19 22:36:31 +0530701
702}
703
704/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700705 * hdd_program_country_code() - process channel information from country code
706 * @hdd_ctx: hddc context
707 *
708 * Return: void
709 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800710#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
711void hdd_program_country_code(struct hdd_context *hdd_ctx)
712{
713}
714#else
Jeff Johnson4af78662017-08-28 11:44:08 -0700715void hdd_program_country_code(struct hdd_context *hdd_ctx)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700716{
717 struct wiphy *wiphy = hdd_ctx->wiphy;
718 uint8_t *country_alpha2 = hdd_ctx->reg.alpha2;
719
Abhishek Singh897b27a2017-03-17 11:56:46 +0530720 if (!init_by_reg_core && !init_by_driver) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700721 init_by_driver = true;
722 if (('0' != country_alpha2[0]) ||
Amar Singhal38c5eeb2016-08-22 16:50:01 -0700723 ('0' != country_alpha2[1]))
Amar Singhale4f28ee2015-10-21 14:36:56 -0700724 regulatory_hint(wiphy, country_alpha2);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700725 }
726}
Paul Zhanga05a0252018-01-22 11:08:21 +0800727#endif
Amar Singhale4f28ee2015-10-21 14:36:56 -0700728
Jeff Johnson4af78662017-08-28 11:44:08 -0700729int hdd_reg_set_country(struct hdd_context *hdd_ctx, char *country_code)
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -0700730{
Dustin Brownad698ae2018-09-05 17:19:30 -0700731 QDF_STATUS status;
Rajeev Kumar Sirasanagandla32ae8042019-03-25 16:37:02 +0530732 uint8_t cc[REG_ALPHA2_LEN + 1];
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -0700733
734 if (!country_code) {
735 hdd_err("country_code is null");
736 return -EINVAL;
737 }
738
Rajeev Kumar Sirasanagandla32ae8042019-03-25 16:37:02 +0530739 qdf_mem_copy(cc, country_code, REG_ALPHA2_LEN);
740 cc[REG_ALPHA2_LEN] = '\0';
741
742 status = ucfg_reg_set_country(hdd_ctx->pdev, cc);
Kiran Kumar Lokereb1d412e2017-04-23 17:19:43 -0700743 if (QDF_IS_STATUS_ERROR(status))
744 hdd_err("Failed to set country");
745
746 return qdf_status_to_os_return(status);
747}
Amar Singhale4f28ee2015-10-21 14:36:56 -0700748
Jeff Johnsonb9d65f22018-04-23 16:21:00 -0700749int hdd_reg_set_band(struct net_device *dev, u8 ui_band)
750{
751 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnsonb396b062018-06-13 14:01:14 -0700752 mac_handle_t mac_handle;
Jeff Johnsonb9d65f22018-04-23 16:21:00 -0700753 enum band_info band;
754 QDF_STATUS status;
755 struct hdd_context *hdd_ctx;
Jeff Johnsondbae0172019-03-09 17:01:56 -0800756 enum band_info current_band;
Jeff Johnson92ed16c2019-03-09 17:03:21 -0800757 enum band_info connected_band;
Jeff Johnsonb9d65f22018-04-23 16:21:00 -0700758 long lrc;
759
760 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
761
762 switch (ui_band) {
763 case WLAN_HDD_UI_BAND_AUTO:
764 band = BAND_ALL;
765 break;
766 case WLAN_HDD_UI_BAND_5_GHZ:
767 band = BAND_5G;
768 break;
769 case WLAN_HDD_UI_BAND_2_4_GHZ:
770 band = BAND_2G;
771 break;
772 default:
773 hdd_err("Invalid band value %u", ui_band);
774 return -EINVAL;
775 }
776
777 hdd_debug("change band to %u", band);
778
Jeff Johnsondbae0172019-03-09 17:01:56 -0800779 if (ucfg_reg_get_curr_band(hdd_ctx->pdev, &current_band) !=
Dustin Brown07901ec2018-09-07 11:02:41 -0700780 QDF_STATUS_SUCCESS) {
Jeff Johnsonb9d65f22018-04-23 16:21:00 -0700781 hdd_debug("Failed to get current band config");
782 return -EIO;
783 }
784
Jeff Johnsondbae0172019-03-09 17:01:56 -0800785 if (current_band == band)
Jeff Johnsonb9d65f22018-04-23 16:21:00 -0700786 return 0;
787
788 hdd_ctx->curr_band = band;
789
790 /* Change band request received.
791 * Abort pending scan requests, flush the existing scan results,
792 * and change the band capability
793 */
794 hdd_debug("Current band value = %u, new setting %u ",
Jeff Johnsondbae0172019-03-09 17:01:56 -0800795 current_band, band);
Jeff Johnsonb9d65f22018-04-23 16:21:00 -0700796
Jeff Johnsonb396b062018-06-13 14:01:14 -0700797 mac_handle = hdd_ctx->mac_handle;
Jeff Johnsonb9d65f22018-04-23 16:21:00 -0700798 hdd_for_each_adapter(hdd_ctx, adapter) {
Dustin Brown07901ec2018-09-07 11:02:41 -0700799 wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID,
Jeff Johnson9597f3b2019-02-04 14:27:56 -0800800 adapter->vdev_id, INVALID_SCAN_ID, false);
Jeff Johnson92ed16c2019-03-09 17:03:21 -0800801 connected_band = hdd_conn_get_connected_band(
Jeff Johnsonb9d65f22018-04-23 16:21:00 -0700802 WLAN_HDD_GET_STATION_CTX_PTR(adapter));
803
804 /* Handling is done only for STA and P2P */
805 if (band != BAND_ALL &&
Jeff Johnsonb396b062018-06-13 14:01:14 -0700806 ((adapter->device_mode == QDF_STA_MODE) ||
807 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
808 (hdd_conn_is_connected(
Jeff Johnsonb9d65f22018-04-23 16:21:00 -0700809 WLAN_HDD_GET_STATION_CTX_PTR(adapter)))
Jeff Johnson92ed16c2019-03-09 17:03:21 -0800810 && (connected_band != band)) {
Jeff Johnsonb9d65f22018-04-23 16:21:00 -0700811 status = QDF_STATUS_SUCCESS;
812
813 /* STA already connected on current
814 * band, So issue disconnect first,
815 * then change the band
816 */
817
818 hdd_debug("STA (Device mode %s(%d)) connected in band %u, Changing band to %u, Issuing Disconnect",
Dustin Brown458027c2018-10-19 12:26:27 -0700819 qdf_opmode_str(adapter->device_mode),
Jeff Johnsondbae0172019-03-09 17:01:56 -0800820 adapter->device_mode, current_band, band);
Jeff Johnsonb9d65f22018-04-23 16:21:00 -0700821 INIT_COMPLETION(adapter->disconnect_comp_var);
822
823 status = sme_roam_disconnect(
Jeff Johnsonb396b062018-06-13 14:01:14 -0700824 mac_handle,
Jeff Johnson9597f3b2019-02-04 14:27:56 -0800825 adapter->vdev_id,
Jeff Johnsonb9d65f22018-04-23 16:21:00 -0700826 eCSR_DISCONNECT_REASON_UNSPECIFIED);
827
828 if (QDF_STATUS_SUCCESS != status) {
829 hdd_err("sme_roam_disconnect failure, status: %d",
830 (int)status);
831 return -EINVAL;
832 }
833
834 lrc = wait_for_completion_timeout(
835 &adapter->disconnect_comp_var,
836 msecs_to_jiffies(
Abhishek Singhd1f21c72019-01-21 15:16:34 +0530837 SME_DISCONNECT_TIMEOUT));
Jeff Johnsonb9d65f22018-04-23 16:21:00 -0700838
839 if (lrc == 0) {
840 hdd_err("Timeout while waiting for csr_roam_disconnect");
841 return -ETIMEDOUT;
842 }
843 }
Abhishek Singhb5c73a42019-05-10 17:30:27 +0530844 ucfg_scan_flush_results(hdd_ctx->pdev, NULL);
Jeff Johnsonb9d65f22018-04-23 16:21:00 -0700845 }
846
Dustin Brown07901ec2018-09-07 11:02:41 -0700847 if (QDF_IS_STATUS_ERROR(ucfg_reg_set_band(hdd_ctx->pdev, band))) {
Jeff Johnsonb9d65f22018-04-23 16:21:00 -0700848 hdd_err("Failed to set the band value to %u", band);
849 return -EINVAL;
850 }
851
852 return 0;
853}
854
Amar Singhale4f28ee2015-10-21 14:36:56 -0700855/**
Amar Singhale4f28ee2015-10-21 14:36:56 -0700856 * hdd_restore_custom_reg_settings() - restore custom reg settings
857 * @wiphy: wiphy structure
858 * @country_alpha2: alpha2 of the country
859 * @reset: whether wiphy is reset
860 *
861 * Return: void
862 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800863#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
864#elif (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700865static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
866 uint8_t *country_alpha2,
867 bool *reset)
868{
869}
870#else
871static void hdd_restore_custom_reg_settings(struct wiphy *wiphy,
872 uint8_t *country_alpha2,
873 bool *reset)
874{
875 struct ieee80211_supported_band *sband;
Dustin Browna30892e2016-10-12 17:28:36 -0700876 enum nl80211_band band;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700877 struct ieee80211_channel *chan;
878 int i;
879
880 if ((country_alpha2[0] == '0') &&
881 (country_alpha2[1] == '0') &&
882 (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) {
883
Srinivas Girigowda5da651b2017-08-04 11:22:54 -0700884 for (band = 0; band < HDD_NUM_NL80211_BANDS; band++) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700885 sband = wiphy->bands[band];
886 if (!sband)
887 continue;
888 for (i = 0; i < sband->n_channels; i++) {
889 chan = &sband->channels[i];
890 chan->flags = chan->orig_flags;
891 chan->max_antenna_gain = chan->orig_mag;
892 chan->max_power = chan->orig_mpwr;
893 }
894 }
895 *reset = true;
896 }
897}
898#endif
899
Amar Singhale4f28ee2015-10-21 14:36:56 -0700900/**
901 * hdd_restore_reg_flags() - restore regulatory flags
902 * @flags: regulatory flags
903 *
904 * Return: void
905 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800906#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
907#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS)
Amar Singhale4f28ee2015-10-21 14:36:56 -0700908static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
909{
910 wiphy->regulatory_flags = flags;
911}
912#else
913static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags)
914{
915 wiphy->flags = flags;
916}
917#endif
918
Amar Singhale4f28ee2015-10-21 14:36:56 -0700919/**
920 * hdd_reg_notifier() - regulatory notifier
921 * @wiphy: wiphy
922 * @request: regulatory request
923 *
924 * Return: void
925 */
Paul Zhanga05a0252018-01-22 11:08:21 +0800926#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
927void hdd_reg_notifier(struct wiphy *wiphy,
928 struct regulatory_request *request)
929{
930 QDF_STATUS status = QDF_STATUS_SUCCESS;
931 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Kiran Kumar Lokere410317a2018-06-04 16:54:53 -0700932 char country[REG_ALPHA2_LEN + 1] = {0};
Paul Zhanga05a0252018-01-22 11:08:21 +0800933
934 hdd_debug("country: %c%c, initiator %d, dfs_region: %d",
935 request->alpha2[0],
936 request->alpha2[1],
937 request->initiator,
938 request->dfs_region);
939
940 switch (request->initiator) {
Amar Singhal2d812012018-02-03 15:06:47 +0800941 case NL80211_REGDOM_SET_BY_USER:
Amar Singhalb5bdce62018-12-06 14:44:07 -0800942
943 if (request->user_reg_hint_type !=
944 NL80211_USER_REG_HINT_CELL_BASE)
945 return;
946
Kiran Kumar Lokere410317a2018-06-04 16:54:53 -0700947 qdf_mem_copy(country, request->alpha2, QDF_MIN(
948 sizeof(request->alpha2), sizeof(country)));
Dustin Brown07901ec2018-09-07 11:02:41 -0700949 status = ucfg_reg_set_country(hdd_ctx->pdev, country);
Paul Zhanga05a0252018-01-22 11:08:21 +0800950 break;
Min Liu2bfab5b2018-04-13 15:30:22 +0800951 case NL80211_REGDOM_SET_BY_CORE:
Paul Zhanga05a0252018-01-22 11:08:21 +0800952 case NL80211_REGDOM_SET_BY_COUNTRY_IE:
953 case NL80211_REGDOM_SET_BY_DRIVER:
954 default:
955 break;
956 }
957
958 if (QDF_IS_STATUS_ERROR(status))
959 hdd_err("Failed to set country");
960}
961#else
Amar Singhale4f28ee2015-10-21 14:36:56 -0700962void hdd_reg_notifier(struct wiphy *wiphy,
963 struct regulatory_request *request)
964{
Jeff Johnson4af78662017-08-28 11:44:08 -0700965 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Amar Singhale4f28ee2015-10-21 14:36:56 -0700966 bool reset = false;
Amar Singhal5cccafe2017-02-15 12:42:58 -0800967 enum dfs_reg dfs_reg;
968 struct reg_config_vars config_vars;
Kiran Kumar Lokerea6e01c02017-11-17 18:59:44 -0800969 int ret_val;
Amar Singhale4f28ee2015-10-21 14:36:56 -0700970
Yeshwanth Sriram Guntuka52bc6bb2017-05-02 16:57:13 +0530971 hdd_debug("country: %c%c, initiator %d, dfs_region: %d",
Amar Singhale4f28ee2015-10-21 14:36:56 -0700972 request->alpha2[0],
973 request->alpha2[1],
974 request->initiator,
975 request->dfs_region);
976
Jeff Johnsond36fa332019-03-18 13:42:25 -0700977 if (!hdd_ctx) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700978 hdd_err("invalid hdd_ctx pointer");
979 return;
980 }
981
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +0530982 if (cds_is_driver_unloading() || cds_is_driver_recovering() ||
983 cds_is_driver_in_bad_state()) {
Amar Singhale4f28ee2015-10-21 14:36:56 -0700984 hdd_err("%s: unloading or ssr in progress, ignore",
985 __func__);
986 return;
987 }
988
Dustin Brownc0ad1ec2017-01-26 12:01:32 -0800989 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
990 hdd_err("Driver module is closed; dropping request");
991 return;
992 }
993
Jeff Johnson214671b2017-10-30 19:45:23 -0700994 if (hdd_ctx->is_wiphy_suspended == true) {
Mukul Sharma0c854a02016-10-20 15:36:20 +0530995 hdd_err("%s: system/cfg80211 is already suspend", __func__);
996 return;
997 }
998
Amar Singhal604ba6cf2016-07-27 15:29:51 -0700999 if (('K' == request->alpha2[0]) &&
1000 ('R' == request->alpha2[1]))
Kiran Kumar Lokeree37c8552018-08-21 11:36:34 -07001001 request->dfs_region = (enum nl80211_dfs_regions)DFS_KR_REGION;
Amar Singhal604ba6cf2016-07-27 15:29:51 -07001002
1003 if (('C' == request->alpha2[0]) &&
1004 ('N' == request->alpha2[1]))
Kiran Kumar Lokeree37c8552018-08-21 11:36:34 -07001005 request->dfs_region = (enum nl80211_dfs_regions)DFS_CN_REGION;
Amar Singhal604ba6cf2016-07-27 15:29:51 -07001006
Amar Singhale4f28ee2015-10-21 14:36:56 -07001007 /* first check if this callback is in response to the driver callback */
Amar Singhale4f28ee2015-10-21 14:36:56 -07001008 switch (request->initiator) {
1009 case NL80211_REGDOM_SET_BY_DRIVER:
1010 case NL80211_REGDOM_SET_BY_CORE:
1011 case NL80211_REGDOM_SET_BY_USER:
1012
1013 if ((false == init_by_driver) &&
1014 (false == init_by_reg_core)) {
1015
1016 if (NL80211_REGDOM_SET_BY_CORE == request->initiator)
1017 return;
1018 init_by_reg_core = true;
1019 }
1020
1021 if ((NL80211_REGDOM_SET_BY_DRIVER == request->initiator) &&
1022 (true == init_by_driver)) {
1023
1024 /*
1025 * restore the driver regulatory flags since
1026 * regulatory_hint may have
1027 * changed them
1028 */
1029 hdd_restore_reg_flags(wiphy, hdd_ctx->reg.reg_flags);
1030 }
1031
1032 if (NL80211_REGDOM_SET_BY_CORE == request->initiator) {
1033 hdd_ctx->reg.cc_src = SOURCE_CORE;
1034 if (is_wiphy_custom_regulatory(wiphy))
1035 reset = true;
Amar Singhal6edf9732016-11-20 21:43:40 -08001036 } else if (NL80211_REGDOM_SET_BY_DRIVER == request->initiator) {
Amar Singhale4f28ee2015-10-21 14:36:56 -07001037 hdd_ctx->reg.cc_src = SOURCE_DRIVER;
Jeff Johnsonb396b062018-06-13 14:01:14 -07001038 sme_set_cc_src(hdd_ctx->mac_handle, SOURCE_DRIVER);
Amar Singhal6edf9732016-11-20 21:43:40 -08001039 } else {
Amar Singhale4f28ee2015-10-21 14:36:56 -07001040 hdd_ctx->reg.cc_src = SOURCE_USERSPACE;
1041 hdd_restore_custom_reg_settings(wiphy,
1042 request->alpha2,
1043 &reset);
1044 }
1045
1046 hdd_ctx->reg.alpha2[0] = request->alpha2[0];
1047 hdd_ctx->reg.alpha2[1] = request->alpha2[1];
1048
Kiran Kumar Lokerea6e01c02017-11-17 18:59:44 -08001049 ret_val = hdd_update_regulatory_info(hdd_ctx);
1050 if (ret_val) {
1051 hdd_err("invalid reg info, do not process");
1052 return;
1053 }
Amar Singhale4f28ee2015-10-21 14:36:56 -07001054
Amar Singhale4f28ee2015-10-21 14:36:56 -07001055 hdd_process_regulatory_data(hdd_ctx, wiphy, reset);
1056
Jeff Johnsonb396b062018-06-13 14:01:14 -07001057 sme_generic_change_country_code(hdd_ctx->mac_handle,
Amar Singhale4f28ee2015-10-21 14:36:56 -07001058 hdd_ctx->reg.alpha2);
1059
1060 cds_fill_and_send_ctl_to_fw(&hdd_ctx->reg);
1061
1062 hdd_set_dfs_region(hdd_ctx, request->dfs_region);
Dustin Brown07901ec2018-09-07 11:02:41 -07001063 wlan_reg_get_dfs_region(hdd_ctx->pdev, &dfs_reg);
Amar Singhal5cccafe2017-02-15 12:42:58 -08001064
1065 reg_program_config_vars(hdd_ctx, &config_vars);
Dustin Brown05d81302018-09-11 16:49:22 -07001066 ucfg_reg_set_config_vars(hdd_ctx->psoc, config_vars);
1067 ucfg_reg_program_mas_chan_list(hdd_ctx->psoc,
Amar Singhal5cccafe2017-02-15 12:42:58 -08001068 reg_channels,
1069 hdd_ctx->reg.alpha2,
1070 dfs_reg);
Amar Singhale4f28ee2015-10-21 14:36:56 -07001071 break;
1072
1073 default:
1074 break;
1075 }
1076}
Paul Zhanga05a0252018-01-22 11:08:21 +08001077#endif
Amar Singhal5cccafe2017-02-15 12:42:58 -08001078
1079#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
1080static void fill_wiphy_channel(struct ieee80211_channel *wiphy_chan,
1081 struct regulatory_channel *cur_chan)
1082{
1083
Paul Zhanga05a0252018-01-22 11:08:21 +08001084 wiphy_chan->flags = 0;
Amar Singhal5cccafe2017-02-15 12:42:58 -08001085 wiphy_chan->max_power = cur_chan->tx_power;
1086
1087 if (cur_chan->chan_flags & REGULATORY_CHAN_DISABLED)
1088 wiphy_chan->flags |= IEEE80211_CHAN_DISABLED;
1089 if (cur_chan->chan_flags & REGULATORY_CHAN_NO_IR)
1090 wiphy_chan->flags |= IEEE80211_CHAN_NO_IR;
1091 if (cur_chan->chan_flags & REGULATORY_CHAN_RADAR)
1092 wiphy_chan->flags |= IEEE80211_CHAN_RADAR;
1093 if (cur_chan->chan_flags & REGULATORY_CHAN_NO_OFDM)
1094 wiphy_chan->flags |= IEEE80211_CHAN_NO_OFDM;
1095 if (cur_chan->chan_flags & REGULATORY_CHAN_INDOOR_ONLY)
1096 wiphy_chan->flags |= IEEE80211_CHAN_INDOOR_ONLY;
1097
1098 if (cur_chan->max_bw < 10)
1099 wiphy_chan->flags |= IEEE80211_CHAN_NO_10MHZ;
1100 if (cur_chan->max_bw < 20)
1101 wiphy_chan->flags |= IEEE80211_CHAN_NO_20MHZ;
1102 if (cur_chan->max_bw < 40)
1103 wiphy_chan->flags |= IEEE80211_CHAN_NO_HT40;
1104 if (cur_chan->max_bw < 80)
1105 wiphy_chan->flags |= IEEE80211_CHAN_NO_80MHZ;
1106 if (cur_chan->max_bw < 160)
1107 wiphy_chan->flags |= IEEE80211_CHAN_NO_160MHZ;
Amar Singhal5cccafe2017-02-15 12:42:58 -08001108
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001109 wiphy_chan->orig_flags = wiphy_chan->flags;
1110}
Amar Singhal5cccafe2017-02-15 12:42:58 -08001111
1112static void fill_wiphy_band_channels(struct wiphy *wiphy,
1113 struct regulatory_channel *cur_chan_list,
1114 uint8_t band_id)
1115{
1116 uint32_t wiphy_num_chan, wiphy_index;
1117 uint32_t chan_cnt;
1118 struct ieee80211_channel *wiphy_chan;
1119
Jeff Johnsond36fa332019-03-18 13:42:25 -07001120 if (!wiphy->bands[band_id])
Amar Singhal5e2d5f02017-10-06 10:56:49 -07001121 return;
1122
Amar Singhal5cccafe2017-02-15 12:42:58 -08001123 wiphy_num_chan = wiphy->bands[band_id]->n_channels;
1124 wiphy_chan = wiphy->bands[band_id]->channels;
1125
1126 for (wiphy_index = 0; wiphy_index < wiphy_num_chan; wiphy_index++) {
1127 for (chan_cnt = 0; chan_cnt < NUM_CHANNELS; chan_cnt++) {
1128 if (wiphy_chan[wiphy_index].center_freq ==
1129 cur_chan_list[chan_cnt].center_freq) {
1130 fill_wiphy_channel(&(wiphy_chan[wiphy_index]),
1131 &(cur_chan_list[chan_cnt]));
1132 break;
1133 }
1134 }
1135 }
1136}
1137
Nirav Shaheb017be2018-02-15 11:20:58 +05301138#ifdef FEATURE_WLAN_CH_AVOID
Kiran Kumar Lokere48795792017-07-07 15:34:29 -07001139/**
1140 * hdd_ch_avoid_ind() - Avoid notified channels from FW handler
1141 * @adapter: HDD adapter pointer
1142 * @indParam: Channel avoid notification parameter
1143 *
1144 * Avoid channel notification from FW handler.
1145 * FW will send un-safe channel list to avoid over wrapping.
1146 * hostapd should not use notified channel
1147 *
1148 * Return: None
1149 */
Jeff Johnson4af78662017-08-28 11:44:08 -07001150void hdd_ch_avoid_ind(struct hdd_context *hdd_ctxt,
Kiran Kumar Lokere48795792017-07-07 15:34:29 -07001151 struct unsafe_ch_list *unsafe_chan_list,
1152 struct ch_avoid_ind_type *avoid_freq_list)
1153{
Liangwei Dong6e1a2092017-08-30 16:29:06 +08001154 uint16_t *local_unsafe_list;
1155 uint16_t local_unsafe_list_count;
Kiran Kumar Lokere48795792017-07-07 15:34:29 -07001156
1157 /* Basic sanity */
1158 if (!hdd_ctxt) {
1159 hdd_err("Invalid arguments");
1160 return;
1161 }
1162
1163 mutex_lock(&hdd_ctxt->avoid_freq_lock);
1164 qdf_mem_copy(&hdd_ctxt->coex_avoid_freq_list, avoid_freq_list,
1165 sizeof(struct ch_avoid_ind_type));
1166 mutex_unlock(&hdd_ctxt->avoid_freq_lock);
1167
Liangwei Dong6e1a2092017-08-30 16:29:06 +08001168 if (hdd_clone_local_unsafe_chan(hdd_ctxt,
1169 &local_unsafe_list,
1170 &local_unsafe_list_count) != 0) {
1171 hdd_err("failed to clone cur unsafe chan list");
1172 return;
1173 }
1174
Kiran Kumar Lokere48795792017-07-07 15:34:29 -07001175 /* clear existing unsafe channel cache */
1176 hdd_ctxt->unsafe_channel_count = 0;
1177 qdf_mem_zero(hdd_ctxt->unsafe_channel_list,
1178 sizeof(hdd_ctxt->unsafe_channel_list));
1179
1180 hdd_ctxt->unsafe_channel_count = unsafe_chan_list->ch_cnt;
1181
1182 qdf_mem_copy(hdd_ctxt->unsafe_channel_list, unsafe_chan_list->ch_list,
1183 sizeof(hdd_ctxt->unsafe_channel_list));
1184 hdd_debug("number of unsafe channels is %d ",
1185 hdd_ctxt->unsafe_channel_count);
1186
1187 if (pld_set_wlan_unsafe_channel(hdd_ctxt->parent_dev,
1188 hdd_ctxt->unsafe_channel_list,
1189 hdd_ctxt->unsafe_channel_count)) {
1190 hdd_err("Failed to set unsafe channel");
1191
1192 /* clear existing unsafe channel cache */
1193 hdd_ctxt->unsafe_channel_count = 0;
1194 qdf_mem_zero(hdd_ctxt->unsafe_channel_list,
1195 sizeof(hdd_ctxt->unsafe_channel_list));
Liangwei Dong6e1a2092017-08-30 16:29:06 +08001196 qdf_mem_free(local_unsafe_list);
Kiran Kumar Lokere48795792017-07-07 15:34:29 -07001197 return;
1198 }
1199
1200 mutex_lock(&hdd_ctxt->avoid_freq_lock);
1201 if (hdd_ctxt->dnbs_avoid_freq_list.ch_avoid_range_cnt)
1202 if (wlan_hdd_merge_avoid_freqs(avoid_freq_list,
1203 &hdd_ctxt->dnbs_avoid_freq_list)) {
1204 mutex_unlock(&hdd_ctxt->avoid_freq_lock);
1205 hdd_debug("unable to merge avoid freqs");
Liangwei Dong6e1a2092017-08-30 16:29:06 +08001206 qdf_mem_free(local_unsafe_list);
Kiran Kumar Lokere48795792017-07-07 15:34:29 -07001207 return;
1208 }
1209 mutex_unlock(&hdd_ctxt->avoid_freq_lock);
1210 /*
1211 * first update the unsafe channel list to the platform driver and
1212 * send the avoid freq event to the application
1213 */
1214 wlan_hdd_send_avoid_freq_event(hdd_ctxt, avoid_freq_list);
1215
1216 if (!hdd_ctxt->unsafe_channel_count) {
1217 hdd_debug("no unsafe channels - not restarting SAP");
Liangwei Dong6e1a2092017-08-30 16:29:06 +08001218 qdf_mem_free(local_unsafe_list);
Kiran Kumar Lokere48795792017-07-07 15:34:29 -07001219 return;
1220 }
Liangwei Dong6e1a2092017-08-30 16:29:06 +08001221 if (hdd_local_unsafe_channel_updated(hdd_ctxt,
1222 local_unsafe_list,
1223 local_unsafe_list_count))
1224 hdd_unsafe_channel_restart_sap(hdd_ctxt);
1225 qdf_mem_free(local_unsafe_list);
1226
Kiran Kumar Lokere48795792017-07-07 15:34:29 -07001227}
Nirav Shaheb017be2018-02-15 11:20:58 +05301228#endif
Amar Singhal5cccafe2017-02-15 12:42:58 -08001229
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001230#if defined CFG80211_USER_HINT_CELL_BASE_SELF_MANAGED || \
1231 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0))
1232static void map_nl_reg_rule_flags(uint16_t drv_reg_rule_flag,
1233 uint32_t *regd_rule_flag)
1234{
1235 if (drv_reg_rule_flag & REGULATORY_CHAN_NO_IR)
1236 *regd_rule_flag |= NL80211_RRF_NO_IR;
1237 if (drv_reg_rule_flag & REGULATORY_CHAN_RADAR)
1238 *regd_rule_flag |= NL80211_RRF_DFS;
1239 if (drv_reg_rule_flag & REGULATORY_CHAN_INDOOR_ONLY)
1240 *regd_rule_flag |= NL80211_RRF_NO_OUTDOOR;
1241 if (drv_reg_rule_flag & REGULATORY_CHAN_NO_OFDM)
1242 *regd_rule_flag |= NL80211_RRF_NO_OFDM;
1243}
1244
Jianmin Zhuc2d91c22018-07-02 14:05:44 +08001245/**
1246 * dfs_reg_to_nl80211_dfs_regions() - convert dfs_reg to nl80211_dfs_regions
1247 * @dfs_region: DFS region
1248 *
1249 * Return: nl80211_dfs_regions
1250 */
1251static enum nl80211_dfs_regions dfs_reg_to_nl80211_dfs_regions(
1252 enum dfs_reg dfs_region)
1253{
1254 switch (dfs_region) {
Kiran Kumar Lokeree37c8552018-08-21 11:36:34 -07001255 case DFS_UNINIT_REGION:
Jianmin Zhuc2d91c22018-07-02 14:05:44 +08001256 return NL80211_DFS_UNSET;
Kiran Kumar Lokeree37c8552018-08-21 11:36:34 -07001257 case DFS_FCC_REGION:
Jianmin Zhuc2d91c22018-07-02 14:05:44 +08001258 return NL80211_DFS_FCC;
Kiran Kumar Lokeree37c8552018-08-21 11:36:34 -07001259 case DFS_ETSI_REGION:
Jianmin Zhuc2d91c22018-07-02 14:05:44 +08001260 return NL80211_DFS_ETSI;
Kiran Kumar Lokeree37c8552018-08-21 11:36:34 -07001261 case DFS_MKK_REGION:
Jianmin Zhuc2d91c22018-07-02 14:05:44 +08001262 return NL80211_DFS_JP;
1263 default:
1264 return NL80211_DFS_UNSET;
1265 }
1266}
1267
Hangtian Zhu9a28ed02019-09-24 12:18:20 +08001268/**
1269 * hdd_set_dfs_pri_multiplier() - Set dfs_pri_multiplier for ETSI region
1270 * @dfs_region: DFS region
1271 *
1272 * Return: none
1273 */
1274#ifdef DFS_PRI_MULTIPLIER
1275static void hdd_set_dfs_pri_multiplier(struct hdd_context *hdd_ctx,
1276 enum dfs_reg dfs_region)
1277{
1278 if (dfs_region == DFS_ETSI_REGION)
1279 wlan_sap_set_dfs_pri_multiplier(hdd_ctx->mac_handle);
1280}
1281#else
1282static inline void hdd_set_dfs_pri_multiplier(struct hdd_context *hdd_ctx,
1283 enum dfs_reg dfs_region)
1284{
1285}
1286#endif
1287
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001288void hdd_send_wiphy_regd_sync_event(struct hdd_context *hdd_ctx)
1289{
1290 struct ieee80211_regdomain *regd;
1291 struct ieee80211_reg_rule *regd_rules;
Amar Singhal27be4442018-09-24 14:30:55 -07001292 struct reg_rule_info reg_rules_struct;
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001293 struct reg_rule_info *reg_rules;
Amar Singhal27be4442018-09-24 14:30:55 -07001294 QDF_STATUS status;
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001295 uint8_t i;
1296
1297 if (!hdd_ctx) {
1298 hdd_err("hdd_ctx is NULL");
1299 return;
1300 }
Amar Singhal27be4442018-09-24 14:30:55 -07001301
1302 status = ucfg_reg_get_regd_rules(hdd_ctx->pdev, &reg_rules_struct);
1303 if (QDF_IS_STATUS_ERROR(status)) {
1304 hdd_err("could not get reg rules");
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001305 return;
1306 }
Amar Singhal27be4442018-09-24 14:30:55 -07001307
1308 reg_rules = &reg_rules_struct;
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001309 if (!reg_rules->num_of_reg_rules) {
1310 hdd_err("no reg rules %d", reg_rules->num_of_reg_rules);
1311 return;
1312 }
Amar Singhal27be4442018-09-24 14:30:55 -07001313
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001314 regd = qdf_mem_malloc((reg_rules->num_of_reg_rules *
1315 sizeof(*regd_rules) + sizeof(*regd)));
1316 if (!regd) {
1317 hdd_err("mem alloc failed for reg rules");
1318 return;
1319 }
Amar Singhal27be4442018-09-24 14:30:55 -07001320
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001321 regd->n_reg_rules = reg_rules->num_of_reg_rules;
1322 qdf_mem_copy(regd->alpha2, reg_rules->alpha2, REG_ALPHA2_LEN + 1);
Jianmin Zhuc2d91c22018-07-02 14:05:44 +08001323 regd->dfs_region =
1324 dfs_reg_to_nl80211_dfs_regions(reg_rules->dfs_region);
Hangtian Zhu9a28ed02019-09-24 12:18:20 +08001325
1326 hdd_set_dfs_pri_multiplier(hdd_ctx, reg_rules->dfs_region);
1327
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001328 regd_rules = regd->reg_rules;
1329 hdd_debug("Regulatory Domain %s", regd->alpha2);
1330 hdd_debug("start freq\tend freq\t@ max_bw\tant_gain\tpwr\tflags");
1331 for (i = 0; i < reg_rules->num_of_reg_rules; i++) {
1332 regd_rules[i].freq_range.start_freq_khz =
Amar Singhal27be4442018-09-24 14:30:55 -07001333 reg_rules->reg_rules[i].start_freq * 1000;
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001334 regd_rules[i].freq_range.end_freq_khz =
Amar Singhal27be4442018-09-24 14:30:55 -07001335 reg_rules->reg_rules[i].end_freq * 1000;
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001336 regd_rules[i].freq_range.max_bandwidth_khz =
Amar Singhal27be4442018-09-24 14:30:55 -07001337 reg_rules->reg_rules[i].max_bw * 1000;
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001338 regd_rules[i].power_rule.max_antenna_gain =
Amar Singhal27be4442018-09-24 14:30:55 -07001339 reg_rules->reg_rules[i].ant_gain * 100;
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001340 regd_rules[i].power_rule.max_eirp =
Amar Singhal27be4442018-09-24 14:30:55 -07001341 reg_rules->reg_rules[i].reg_power * 100;
1342 map_nl_reg_rule_flags(reg_rules->reg_rules[i].flags,
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001343 &regd_rules[i].flags);
1344 hdd_debug("%d KHz\t%d KHz\t@ %d KHz\t%d\t\t%d\t%d",
1345 regd_rules[i].freq_range.start_freq_khz,
1346 regd_rules[i].freq_range.end_freq_khz,
1347 regd_rules[i].freq_range.max_bandwidth_khz,
1348 regd_rules[i].power_rule.max_antenna_gain,
1349 regd_rules[i].power_rule.max_eirp,
1350 regd_rules[i].flags);
1351 }
Amar Singhalac26de22018-06-22 12:53:06 -07001352
1353 regulatory_set_wiphy_regd(hdd_ctx->wiphy, regd);
1354
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001355 hdd_debug("regd sync event sent with reg rules info");
1356 qdf_mem_free(regd);
1357}
1358#endif
1359
Amar Singhal6f8592b2017-04-26 14:31:58 -07001360static void hdd_regulatory_dyn_cbk(struct wlan_objmgr_psoc *psoc,
1361 struct wlan_objmgr_pdev *pdev,
1362 struct regulatory_channel *chan_list,
Kiran Kumar Lokere48795792017-07-07 15:34:29 -07001363 struct avoid_freq_ind_data *avoid_freq_ind,
Amar Singhal6f8592b2017-04-26 14:31:58 -07001364 void *arg)
1365{
1366 struct wiphy *wiphy;
1367 struct pdev_osif_priv *pdev_priv;
Jeff Johnson4af78662017-08-28 11:44:08 -07001368 struct hdd_context *hdd_ctx;
Amar Singhal6f8592b2017-04-26 14:31:58 -07001369 enum country_src cc_src;
1370 uint8_t alpha2[REG_ALPHA2_LEN + 1];
1371
1372 pdev_priv = wlan_pdev_get_ospriv(pdev);
1373 wiphy = pdev_priv->wiphy;
1374 hdd_ctx = wiphy_priv(wiphy);
1375
Paul Zhang3d026fb2018-02-03 15:46:29 +08001376 hdd_debug("process channel list update from regulatory");
Amar Singhal6f8592b2017-04-26 14:31:58 -07001377
1378 fill_wiphy_band_channels(wiphy, chan_list, NL80211_BAND_2GHZ);
1379 fill_wiphy_band_channels(wiphy, chan_list, NL80211_BAND_5GHZ);
1380
Dustin Brown05d81302018-09-11 16:49:22 -07001381 cc_src = ucfg_reg_get_cc_and_src(hdd_ctx->psoc, alpha2);
Amar Singhal6f8592b2017-04-26 14:31:58 -07001382 qdf_mem_copy(hdd_ctx->reg.alpha2, alpha2, REG_ALPHA2_LEN + 1);
Jeff Johnsonb396b062018-06-13 14:01:14 -07001383 sme_set_cc_src(hdd_ctx->mac_handle, cc_src);
Amar Singhal6f8592b2017-04-26 14:31:58 -07001384
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001385 /* Check the kernel version for upstream commit aced43ce780dc5 that
1386 * has support for processing user cell_base hints when wiphy is
1387 * self managed or check the backport flag for the same.
1388 */
1389#if defined CFG80211_USER_HINT_CELL_BASE_SELF_MANAGED || \
1390 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0))
1391 if (wiphy->registered)
1392 hdd_send_wiphy_regd_sync_event(hdd_ctx);
1393#endif
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001394
Kiran Kumar Lokere48795792017-07-07 15:34:29 -07001395 if (avoid_freq_ind)
1396 hdd_ch_avoid_ind(hdd_ctx, &avoid_freq_ind->chan_list,
1397 &avoid_freq_ind->freq_list);
Tushnim Bhattacharyya84e1e232018-06-27 17:57:24 -07001398 else
1399 sme_generic_change_country_code(hdd_ctx->mac_handle,
1400 hdd_ctx->reg.alpha2);
Amar Singhal6f8592b2017-04-26 14:31:58 -07001401}
1402
Paul Zhanga05a0252018-01-22 11:08:21 +08001403int hdd_regulatory_init(struct hdd_context *hdd_ctx, struct wiphy *wiphy)
Will Huang93bc1372018-01-08 18:16:17 +08001404{
Paul Zhanga05a0252018-01-22 11:08:21 +08001405 bool offload_enabled;
Amar Singhal5cccafe2017-02-15 12:42:58 -08001406 struct reg_config_vars config_vars;
Amar Singhal2e4cccc2019-08-06 12:47:18 -07001407 struct regulatory_channel *cur_chan_list;
Amar Singhal6f8592b2017-04-26 14:31:58 -07001408 enum country_src cc_src;
1409 uint8_t alpha2[REG_ALPHA2_LEN + 1];
Amar Singhal5cccafe2017-02-15 12:42:58 -08001410
Amar Singhal2e4cccc2019-08-06 12:47:18 -07001411 cur_chan_list = qdf_mem_malloc(sizeof(*cur_chan_list) * NUM_CHANNELS);
1412 if (!cur_chan_list) {
1413 return -ENOMEM;
1414 }
1415
Amar Singhal5cccafe2017-02-15 12:42:58 -08001416 reg_program_config_vars(hdd_ctx, &config_vars);
Dustin Brown05d81302018-09-11 16:49:22 -07001417 ucfg_reg_register_chan_change_callback(hdd_ctx->psoc,
Amar Singhal6f8592b2017-04-26 14:31:58 -07001418 hdd_regulatory_dyn_cbk,
1419 NULL);
Amar Singhal5cccafe2017-02-15 12:42:58 -08001420
Dustin Brown05d81302018-09-11 16:49:22 -07001421 ucfg_reg_set_config_vars(hdd_ctx->psoc, config_vars);
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001422
Paul Zhanga05a0252018-01-22 11:08:21 +08001423 wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001424 /* Check the kernel version for upstream commit aced43ce780dc5 that
1425 * has support for processing user cell_base hints when wiphy is
1426 * self managed or check the backport flag for the same.
1427 */
1428#if defined CFG80211_USER_HINT_CELL_BASE_SELF_MANAGED || \
1429 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0))
1430 wiphy->features |= NL80211_FEATURE_CELL_BASE_REG_HINTS;
1431#endif
Paul Zhanga05a0252018-01-22 11:08:21 +08001432 wiphy->reg_notifier = hdd_reg_notifier;
Dustin Brown05d81302018-09-11 16:49:22 -07001433 offload_enabled = ucfg_reg_is_regdb_offloaded(hdd_ctx->psoc);
Kiran Kumar Lokere0508af92018-04-23 18:38:32 -07001434 hdd_debug("regulatory offload_enabled %d", offload_enabled);
Paul Zhanga05a0252018-01-22 11:08:21 +08001435 if (offload_enabled) {
Amar Singhal5cccafe2017-02-15 12:42:58 -08001436 hdd_ctx->reg_offload = true;
Dustin Brown07901ec2018-09-07 11:02:41 -07001437 ucfg_reg_get_current_chan_list(hdd_ctx->pdev,
Paul Zhanga05a0252018-01-22 11:08:21 +08001438 cur_chan_list);
1439 fill_wiphy_band_channels(wiphy, cur_chan_list,
1440 NL80211_BAND_2GHZ);
1441 fill_wiphy_band_channels(wiphy, cur_chan_list,
1442 NL80211_BAND_5GHZ);
1443
Dustin Brown05d81302018-09-11 16:49:22 -07001444 cc_src = ucfg_reg_get_cc_and_src(hdd_ctx->psoc, alpha2);
Paul Zhanga05a0252018-01-22 11:08:21 +08001445 qdf_mem_copy(hdd_ctx->reg.alpha2, alpha2, REG_ALPHA2_LEN + 1);
Jeff Johnsonb396b062018-06-13 14:01:14 -07001446 sme_set_cc_src(hdd_ctx->mac_handle, cc_src);
Amar Singhal5cccafe2017-02-15 12:42:58 -08001447 } else {
1448 hdd_ctx->reg_offload = false;
Amar Singhal5cccafe2017-02-15 12:42:58 -08001449 }
1450
Amar Singhal2e4cccc2019-08-06 12:47:18 -07001451 qdf_mem_free(cur_chan_list);
Amar Singhal5cccafe2017-02-15 12:42:58 -08001452 return 0;
1453}
Amar Singhal6f8592b2017-04-26 14:31:58 -07001454
Amar Singhal5cccafe2017-02-15 12:42:58 -08001455#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
Jeff Johnson4af78662017-08-28 11:44:08 -07001456int hdd_regulatory_init(struct hdd_context *hdd_ctx, struct wiphy *wiphy)
Amar Singhal5cccafe2017-02-15 12:42:58 -08001457{
1458 hdd_ctx->reg_offload = false;
1459 wiphy->reg_notifier = hdd_reg_notifier;
1460 wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
1461 wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
1462 hdd_regulatory_init_no_offload(hdd_ctx, wiphy);
1463
1464 return 0;
1465}
Amar Singhal6f8592b2017-04-26 14:31:58 -07001466
Amar Singhal5cccafe2017-02-15 12:42:58 -08001467#else
Jeff Johnson4af78662017-08-28 11:44:08 -07001468int hdd_regulatory_init(struct hdd_context *hdd_ctx, struct wiphy *wiphy)
Amar Singhal5cccafe2017-02-15 12:42:58 -08001469{
1470 hdd_ctx->reg_offload = false;
1471 wiphy->reg_notifier = hdd_reg_notifier;
1472 wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS;
1473 wiphy->country_ie_pref |= NL80211_COUNTRY_IE_IGNORE_CORE;
1474 hdd_regulatory_init_no_offload(hdd_ctx, wiphy);
1475
1476 return 0;
1477}
1478#endif