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