1 /*
2 * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 *
6 * Permission to use, copy, modify, and/or distribute this software for
7 * any purpose with or without fee is hereby granted, provided that the
8 * above copyright notice and this permission notice appear in all
9 * copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
12 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
14 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
15 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
16 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
17 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
18 * PERFORMANCE OF THIS SOFTWARE.
19 */
20
21 /**
22 * DOC: reg_db_parser.c
23 * This file provides regulatory data base parser functions.
24 */
25
26 #include <qdf_types.h>
27 #include <wlan_cmn.h>
28 #include <reg_services_public_struct.h>
29 #include "reg_db.h"
30 #include "reg_db_parser.h"
31 #include <qdf_mem.h>
32 #include <wlan_objmgr_psoc_obj.h>
33 #include "reg_priv_objs.h"
34 #include "reg_utils.h"
35
36 #ifdef CONFIG_REG_CLIENT
37 /**
38 * reg_update_alpha2_from_domain() - Get country alpha2 code from reg domain
39 * @reg_info: pointer to hold alpha2 code
40 *
41 * This function is used to populate alpha2 of @reg_info with:
42 * (a) "00" (REG_WORLD_ALPHA2) for WORLD domain and
43 * (b) alpha2 of first country matching with non WORLD domain.
44 *
45 * Return: None
46 */
47 static void
reg_update_alpha2_from_domain(struct cur_regulatory_info * reg_info)48 reg_update_alpha2_from_domain(struct cur_regulatory_info *reg_info)
49 {
50 uint16_t i;
51 int num_countries;
52
53 if (reg_is_world_ctry_code(reg_info->reg_dmn_pair)) {
54 qdf_mem_copy(reg_info->alpha2, REG_WORLD_ALPHA2,
55 sizeof(reg_info->alpha2));
56 return;
57 }
58
59 reg_get_num_countries(&num_countries);
60
61 for (i = 0; i < (uint16_t)num_countries; i++)
62 if (g_all_countries[i].reg_dmn_pair_id ==
63 reg_info->reg_dmn_pair)
64 break;
65
66 if (i == (uint16_t)num_countries)
67 return;
68
69 qdf_mem_copy(reg_info->alpha2, g_all_countries[i].alpha2,
70 sizeof(g_all_countries[i].alpha2));
71 reg_info->ctry_code = g_all_countries[i].country_code;
72 }
73 #else
74 static inline void
reg_update_alpha2_from_domain(struct cur_regulatory_info * reg_info)75 reg_update_alpha2_from_domain(struct cur_regulatory_info *reg_info)
76 {
77 }
78 #endif
79
80 #ifdef WLAN_REG_PARTIAL_OFFLOAD
reg_is_country_code_valid(uint8_t * alpha2)81 QDF_STATUS reg_is_country_code_valid(uint8_t *alpha2)
82 {
83 uint16_t i;
84 int num_countries;
85
86 reg_get_num_countries(&num_countries);
87
88 for (i = 0; i < num_countries; i++) {
89 if ((g_all_countries[i].alpha2[0] == alpha2[0]) &&
90 (g_all_countries[i].alpha2[1] == alpha2[1]))
91 return QDF_STATUS_SUCCESS;
92 else
93 continue;
94 }
95
96 return QDF_STATUS_E_FAILURE;
97 }
98
reg_regrules_assign(uint8_t dmn_id_2g,uint8_t dmn_id_5g,uint8_t ant_gain_2g,uint8_t ant_gain_5g,struct cur_regulatory_info * reg_info)99 QDF_STATUS reg_regrules_assign(uint8_t dmn_id_2g, uint8_t dmn_id_5g,
100 uint8_t ant_gain_2g, uint8_t ant_gain_5g,
101 struct cur_regulatory_info *reg_info)
102
103 {
104 uint8_t k;
105 uint8_t rule_index;
106 struct cur_reg_rule *r_r_2g = reg_info->reg_rules_2g_ptr;
107 struct cur_reg_rule *r_r_5g = reg_info->reg_rules_5g_ptr;
108
109 for (k = 0; k < reg_info->num_2g_reg_rules; k++) {
110 rule_index = regdomains_2g[dmn_id_2g].reg_rule_id[k];
111 r_r_2g->start_freq = reg_rules_2g[rule_index].start_freq;
112 r_r_2g->end_freq = reg_rules_2g[rule_index].end_freq;
113 r_r_2g->max_bw = reg_rules_2g[rule_index].max_bw;
114 r_r_2g->reg_power = reg_rules_2g[rule_index].reg_power;
115 r_r_2g->flags = reg_rules_2g[rule_index].flags;
116 r_r_2g->ant_gain = ant_gain_2g;
117 r_r_2g++;
118 }
119
120 for (k = 0; k < reg_info->num_5g_reg_rules; k++) {
121 rule_index = regdomains_5g[dmn_id_5g].reg_rule_id[k];
122 r_r_5g->start_freq = reg_rules_5g[rule_index].start_freq;
123 r_r_5g->end_freq = reg_rules_5g[rule_index].end_freq;
124 r_r_5g->max_bw = reg_rules_5g[rule_index].max_bw;
125 r_r_5g->reg_power = reg_rules_5g[rule_index].reg_power;
126 r_r_5g->flags = reg_rules_5g[rule_index].flags;
127 r_r_5g->ant_gain = ant_gain_5g;
128 r_r_5g++;
129 }
130
131 if ((r_r_2g == reg_info->reg_rules_2g_ptr) &&
132 (r_r_5g == reg_info->reg_rules_5g_ptr))
133 return QDF_STATUS_E_FAILURE;
134
135 return QDF_STATUS_SUCCESS;
136 }
137
reg_get_rdpair_from_country_iso(uint8_t * alpha2,uint16_t * country_index,uint16_t * regdmn_pair)138 QDF_STATUS reg_get_rdpair_from_country_iso(uint8_t *alpha2,
139 uint16_t *country_index,
140 uint16_t *regdmn_pair)
141 {
142 uint16_t i, j;
143 int num_countries;
144 int num_reg_dmn;
145
146 reg_get_num_countries(&num_countries);
147 reg_get_num_reg_dmn_pairs(&num_reg_dmn);
148
149 for (i = 0; i < num_countries; i++) {
150 if ((g_all_countries[i].alpha2[0] == alpha2[0]) &&
151 (g_all_countries[i].alpha2[1] == alpha2[1]))
152 break;
153 }
154
155 if (i == num_countries) {
156 *country_index = -1;
157 return QDF_STATUS_E_FAILURE;
158 }
159
160 for (j = 0; j < num_reg_dmn; j++) {
161 if (g_reg_dmn_pairs[j].reg_dmn_pair_id ==
162 g_all_countries[i].reg_dmn_pair_id)
163 break;
164 }
165
166 if (j == num_reg_dmn) {
167 *regdmn_pair = -1;
168 return QDF_STATUS_E_FAILURE;
169 }
170
171 *country_index = i;
172 *regdmn_pair = j;
173
174 return QDF_STATUS_SUCCESS;
175 }
176
reg_get_rdpair_from_regdmn_id(uint16_t reg_2g_5g_pair_id,uint16_t * regdmn_pair)177 QDF_STATUS reg_get_rdpair_from_regdmn_id(uint16_t reg_2g_5g_pair_id,
178 uint16_t *regdmn_pair)
179 {
180 uint16_t j;
181 int num_reg_dmn;
182
183 reg_get_num_reg_dmn_pairs(&num_reg_dmn);
184
185 for (j = 0; j < num_reg_dmn; j++) {
186 if (g_reg_dmn_pairs[j].reg_dmn_pair_id == reg_2g_5g_pair_id)
187 break;
188 }
189
190 if (j == num_reg_dmn) {
191 *regdmn_pair = -1;
192 return QDF_STATUS_E_FAILURE;
193 }
194
195 *regdmn_pair = j;
196
197 return QDF_STATUS_SUCCESS;
198 }
199
reg_get_rdpair_from_country_code(uint16_t cc,uint16_t * country_index,uint16_t * regdmn_pair)200 QDF_STATUS reg_get_rdpair_from_country_code(uint16_t cc,
201 uint16_t *country_index,
202 uint16_t *regdmn_pair)
203 {
204 uint16_t i, j;
205 int num_countries;
206 int num_reg_dmn;
207
208 reg_get_num_countries(&num_countries);
209 reg_get_num_reg_dmn_pairs(&num_reg_dmn);
210
211 for (i = 0; i < num_countries; i++) {
212 if (g_all_countries[i].country_code == cc)
213 break;
214 }
215
216 if (i == num_countries) {
217 *country_index = -1;
218 return QDF_STATUS_E_FAILURE;
219 }
220
221 for (j = 0; j < num_reg_dmn; j++) {
222 if (g_reg_dmn_pairs[j].reg_dmn_pair_id ==
223 g_all_countries[i].reg_dmn_pair_id)
224 break;
225 }
226
227 if (j == num_reg_dmn) {
228 *regdmn_pair = -1;
229 return QDF_STATUS_E_FAILURE;
230 }
231
232 *country_index = i;
233 *regdmn_pair = j;
234
235 return QDF_STATUS_SUCCESS;
236 }
237
reg_get_reginfo_from_country_code_and_regdmn_pair(struct cur_regulatory_info * reg_info,uint16_t country_index,uint16_t regdmn_pair)238 static inline QDF_STATUS reg_get_reginfo_from_country_code_and_regdmn_pair(
239 struct cur_regulatory_info *reg_info,
240 uint16_t country_index,
241 uint16_t regdmn_pair)
242 {
243 uint8_t rule_size_2g, rule_size_5g;
244 uint8_t dmn_id_5g, dmn_id_2g;
245 uint8_t ant_gain_2g, ant_gain_5g;
246 QDF_STATUS err;
247
248 dmn_id_5g = g_reg_dmn_pairs[regdmn_pair].dmn_id_5g;
249 dmn_id_2g = g_reg_dmn_pairs[regdmn_pair].dmn_id_2g;
250
251 rule_size_2g = QDF_ARRAY_SIZE(regdomains_2g[dmn_id_2g].reg_rule_id);
252 rule_size_5g = QDF_ARRAY_SIZE(regdomains_5g[dmn_id_5g].reg_rule_id);
253
254 if (((rule_size_2g + rule_size_5g) >=
255 regdomains_2g[dmn_id_2g].num_reg_rules +
256 regdomains_5g[dmn_id_5g].num_reg_rules)) {
257
258 qdf_mem_copy(reg_info->alpha2,
259 g_all_countries[country_index].alpha2,
260 sizeof(g_all_countries[country_index].alpha2));
261
262 reg_info->ctry_code =
263 g_all_countries[country_index].country_code;
264 reg_info->reg_dmn_pair =
265 g_reg_dmn_pairs[regdmn_pair].reg_dmn_pair_id;
266 reg_info->dfs_region = regdomains_5g[dmn_id_5g].dfs_region;
267 reg_info->phybitmap =
268 g_all_countries[country_index].phymode_bitmap;
269 if (g_all_countries[country_index].max_bw_2g <
270 regdomains_2g[dmn_id_2g].max_bw)
271 reg_info->max_bw_2g =
272 g_all_countries[country_index].max_bw_2g;
273 else
274 reg_info->max_bw_2g =
275 regdomains_2g[dmn_id_2g].max_bw;
276
277 if (g_all_countries[country_index].max_bw_5g <
278 regdomains_5g[dmn_id_5g].max_bw)
279 reg_info->max_bw_5g =
280 g_all_countries[country_index].max_bw_5g;
281 else
282 reg_info->max_bw_5g =
283 regdomains_5g[dmn_id_5g].max_bw;
284
285 reg_info->min_bw_2g = regdomains_2g[dmn_id_2g].min_bw;
286 reg_info->min_bw_5g = regdomains_5g[dmn_id_5g].min_bw;
287
288 ant_gain_2g = regdomains_2g[dmn_id_2g].ant_gain;
289 ant_gain_5g = regdomains_5g[dmn_id_5g].ant_gain;
290
291 reg_info->num_2g_reg_rules =
292 regdomains_2g[dmn_id_2g].num_reg_rules;
293 reg_info->num_5g_reg_rules =
294 regdomains_5g[dmn_id_5g].num_reg_rules;
295
296 reg_info->reg_rules_2g_ptr = (struct cur_reg_rule *)
297 qdf_mem_malloc((reg_info->num_2g_reg_rules) *
298 sizeof(struct cur_reg_rule));
299 reg_info->reg_rules_5g_ptr = (struct cur_reg_rule *)
300 qdf_mem_malloc((reg_info->num_5g_reg_rules) *
301 sizeof(struct cur_reg_rule));
302
303 err = reg_regrules_assign(dmn_id_2g, dmn_id_5g,
304 ant_gain_2g, ant_gain_5g, reg_info);
305
306 if (err == QDF_STATUS_E_FAILURE) {
307 reg_err("No rule for country index = %d regdmn_pair = %d",
308 country_index, regdmn_pair);
309 return QDF_STATUS_E_FAILURE;
310 }
311
312 return QDF_STATUS_SUCCESS;
313 } else if (!(((rule_size_2g + rule_size_5g) >=
314 regdomains_2g[dmn_id_2g].num_reg_rules +
315 regdomains_5g[dmn_id_5g].num_reg_rules)))
316 return QDF_STATUS_E_NOMEM;
317
318 return QDF_STATUS_SUCCESS;
319 }
320
reg_get_reginfo_from_regdmn_pair(struct cur_regulatory_info * reg_info,uint16_t regdmn_pair)321 static inline QDF_STATUS reg_get_reginfo_from_regdmn_pair(
322 struct cur_regulatory_info *reg_info,
323 uint16_t regdmn_pair)
324 {
325 uint8_t rule_size_2g, rule_size_5g;
326 uint8_t dmn_id_5g, dmn_id_2g;
327 uint8_t ant_gain_2g, ant_gain_5g;
328 QDF_STATUS err;
329
330 dmn_id_5g = g_reg_dmn_pairs[regdmn_pair].dmn_id_5g;
331 dmn_id_2g = g_reg_dmn_pairs[regdmn_pair].dmn_id_2g;
332
333 rule_size_2g = QDF_ARRAY_SIZE(regdomains_2g[dmn_id_2g].reg_rule_id);
334 rule_size_5g = QDF_ARRAY_SIZE(regdomains_5g[dmn_id_5g].reg_rule_id);
335
336 if (((rule_size_2g + rule_size_5g) >=
337 regdomains_2g[dmn_id_2g].num_reg_rules +
338 regdomains_5g[dmn_id_5g].num_reg_rules)) {
339
340 qdf_mem_zero(reg_info->alpha2, sizeof(reg_info->alpha2));
341
342 reg_info->reg_dmn_pair =
343 g_reg_dmn_pairs[regdmn_pair].reg_dmn_pair_id;
344 reg_info->ctry_code = 0;
345
346 reg_update_alpha2_from_domain(reg_info);
347
348 reg_info->dfs_region = regdomains_5g[dmn_id_5g].dfs_region;
349 reg_info->phybitmap = 0;
350
351 reg_info->max_bw_2g = regdomains_2g[dmn_id_2g].max_bw;
352 reg_info->max_bw_5g = regdomains_5g[dmn_id_5g].max_bw;
353
354 reg_info->min_bw_2g = regdomains_2g[dmn_id_2g].min_bw;
355 reg_info->min_bw_5g = regdomains_5g[dmn_id_5g].min_bw;
356
357 ant_gain_2g = regdomains_2g[dmn_id_2g].ant_gain;
358 ant_gain_5g = regdomains_5g[dmn_id_5g].ant_gain;
359
360 reg_info->num_2g_reg_rules =
361 regdomains_2g[dmn_id_2g].num_reg_rules;
362 reg_info->num_5g_reg_rules =
363 regdomains_5g[dmn_id_5g].num_reg_rules;
364
365 reg_info->reg_rules_2g_ptr = (struct cur_reg_rule *)
366 qdf_mem_malloc((reg_info->num_2g_reg_rules) *
367 sizeof(struct cur_reg_rule));
368 reg_info->reg_rules_5g_ptr = (struct cur_reg_rule *)
369 qdf_mem_malloc((reg_info->num_5g_reg_rules) *
370 sizeof(struct cur_reg_rule));
371
372 err = reg_regrules_assign(dmn_id_2g, dmn_id_5g,
373 ant_gain_2g, ant_gain_5g, reg_info);
374 if (err == QDF_STATUS_E_FAILURE) {
375 reg_err("No rule for regdmn_pair = %d\n", regdmn_pair);
376 return QDF_STATUS_E_FAILURE;
377 }
378
379 return QDF_STATUS_SUCCESS;
380 } else if (!(((rule_size_2g + rule_size_5g) >=
381 regdomains_2g[dmn_id_2g].num_reg_rules +
382 regdomains_5g[dmn_id_5g].num_reg_rules)))
383 return QDF_STATUS_E_NOMEM;
384
385 return QDF_STATUS_SUCCESS;
386 }
387
reg_get_cur_reginfo(struct cur_regulatory_info * reg_info,uint16_t country_index,uint16_t regdmn_pair)388 QDF_STATUS reg_get_cur_reginfo(struct cur_regulatory_info *reg_info,
389 uint16_t country_index,
390 uint16_t regdmn_pair)
391 {
392 if ((country_index != (uint16_t)(-1)) &&
393 (regdmn_pair != (uint16_t)(-1)))
394 return reg_get_reginfo_from_country_code_and_regdmn_pair(
395 reg_info, country_index, regdmn_pair);
396 else if (regdmn_pair != (uint16_t)(-1))
397 return reg_get_reginfo_from_regdmn_pair(reg_info, regdmn_pair);
398 else
399 return QDF_STATUS_E_FAILURE;
400
401 return QDF_STATUS_SUCCESS;
402 }
403 #endif /* WLAN_REG_PARTIAL_OFFLOAD */
404