1 /* 2 * Copyright (c) 2017-2019 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_form_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 224 reg_info->max_bw_2g = g_all_countries[country_index].max_bw_2g; 225 reg_info->max_bw_5g = g_all_countries[country_index].max_bw_5g; 226 227 reg_info->min_bw_2g = regdomains_2g[dmn_id_2g].min_bw; 228 reg_info->min_bw_5g = regdomains_5g[dmn_id_5g].min_bw; 229 230 ant_gain_2g = regdomains_2g[dmn_id_2g].ant_gain; 231 ant_gain_5g = regdomains_5g[dmn_id_5g].ant_gain; 232 233 reg_info->num_2g_reg_rules = 234 regdomains_2g[dmn_id_2g].num_reg_rules; 235 reg_info->num_5g_reg_rules = 236 regdomains_5g[dmn_id_5g].num_reg_rules; 237 238 reg_info->reg_rules_2g_ptr = (struct cur_reg_rule *) 239 qdf_mem_malloc((reg_info->num_2g_reg_rules) * 240 sizeof(struct cur_reg_rule)); 241 reg_info->reg_rules_5g_ptr = (struct cur_reg_rule *) 242 qdf_mem_malloc((reg_info->num_5g_reg_rules) * 243 sizeof(struct cur_reg_rule)); 244 245 err = reg_regrules_assign(dmn_id_2g, dmn_id_5g, 246 ant_gain_2g, ant_gain_5g, reg_info); 247 248 if (err == QDF_STATUS_E_FAILURE) { 249 reg_err("%s : No rule found for country index = %d regdmn_pair = %d", 250 __func__, country_index, regdmn_pair); 251 return QDF_STATUS_E_FAILURE; 252 } 253 254 return QDF_STATUS_SUCCESS; 255 } else if (!(((rule_size_2g + rule_size_5g) >= 256 regdomains_2g[dmn_id_2g].num_reg_rules + 257 regdomains_5g[dmn_id_5g].num_reg_rules))) 258 return QDF_STATUS_E_NOMEM; 259 260 return QDF_STATUS_SUCCESS; 261 } 262 263 #ifdef CONFIG_REG_CLIENT 264 /** 265 * reg_update_alpha2_from_domain() - Get country alpha2 code from reg domain 266 * @reg_info: pointer to hold alpha2 code 267 * 268 * This function is used to populate alpha2 of @reg_info with: 269 * (a) "00" (REG_WORLD_ALPHA2) for WORLD domain and 270 * (b) alpha2 of first country matching with non WORLD domain. 271 * 272 * Return: None 273 */ 274 static void 275 reg_update_alpha2_from_domain(struct cur_regulatory_info *reg_info) 276 { 277 uint16_t i; 278 int num_countries; 279 280 if (reg_is_world_ctry_code(reg_info->reg_dmn_pair)) { 281 qdf_mem_copy(reg_info->alpha2, REG_WORLD_ALPHA2, 282 sizeof(reg_info->alpha2)); 283 return; 284 } 285 286 reg_get_num_countries(&num_countries); 287 288 for (i = 0; i < (uint16_t)num_countries; i++) 289 if (g_all_countries[i].reg_dmn_pair_id == 290 reg_info->reg_dmn_pair) 291 break; 292 293 if (i == (uint16_t)num_countries) 294 return; 295 296 qdf_mem_copy(reg_info->alpha2, g_all_countries[i].alpha2, 297 sizeof(g_all_countries[i].alpha2)); 298 reg_info->ctry_code = g_all_countries[i].country_code; 299 } 300 #else 301 static inline void 302 reg_update_alpha2_from_domain(struct cur_regulatory_info *reg_info) 303 { 304 } 305 #endif 306 307 static inline QDF_STATUS reg_get_reginfo_form_regdmn_pair( 308 struct cur_regulatory_info *reg_info, 309 uint16_t regdmn_pair) 310 { 311 uint8_t rule_size_2g, rule_size_5g; 312 uint8_t dmn_id_5g, dmn_id_2g; 313 uint8_t ant_gain_2g, ant_gain_5g; 314 QDF_STATUS err; 315 316 dmn_id_5g = g_reg_dmn_pairs[regdmn_pair].dmn_id_5g; 317 dmn_id_2g = g_reg_dmn_pairs[regdmn_pair].dmn_id_2g; 318 319 rule_size_2g = QDF_ARRAY_SIZE(regdomains_2g[dmn_id_2g].reg_rule_id); 320 rule_size_5g = QDF_ARRAY_SIZE(regdomains_5g[dmn_id_5g].reg_rule_id); 321 322 if (((rule_size_2g + rule_size_5g) >= 323 regdomains_2g[dmn_id_2g].num_reg_rules + 324 regdomains_5g[dmn_id_5g].num_reg_rules)) { 325 326 qdf_mem_zero(reg_info->alpha2, sizeof(reg_info->alpha2)); 327 328 reg_info->reg_dmn_pair = 329 g_reg_dmn_pairs[regdmn_pair].reg_dmn_pair_id; 330 reg_info->ctry_code = 0; 331 332 reg_update_alpha2_from_domain(reg_info); 333 334 reg_info->dfs_region = regdomains_5g[dmn_id_5g].dfs_region; 335 reg_info->phybitmap = 0; 336 337 reg_info->max_bw_2g = 40; 338 reg_info->max_bw_5g = 160; 339 340 reg_info->min_bw_2g = regdomains_2g[dmn_id_2g].min_bw; 341 reg_info->min_bw_5g = regdomains_5g[dmn_id_5g].min_bw; 342 343 ant_gain_2g = regdomains_2g[dmn_id_2g].ant_gain; 344 ant_gain_5g = regdomains_5g[dmn_id_5g].ant_gain; 345 346 reg_info->num_2g_reg_rules = 347 regdomains_2g[dmn_id_2g].num_reg_rules; 348 reg_info->num_5g_reg_rules = 349 regdomains_5g[dmn_id_5g].num_reg_rules; 350 351 reg_info->reg_rules_2g_ptr = (struct cur_reg_rule *) 352 qdf_mem_malloc((reg_info->num_2g_reg_rules) * 353 sizeof(struct cur_reg_rule)); 354 reg_info->reg_rules_5g_ptr = (struct cur_reg_rule *) 355 qdf_mem_malloc((reg_info->num_5g_reg_rules) * 356 sizeof(struct cur_reg_rule)); 357 358 err = reg_regrules_assign(dmn_id_2g, dmn_id_5g, 359 ant_gain_2g, ant_gain_5g, reg_info); 360 if (err == QDF_STATUS_E_FAILURE) { 361 reg_err("%s : No rule found for regdmn_pair = %d\n", 362 __func__, regdmn_pair); 363 return QDF_STATUS_E_FAILURE; 364 } 365 366 return QDF_STATUS_SUCCESS; 367 } else if (!(((rule_size_2g + rule_size_5g) >= 368 regdomains_2g[dmn_id_2g].num_reg_rules + 369 regdomains_5g[dmn_id_5g].num_reg_rules))) 370 return QDF_STATUS_E_NOMEM; 371 372 return QDF_STATUS_SUCCESS; 373 } 374 375 QDF_STATUS reg_get_cur_reginfo(struct cur_regulatory_info *reg_info, 376 uint16_t country_index, 377 uint16_t regdmn_pair) 378 { 379 if ((country_index != (uint16_t)(-1)) && 380 (regdmn_pair != (uint16_t)(-1))) 381 return reg_get_reginfo_form_country_code_and_regdmn_pair( 382 reg_info, country_index, regdmn_pair); 383 else if (regdmn_pair != (uint16_t)(-1)) 384 return reg_get_reginfo_form_regdmn_pair(reg_info, regdmn_pair); 385 else 386 return QDF_STATUS_E_FAILURE; 387 388 return QDF_STATUS_SUCCESS; 389 } 390