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