1 /* 2 * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 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 #include "cfg_all.h" 21 #include "cfg_define.h" 22 #include "cfg_dispatcher.h" 23 #include "cfg_ucfg_api.h" 24 #include "i_cfg.h" 25 #include "i_cfg_objmgr.h" 26 #include "qdf_atomic.h" 27 #include "qdf_list.h" 28 #include "qdf_mem.h" 29 #include "qdf_module.h" 30 #include "qdf_parse.h" 31 #include "qdf_status.h" 32 #include "qdf_str.h" 33 #include "qdf_trace.h" 34 #include "qdf_types.h" 35 #include "wlan_objmgr_psoc_obj.h" 36 37 /** 38 * struct cfg_value_store - backing store for an ini file 39 * @path: file path of the ini file 40 * @node: internal list node for keeping track of all the allocated stores 41 * @users: number of references on the store 42 * @values: a values struct containing the parsed values from the ini file 43 */ 44 struct cfg_value_store { 45 char *path; 46 qdf_list_node_t node; 47 qdf_atomic_t users; 48 struct cfg_values values; 49 }; 50 51 /** 52 * enum cfg_type - Enum for CFG/INI types 53 * @CFG_INT_ITEM: Integer CFG/INI 54 * @CFG_UINT_ITEM: Unsigned integer CFG/INI 55 * @CFG_BOOL_ITEM: Boolean CFG/INI 56 * @CFG_STRING_ITEM: String CFG/INI 57 * @CFG_MAC_ITEM: Mac address CFG/INI 58 * @CFG_IPV4_ITEM: IPV4 address CFG/INI 59 * @CFG_IPV6_ITEM: IPV6 address CFG/INI 60 * @CFG_MAX_ITEM: Max CFG type 61 */ 62 enum cfg_type { 63 CFG_INT_ITEM, 64 CFG_UINT_ITEM, 65 CFG_BOOL_ITEM, 66 CFG_STRING_ITEM, 67 CFG_MAC_ITEM, 68 CFG_IPV4_ITEM, 69 CFG_IPV6_ITEM, 70 CFG_MAX_ITEM, 71 }; 72 73 #define CFG_META_NAME_LENGTH_MAX 256 74 #define CFG_INI_LENGTH_MAX 128 75 76 /* define/populate dynamic metadata lookup table */ 77 78 /** 79 * struct cfg_meta - configuration item metadata for dynamic lookup during parse 80 * @name: name of the config item used in the ini file (i.e. "gScanDwellTime") 81 * @item_handler: parsing callback based on the type of the config item 82 * @min: minimum value for use in bounds checking (min_len for strings) 83 * @max: maximum value for use in bounds checking (max_len for strings) 84 * @fallback: the fallback behavior to use when configured values are invalid 85 */ 86 struct cfg_meta { 87 const char *name; 88 const uint32_t field_offset; 89 const enum cfg_type cfg_type; 90 void (*const item_handler)(struct cfg_value_store *store, 91 const struct cfg_meta *meta, 92 const char *value); 93 const int32_t min; 94 const int32_t max; 95 const enum cfg_fallback_behavior fallback; 96 }; 97 98 /* ini item handler functions */ 99 100 #define cfg_value_ptr(store, meta) \ 101 ((void *)&(store)->values + (meta)->field_offset) 102 103 static __attribute__((unused)) void cfg_int_item_handler(struct cfg_value_store * store,const struct cfg_meta * meta,const char * str_value)104 cfg_int_item_handler(struct cfg_value_store *store, 105 const struct cfg_meta *meta, 106 const char *str_value) 107 { 108 QDF_STATUS status; 109 int32_t *store_value = cfg_value_ptr(store, meta); 110 int32_t value; 111 112 status = qdf_int32_parse(str_value, &value); 113 if (QDF_IS_STATUS_ERROR(status)) { 114 cfg_err("%s=%s - Invalid format (status %d); Using default %d", 115 meta->name, str_value, status, *store_value); 116 return; 117 } 118 119 QDF_BUG(meta->min <= meta->max); 120 if (meta->min > meta->max) { 121 cfg_err("Invalid config item meta for %s", meta->name); 122 return; 123 } 124 125 if (value >= meta->min && value <= meta->max) { 126 *store_value = value; 127 return; 128 } 129 130 switch (meta->fallback) { 131 default: 132 QDF_DEBUG_PANIC("Unknown fallback method %d for cfg item '%s'", 133 meta->fallback, meta->name); 134 fallthrough; 135 case CFG_VALUE_OR_DEFAULT: 136 /* store already contains default */ 137 break; 138 case CFG_VALUE_OR_CLAMP: 139 *store_value = __cfg_clamp(value, meta->min, meta->max); 140 break; 141 } 142 143 cfg_err("%s=%d - Out of range [%d, %d]; Using %d", 144 meta->name, value, meta->min, meta->max, *store_value); 145 } 146 147 static __attribute__((unused)) void cfg_uint_item_handler(struct cfg_value_store * store,const struct cfg_meta * meta,const char * str_value)148 cfg_uint_item_handler(struct cfg_value_store *store, 149 const struct cfg_meta *meta, 150 const char *str_value) 151 { 152 QDF_STATUS status; 153 uint32_t *store_value = cfg_value_ptr(store, meta); 154 uint32_t value; 155 uint32_t min; 156 uint32_t max; 157 158 /** 159 * Since meta min and max are of type int32_t 160 * We need explicit type casting to avoid 161 * implicit wrap around for uint32_t type cfg data. 162 */ 163 min = (uint32_t)meta->min; 164 max = (uint32_t)meta->max; 165 166 status = qdf_uint32_parse(str_value, &value); 167 if (QDF_IS_STATUS_ERROR(status)) { 168 cfg_err("%s=%s - Invalid format (status %d); Using default %u", 169 meta->name, str_value, status, *store_value); 170 return; 171 } 172 173 QDF_BUG(min <= max); 174 if (min > max) { 175 cfg_err("Invalid config item meta for %s", meta->name); 176 return; 177 } 178 179 if (value >= min && value <= max) { 180 *store_value = value; 181 return; 182 } 183 184 switch (meta->fallback) { 185 default: 186 QDF_DEBUG_PANIC("Unknown fallback method %d for cfg item '%s'", 187 meta->fallback, meta->name); 188 fallthrough; 189 case CFG_VALUE_OR_DEFAULT: 190 /* store already contains default */ 191 break; 192 case CFG_VALUE_OR_CLAMP: 193 *store_value = __cfg_clamp(value, min, max); 194 break; 195 } 196 197 cfg_err("%s=%u - Out of range [%d, %d]; Using %u", 198 meta->name, value, min, max, *store_value); 199 } 200 201 static __attribute__((unused)) void cfg_bool_item_handler(struct cfg_value_store * store,const struct cfg_meta * meta,const char * str_value)202 cfg_bool_item_handler(struct cfg_value_store *store, 203 const struct cfg_meta *meta, 204 const char *str_value) 205 { 206 QDF_STATUS status; 207 bool *store_value = cfg_value_ptr(store, meta); 208 209 status = qdf_bool_parse(str_value, store_value); 210 if (QDF_IS_STATUS_SUCCESS(status)) 211 return; 212 213 cfg_err("%s=%s - Invalid format (status %d); Using default '%s'", 214 meta->name, str_value, status, *store_value ? "true" : "false"); 215 } 216 217 static __attribute__((unused)) void cfg_string_item_handler(struct cfg_value_store * store,const struct cfg_meta * meta,const char * str_value)218 cfg_string_item_handler(struct cfg_value_store *store, 219 const struct cfg_meta *meta, 220 const char *str_value) 221 { 222 char *store_value = cfg_value_ptr(store, meta); 223 qdf_size_t len; 224 225 QDF_BUG(meta->min >= 0); 226 QDF_BUG(meta->min <= meta->max); 227 if (meta->min < 0 || meta->min > meta->max) { 228 cfg_err("Invalid config item meta for %s", meta->name); 229 return; 230 } 231 232 /* ensure min length */ 233 len = qdf_str_nlen(str_value, meta->min); 234 if (len < meta->min) { 235 cfg_err("%s=%s - Too short; Using default '%s'", 236 meta->name, str_value, store_value); 237 return; 238 } 239 240 /* check max length */ 241 len += qdf_str_nlen(str_value + meta->min, meta->max - meta->min + 1); 242 if (len > meta->max) { 243 cfg_err("%s=%s - Too long; Using default '%s'", 244 meta->name, str_value, store_value); 245 return; 246 } 247 248 qdf_str_lcopy(store_value, str_value, meta->max + 1); 249 } 250 251 static __attribute__((unused)) void cfg_mac_item_handler(struct cfg_value_store * store,const struct cfg_meta * meta,const char * str_value)252 cfg_mac_item_handler(struct cfg_value_store *store, 253 const struct cfg_meta *meta, 254 const char *str_value) 255 { 256 QDF_STATUS status; 257 struct qdf_mac_addr *store_value = cfg_value_ptr(store, meta); 258 259 status = qdf_mac_parse(str_value, store_value); 260 if (QDF_IS_STATUS_SUCCESS(status)) 261 return; 262 263 cfg_err("%s=%s - Invalid format (status %d); Using default " 264 QDF_MAC_ADDR_FMT, meta->name, str_value, status, 265 QDF_MAC_ADDR_REF(store_value->bytes)); 266 } 267 268 static __attribute__((unused)) void cfg_ipv4_item_handler(struct cfg_value_store * store,const struct cfg_meta * meta,const char * str_value)269 cfg_ipv4_item_handler(struct cfg_value_store *store, 270 const struct cfg_meta *meta, 271 const char *str_value) 272 { 273 QDF_STATUS status; 274 struct qdf_ipv4_addr *store_value = cfg_value_ptr(store, meta); 275 276 status = qdf_ipv4_parse(str_value, store_value); 277 if (QDF_IS_STATUS_SUCCESS(status)) 278 return; 279 280 cfg_err("%s=%s - Invalid format (status %d); Using default " 281 QDF_IPV4_ADDR_STR, meta->name, str_value, status, 282 QDF_IPV4_ADDR_ARRAY(store_value->bytes)); 283 } 284 285 static __attribute__((unused)) void cfg_ipv6_item_handler(struct cfg_value_store * store,const struct cfg_meta * meta,const char * str_value)286 cfg_ipv6_item_handler(struct cfg_value_store *store, 287 const struct cfg_meta *meta, 288 const char *str_value) 289 { 290 QDF_STATUS status; 291 struct qdf_ipv6_addr *store_value = cfg_value_ptr(store, meta); 292 293 status = qdf_ipv6_parse(str_value, store_value); 294 if (QDF_IS_STATUS_SUCCESS(status)) 295 return; 296 297 cfg_err("%s=%s - Invalid format (status %d); Using default " 298 QDF_IPV6_ADDR_STR, meta->name, str_value, status, 299 QDF_IPV6_ADDR_ARRAY(store_value->bytes)); 300 } 301 302 /* populate metadata lookup table */ 303 #undef __CFG_INI 304 #define __CFG_INI(_id, _mtype, _ctype, _name, _min, _max, _fallback, ...) \ 305 { \ 306 .name = _name, \ 307 .field_offset = qdf_offsetof(struct cfg_values, _id##_internal), \ 308 .cfg_type = CFG_ ##_mtype ## _ITEM, \ 309 .item_handler = cfg_ ## _mtype ## _item_handler, \ 310 .min = _min, \ 311 .max = _max, \ 312 .fallback = _fallback, \ 313 }, 314 315 #define cfg_INT_item_handler cfg_int_item_handler 316 #define cfg_UINT_item_handler cfg_uint_item_handler 317 #define cfg_BOOL_item_handler cfg_bool_item_handler 318 #define cfg_STRING_item_handler cfg_string_item_handler 319 #define cfg_MAC_item_handler cfg_mac_item_handler 320 #define cfg_IPV4_item_handler cfg_ipv4_item_handler 321 #define cfg_IPV6_item_handler cfg_ipv6_item_handler 322 323 static const struct cfg_meta cfg_meta_lookup_table[] = { 324 CFG_ALL 325 }; 326 327 /* default store initializer */ 328 cfg_store_set_defaults(struct cfg_value_store * store)329 static void cfg_store_set_defaults(struct cfg_value_store *store) 330 { 331 #undef __CFG_INI 332 #define __CFG_INI(id, mtype, ctype, name, min, max, fallback, desc, def...) \ 333 ctype id = def; 334 335 CFG_ALL 336 337 #undef __CFG_INI_STRING 338 #define __CFG_INI_STRING(id, mtype, ctype, name, min_len, max_len, ...) \ 339 qdf_str_lcopy((char *)&store->values.id##_internal, id, (max_len) + 1); 340 341 #undef __CFG_INI 342 #define __CFG_INI(id, mtype, ctype, name, min, max, fallback, desc, def...) \ 343 *(ctype *)&store->values.id##_internal = id; 344 345 CFG_ALL 346 } 347 cfg_lookup_meta(const char * name)348 static const struct cfg_meta *cfg_lookup_meta(const char *name) 349 { 350 int i; 351 char *param1; 352 char param[CFG_META_NAME_LENGTH_MAX]; 353 uint8_t ini_name[CFG_INI_LENGTH_MAX]; 354 355 QDF_BUG(name); 356 if (!name) 357 return NULL; 358 359 /* linear search for now; optimize in the future if needed */ 360 for (i = 0; i < QDF_ARRAY_SIZE(cfg_meta_lookup_table); i++) { 361 const struct cfg_meta *meta = &cfg_meta_lookup_table[i]; 362 363 qdf_mem_zero(ini_name, CFG_INI_LENGTH_MAX); 364 365 qdf_mem_zero(param, CFG_META_NAME_LENGTH_MAX); 366 if (strlen(meta->name) >= CFG_META_NAME_LENGTH_MAX) { 367 cfg_err("Invalid meta name %s", meta->name); 368 continue; 369 } 370 371 qdf_mem_copy(param, meta->name, strlen(meta->name)); 372 param[strlen(meta->name)] = '\0'; 373 param1 = param; 374 if (!sscanf(param1, "%s", ini_name)) { 375 cfg_err("Cannot get ini name %s", param1); 376 return NULL; 377 } 378 if (qdf_str_eq(name, ini_name)) 379 return meta; 380 381 param1 = strpbrk(param, " "); 382 while (param1) { 383 param1++; 384 if (!sscanf(param1, "%s ", ini_name)) { 385 cfg_err("Invalid ini name %s", meta->name); 386 return NULL; 387 } 388 if (qdf_str_eq(name, ini_name)) 389 return meta; 390 param1 = strpbrk(param1, " "); 391 } 392 } 393 return NULL; 394 } 395 396 static QDF_STATUS cfg_ini_item_handler(void * context,const char * key,const char * value)397 cfg_ini_item_handler(void *context, const char *key, const char *value) 398 { 399 struct cfg_value_store *store = context; 400 const struct cfg_meta *meta; 401 402 meta = cfg_lookup_meta(key); 403 if (!meta) { 404 /* TODO: promote to 'err' or 'warn' once legacy is ported */ 405 cfg_debug("Unknown config item '%s'", key); 406 return QDF_STATUS_SUCCESS; 407 } 408 409 QDF_BUG(meta->item_handler); 410 if (!meta->item_handler) 411 return QDF_STATUS_SUCCESS; 412 413 meta->item_handler(store, meta, value); 414 415 return QDF_STATUS_SUCCESS; 416 } 417 cfg_ini_section_handler(void * context,const char * name)418 static QDF_STATUS cfg_ini_section_handler(void *context, const char *name) 419 { 420 cfg_err("Unexpected section '%s'. Sections are not supported.", name); 421 422 return QDF_STATUS_SUCCESS; 423 } 424 425 #define cfg_assert_success(expr) \ 426 do { \ 427 QDF_STATUS __assert_status = (expr); \ 428 QDF_BUG(QDF_IS_STATUS_SUCCESS(__assert_status)); \ 429 } while (0) 430 431 static bool __cfg_is_init; 432 static struct cfg_value_store *__cfg_global_store; 433 static qdf_list_t __cfg_stores_list; 434 static qdf_spinlock_t __cfg_stores_lock; 435 436 struct cfg_psoc_ctx { 437 struct cfg_value_store *store; 438 }; 439 440 static QDF_STATUS cfg_store_alloc(const char * path,struct cfg_value_store ** out_store)441 cfg_store_alloc(const char *path, struct cfg_value_store **out_store) 442 { 443 QDF_STATUS status; 444 struct cfg_value_store *store; 445 446 cfg_enter(); 447 448 store = qdf_mem_common_alloc(sizeof(*store)); 449 if (!store) 450 return QDF_STATUS_E_NOMEM; 451 452 status = qdf_str_dup(&store->path, path); 453 if (QDF_IS_STATUS_ERROR(status)) 454 goto free_store; 455 456 status = qdf_atomic_init(&store->users); 457 if (QDF_IS_STATUS_ERROR(status)) 458 goto free_path; 459 qdf_atomic_inc(&store->users); 460 461 qdf_spin_lock_bh(&__cfg_stores_lock); 462 status = qdf_list_insert_back(&__cfg_stores_list, &store->node); 463 qdf_spin_unlock_bh(&__cfg_stores_lock); 464 if (QDF_IS_STATUS_ERROR(status)) 465 goto free_path; 466 467 *out_store = store; 468 469 return QDF_STATUS_SUCCESS; 470 471 free_path: 472 qdf_mem_free(store->path); 473 474 free_store: 475 qdf_mem_common_free(store); 476 477 return status; 478 } 479 cfg_store_free(struct cfg_value_store * store)480 static void cfg_store_free(struct cfg_value_store *store) 481 { 482 QDF_STATUS status; 483 484 cfg_enter(); 485 486 qdf_spin_lock_bh(&__cfg_stores_lock); 487 status = qdf_list_remove_node(&__cfg_stores_list, &store->node); 488 qdf_spin_unlock_bh(&__cfg_stores_lock); 489 if (QDF_IS_STATUS_ERROR(status)) 490 QDF_DEBUG_PANIC("Failed config store list removal; status:%d", 491 status); 492 493 qdf_mem_free(store->path); 494 qdf_mem_common_free(store); 495 } 496 497 static QDF_STATUS cfg_store_get(const char * path,struct cfg_value_store ** out_store)498 cfg_store_get(const char *path, struct cfg_value_store **out_store) 499 { 500 QDF_STATUS status; 501 qdf_list_node_t *node; 502 503 *out_store = NULL; 504 505 qdf_spin_lock_bh(&__cfg_stores_lock); 506 status = qdf_list_peek_front(&__cfg_stores_list, &node); 507 while (QDF_IS_STATUS_SUCCESS(status)) { 508 struct cfg_value_store *store = 509 qdf_container_of(node, struct cfg_value_store, node); 510 511 if (qdf_str_eq(path, store->path)) { 512 qdf_atomic_inc(&store->users); 513 *out_store = store; 514 break; 515 } 516 517 status = qdf_list_peek_next(&__cfg_stores_list, node, &node); 518 } 519 qdf_spin_unlock_bh(&__cfg_stores_lock); 520 521 return status; 522 } 523 cfg_store_put(struct cfg_value_store * store)524 static void cfg_store_put(struct cfg_value_store *store) 525 { 526 if (qdf_atomic_dec_and_test(&store->users)) 527 cfg_store_free(store); 528 } 529 cfg_psoc_get_ctx(struct wlan_objmgr_psoc * psoc)530 static struct cfg_psoc_ctx *cfg_psoc_get_ctx(struct wlan_objmgr_psoc *psoc) 531 { 532 struct cfg_psoc_ctx *psoc_ctx; 533 534 psoc_ctx = cfg_psoc_get_priv(psoc); 535 QDF_BUG(psoc_ctx); 536 537 return psoc_ctx; 538 } 539 cfg_psoc_get_values(struct wlan_objmgr_psoc * psoc)540 struct cfg_values *cfg_psoc_get_values(struct wlan_objmgr_psoc *psoc) 541 { 542 return &cfg_psoc_get_ctx(psoc)->store->values; 543 } 544 qdf_export_symbol(cfg_psoc_get_values); 545 546 static QDF_STATUS cfg_ini_parse_to_store(const char * path,struct cfg_value_store * store)547 cfg_ini_parse_to_store(const char *path, struct cfg_value_store *store) 548 { 549 QDF_STATUS status; 550 551 status = qdf_ini_parse(path, store, cfg_ini_item_handler, 552 cfg_ini_section_handler); 553 if (QDF_IS_STATUS_ERROR(status)) 554 cfg_err("Failed to parse *.ini file @ %s; status:%d", 555 path, status); 556 557 return status; 558 } 559 560 static QDF_STATUS cfg_ini_section_parse_to_store(const char * path,const char * section_name,struct cfg_value_store * store)561 cfg_ini_section_parse_to_store(const char *path, const char *section_name, 562 struct cfg_value_store *store) 563 { 564 QDF_STATUS status; 565 566 status = qdf_ini_section_parse(path, store, cfg_ini_item_handler, 567 section_name); 568 if (QDF_IS_STATUS_ERROR(status)) 569 cfg_err("Failed to parse *.ini file @ %s; status:%d", 570 path, status); 571 572 return status; 573 } 574 cfg_parse_to_psoc_store(struct wlan_objmgr_psoc * psoc,const char * path)575 QDF_STATUS cfg_parse_to_psoc_store(struct wlan_objmgr_psoc *psoc, 576 const char *path) 577 { 578 return cfg_ini_parse_to_store(path, cfg_psoc_get_ctx(psoc)->store); 579 } 580 581 qdf_export_symbol(cfg_parse_to_psoc_store); 582 cfg_section_parse_to_psoc_store(struct wlan_objmgr_psoc * psoc,const char * path,const char * section_name)583 QDF_STATUS cfg_section_parse_to_psoc_store(struct wlan_objmgr_psoc *psoc, 584 const char *path, 585 const char *section_name) 586 { 587 return cfg_ini_section_parse_to_store(path, section_name, 588 cfg_psoc_get_ctx(psoc)->store); 589 } 590 591 qdf_export_symbol(cfg_section_parse_to_psoc_store); 592 cfg_parse_to_global_store(const char * path)593 QDF_STATUS cfg_parse_to_global_store(const char *path) 594 { 595 if (!__cfg_global_store) { 596 cfg_err("Global INI store is not valid"); 597 return QDF_STATUS_E_NOMEM; 598 } 599 600 return cfg_ini_parse_to_store(path, __cfg_global_store); 601 } 602 603 qdf_export_symbol(cfg_parse_to_global_store); 604 605 static QDF_STATUS cfg_store_print(struct wlan_objmgr_psoc * psoc)606 cfg_store_print(struct wlan_objmgr_psoc *psoc) 607 { 608 struct cfg_value_store *store; 609 struct cfg_psoc_ctx *psoc_ctx; 610 void *offset; 611 uint32_t i; 612 613 cfg_enter(); 614 615 psoc_ctx = cfg_psoc_get_ctx(psoc); 616 if (!psoc_ctx) 617 return QDF_STATUS_E_FAILURE; 618 619 store = psoc_ctx->store; 620 if (!store) 621 return QDF_STATUS_E_FAILURE; 622 623 for (i = 0; i < QDF_ARRAY_SIZE(cfg_meta_lookup_table); i++) { 624 const struct cfg_meta *meta = &cfg_meta_lookup_table[i]; 625 626 offset = cfg_value_ptr(store, meta); 627 628 switch (meta->cfg_type) { 629 case CFG_INT_ITEM: 630 cfg_nofl_debug("%pK %s %d", offset, meta->name, 631 *((int32_t *)offset)); 632 break; 633 case CFG_UINT_ITEM: 634 cfg_nofl_debug("%pK %s %d", offset, meta->name, 635 *((uint32_t *)offset)); 636 break; 637 case CFG_BOOL_ITEM: 638 cfg_nofl_debug("%pK %s %d", offset, meta->name, 639 *((bool *)offset)); 640 break; 641 case CFG_STRING_ITEM: 642 cfg_nofl_debug("%pK %s %s", offset, meta->name, 643 (char *)offset); 644 break; 645 case CFG_MAC_ITEM: 646 cfg_nofl_debug("%pK %s " QDF_MAC_ADDR_FMT, 647 offset, meta->name, 648 QDF_MAC_ADDR_REF((uint8_t *)offset)); 649 break; 650 case CFG_IPV4_ITEM: 651 cfg_nofl_debug("%pK %s %pI4", 652 offset, meta->name, 653 offset); 654 break; 655 case CFG_IPV6_ITEM: 656 cfg_nofl_debug("%pK %s %pI6c", 657 offset, meta->name, 658 offset); 659 break; 660 default: 661 continue; 662 } 663 } 664 665 cfg_exit(); 666 return QDF_STATUS_SUCCESS; 667 } 668 669 static QDF_STATUS cfg_ini_config_print(struct wlan_objmgr_psoc * psoc,uint8_t * buf,ssize_t * plen,ssize_t buflen)670 cfg_ini_config_print(struct wlan_objmgr_psoc *psoc, uint8_t *buf, 671 ssize_t *plen, ssize_t buflen) 672 { 673 struct cfg_value_store *store; 674 struct cfg_psoc_ctx *psoc_ctx; 675 ssize_t len; 676 ssize_t total_len = buflen; 677 uint32_t i; 678 void *offset; 679 680 cfg_enter(); 681 682 psoc_ctx = cfg_psoc_get_ctx(psoc); 683 if (!psoc_ctx) 684 return QDF_STATUS_E_FAILURE; 685 686 store = psoc_ctx->store; 687 if (!store) 688 return QDF_STATUS_E_FAILURE; 689 690 for (i = 0; i < QDF_ARRAY_SIZE(cfg_meta_lookup_table); i++) { 691 const struct cfg_meta *meta = &cfg_meta_lookup_table[i]; 692 693 offset = cfg_value_ptr(store, meta); 694 695 switch (meta->cfg_type) { 696 case CFG_INT_ITEM: 697 len = qdf_scnprintf(buf, buflen, "%s %d\n", meta->name, 698 *((int32_t *)offset)); 699 buf += len; 700 buflen -= len; 701 break; 702 case CFG_UINT_ITEM: 703 len = qdf_scnprintf(buf, buflen, "%s %d\n", meta->name, 704 *((uint32_t *)offset)); 705 buf += len; 706 buflen -= len; 707 break; 708 case CFG_BOOL_ITEM: 709 len = qdf_scnprintf(buf, buflen, "%s %d\n", meta->name, 710 *((bool *)offset)); 711 buf += len; 712 buflen -= len; 713 break; 714 case CFG_STRING_ITEM: 715 len = qdf_scnprintf(buf, buflen, "%s %s\n", meta->name, 716 (char *)offset); 717 buf += len; 718 buflen -= len; 719 break; 720 case CFG_MAC_ITEM: 721 len = qdf_scnprintf(buf, buflen, 722 "%s " QDF_MAC_ADDR_FMT "\n", 723 meta->name, 724 QDF_MAC_ADDR_REF( 725 (uint8_t *)offset)); 726 buf += len; 727 buflen -= len; 728 break; 729 case CFG_IPV4_ITEM: 730 len = qdf_scnprintf(buf, buflen, "%s %pI4\n", 731 meta->name, 732 offset); 733 buf += len; 734 buflen -= len; 735 break; 736 case CFG_IPV6_ITEM: 737 len = qdf_scnprintf(buf, buflen, "%s %pI6c\n", 738 meta->name, 739 offset); 740 buf += len; 741 buflen -= len; 742 break; 743 default: 744 continue; 745 } 746 } 747 748 *plen = total_len - buflen; 749 cfg_exit(); 750 751 return QDF_STATUS_SUCCESS; 752 } 753 ucfg_cfg_store_print(struct wlan_objmgr_psoc * psoc)754 QDF_STATUS ucfg_cfg_store_print(struct wlan_objmgr_psoc *psoc) 755 { 756 return cfg_store_print(psoc); 757 } 758 759 qdf_export_symbol(ucfg_cfg_store_print); 760 ucfg_cfg_ini_config_print(struct wlan_objmgr_psoc * psoc,uint8_t * buf,ssize_t * plen,ssize_t buflen)761 QDF_STATUS ucfg_cfg_ini_config_print(struct wlan_objmgr_psoc *psoc, 762 uint8_t *buf, ssize_t *plen, 763 ssize_t buflen) 764 { 765 return cfg_ini_config_print(psoc, buf, plen, buflen); 766 } 767 768 static QDF_STATUS cfg_on_psoc_create(struct wlan_objmgr_psoc * psoc,void * context)769 cfg_on_psoc_create(struct wlan_objmgr_psoc *psoc, void *context) 770 { 771 QDF_STATUS status; 772 struct cfg_psoc_ctx *psoc_ctx; 773 774 cfg_enter(); 775 776 QDF_BUG(__cfg_global_store); 777 if (!__cfg_global_store) 778 return QDF_STATUS_E_FAILURE; 779 780 psoc_ctx = qdf_mem_malloc(sizeof(*psoc_ctx)); 781 if (!psoc_ctx) 782 return QDF_STATUS_E_NOMEM; 783 784 qdf_atomic_inc(&__cfg_global_store->users); 785 psoc_ctx->store = __cfg_global_store; 786 787 status = cfg_psoc_set_priv(psoc, psoc_ctx); 788 if (QDF_IS_STATUS_ERROR(status)) 789 goto put_store; 790 791 return QDF_STATUS_SUCCESS; 792 793 put_store: 794 cfg_store_put(__cfg_global_store); 795 qdf_mem_free(psoc_ctx); 796 797 return status; 798 } 799 800 static QDF_STATUS cfg_on_psoc_destroy(struct wlan_objmgr_psoc * psoc,void * context)801 cfg_on_psoc_destroy(struct wlan_objmgr_psoc *psoc, void *context) 802 { 803 QDF_STATUS status; 804 struct cfg_psoc_ctx *psoc_ctx; 805 806 cfg_enter(); 807 808 psoc_ctx = cfg_psoc_get_ctx(psoc); 809 status = cfg_psoc_unset_priv(psoc, psoc_ctx); 810 811 cfg_store_put(psoc_ctx->store); 812 qdf_mem_free(psoc_ctx); 813 814 return status; 815 } 816 cfg_dispatcher_init(void)817 QDF_STATUS cfg_dispatcher_init(void) 818 { 819 QDF_STATUS status; 820 821 cfg_enter(); 822 823 QDF_BUG(!__cfg_is_init); 824 if (__cfg_is_init) 825 return QDF_STATUS_E_INVAL; 826 827 qdf_list_create(&__cfg_stores_list, 0); 828 qdf_spinlock_create(&__cfg_stores_lock); 829 830 status = cfg_psoc_register_create(cfg_on_psoc_create); 831 if (QDF_IS_STATUS_ERROR(status)) 832 return status; 833 834 status = cfg_psoc_register_destroy(cfg_on_psoc_destroy); 835 if (QDF_IS_STATUS_ERROR(status)) 836 goto unreg_create; 837 838 __cfg_is_init = true; 839 840 return QDF_STATUS_SUCCESS; 841 842 unreg_create: 843 cfg_assert_success(cfg_psoc_unregister_create(cfg_on_psoc_create)); 844 845 return status; 846 } 847 cfg_dispatcher_deinit(void)848 QDF_STATUS cfg_dispatcher_deinit(void) 849 { 850 cfg_enter(); 851 852 QDF_BUG(__cfg_is_init); 853 if (!__cfg_is_init) 854 return QDF_STATUS_E_INVAL; 855 856 __cfg_is_init = false; 857 858 cfg_assert_success(cfg_psoc_unregister_create(cfg_on_psoc_create)); 859 cfg_assert_success(cfg_psoc_unregister_destroy(cfg_on_psoc_destroy)); 860 861 qdf_spin_lock_bh(&__cfg_stores_lock); 862 QDF_BUG(qdf_list_empty(&__cfg_stores_list)); 863 qdf_spin_unlock_bh(&__cfg_stores_lock); 864 865 qdf_spinlock_destroy(&__cfg_stores_lock); 866 qdf_list_destroy(&__cfg_stores_list); 867 868 return QDF_STATUS_SUCCESS; 869 } 870 cfg_parse(const char * path)871 QDF_STATUS cfg_parse(const char *path) 872 { 873 QDF_STATUS status; 874 struct cfg_value_store *store; 875 876 cfg_enter(); 877 878 if (!__cfg_global_store) { 879 status = cfg_store_alloc(path, &store); 880 if (QDF_IS_STATUS_ERROR(status)) 881 return status; 882 883 cfg_store_set_defaults(store); 884 status = cfg_ini_parse_to_store(path, store); 885 if (QDF_IS_STATUS_ERROR(status)) 886 goto free_store; 887 __cfg_global_store = store; 888 889 return QDF_STATUS_SUCCESS; 890 } 891 store = __cfg_global_store; 892 status = cfg_ini_parse_to_store(path, store); 893 return status; 894 895 free_store: 896 cfg_store_free(store); 897 898 return status; 899 } 900 cfg_valid_ini_check(const char * path)901 bool cfg_valid_ini_check(const char *path) 902 { 903 cfg_enter(); 904 905 return qdf_valid_ini_check(path); 906 } 907 cfg_release(void)908 void cfg_release(void) 909 { 910 cfg_enter(); 911 912 QDF_BUG(__cfg_global_store); 913 if (!__cfg_global_store) 914 return; 915 916 cfg_store_put(__cfg_global_store); 917 __cfg_global_store = NULL; 918 } 919 cfg_psoc_parse(struct wlan_objmgr_psoc * psoc,const char * path)920 QDF_STATUS cfg_psoc_parse(struct wlan_objmgr_psoc *psoc, const char *path) 921 { 922 QDF_STATUS status; 923 struct cfg_value_store *store; 924 struct cfg_psoc_ctx *psoc_ctx; 925 926 cfg_enter(); 927 928 QDF_BUG(__cfg_global_store); 929 if (!__cfg_global_store) 930 return QDF_STATUS_E_INVAL; 931 932 QDF_BUG(__cfg_is_init); 933 if (!__cfg_is_init) 934 return QDF_STATUS_E_INVAL; 935 936 QDF_BUG(psoc); 937 if (!psoc) 938 return QDF_STATUS_E_INVAL; 939 940 QDF_BUG(path); 941 if (!path) 942 return QDF_STATUS_E_INVAL; 943 944 psoc_ctx = cfg_psoc_get_ctx(psoc); 945 946 QDF_BUG(psoc_ctx->store == __cfg_global_store); 947 if (psoc_ctx->store != __cfg_global_store) 948 return QDF_STATUS_SUCCESS; 949 950 /* check if @path has been parsed before */ 951 status = cfg_store_get(path, &store); 952 if (QDF_IS_STATUS_ERROR(status)) { 953 status = cfg_store_alloc(path, &store); 954 if (QDF_IS_STATUS_ERROR(status)) 955 return status; 956 957 /* inherit global configuration */ 958 qdf_mem_copy(&store->values, &__cfg_global_store->values, 959 sizeof(store->values)); 960 961 status = cfg_ini_parse_to_store(path, store); 962 if (QDF_IS_STATUS_ERROR(status)) 963 goto put_store; 964 } 965 966 psoc_ctx->store = store; 967 cfg_store_put(__cfg_global_store); 968 969 return QDF_STATUS_SUCCESS; 970 971 put_store: 972 cfg_store_put(store); 973 974 return status; 975 } 976 977 qdf_export_symbol(cfg_psoc_parse); 978