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