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