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