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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 break; 701 case CFG_UINT_ITEM: 702 len = qdf_scnprintf(buf, buflen, "%s %d\n", meta->name, 703 *((uint32_t *)offset)); 704 buf += len; 705 buflen -= len; 706 break; 707 case CFG_BOOL_ITEM: 708 len = qdf_scnprintf(buf, buflen, "%s %d\n", meta->name, 709 *((bool *)offset)); 710 buf += len; 711 buflen -= len; 712 break; 713 case CFG_STRING_ITEM: 714 len = qdf_scnprintf(buf, buflen, "%s %s\n", meta->name, 715 (char *)offset); 716 buf += len; 717 buflen -= len; 718 break; 719 case CFG_MAC_ITEM: 720 len = qdf_scnprintf(buf, buflen, 721 "%s " QDF_MAC_ADDR_FMT "\n", 722 meta->name, 723 QDF_MAC_ADDR_REF( 724 (uint8_t *)offset)); 725 buf += len; 726 buflen -= len; 727 break; 728 case CFG_IPV4_ITEM: 729 len = qdf_scnprintf(buf, buflen, "%s %pI4\n", 730 meta->name, 731 offset); 732 buf += len; 733 buflen -= len; 734 break; 735 case CFG_IPV6_ITEM: 736 len = qdf_scnprintf(buf, buflen, "%s %pI6c\n", 737 meta->name, 738 offset); 739 buf += len; 740 buflen -= len; 741 break; 742 default: 743 continue; 744 } 745 } 746 747 *plen = total_len - buflen; 748 cfg_exit(); 749 750 return QDF_STATUS_SUCCESS; 751 } 752 753 QDF_STATUS ucfg_cfg_store_print(struct wlan_objmgr_psoc *psoc) 754 { 755 return cfg_store_print(psoc); 756 } 757 758 qdf_export_symbol(ucfg_cfg_store_print); 759 760 QDF_STATUS ucfg_cfg_ini_config_print(struct wlan_objmgr_psoc *psoc, 761 uint8_t *buf, ssize_t *plen, 762 ssize_t buflen) 763 { 764 return cfg_ini_config_print(psoc, buf, plen, buflen); 765 } 766 767 static QDF_STATUS 768 cfg_on_psoc_create(struct wlan_objmgr_psoc *psoc, void *context) 769 { 770 QDF_STATUS status; 771 struct cfg_psoc_ctx *psoc_ctx; 772 773 cfg_enter(); 774 775 QDF_BUG(__cfg_global_store); 776 if (!__cfg_global_store) 777 return QDF_STATUS_E_FAILURE; 778 779 psoc_ctx = qdf_mem_malloc(sizeof(*psoc_ctx)); 780 if (!psoc_ctx) 781 return QDF_STATUS_E_NOMEM; 782 783 qdf_atomic_inc(&__cfg_global_store->users); 784 psoc_ctx->store = __cfg_global_store; 785 786 status = cfg_psoc_set_priv(psoc, psoc_ctx); 787 if (QDF_IS_STATUS_ERROR(status)) 788 goto put_store; 789 790 return QDF_STATUS_SUCCESS; 791 792 put_store: 793 cfg_store_put(__cfg_global_store); 794 qdf_mem_free(psoc_ctx); 795 796 return status; 797 } 798 799 static QDF_STATUS 800 cfg_on_psoc_destroy(struct wlan_objmgr_psoc *psoc, void *context) 801 { 802 QDF_STATUS status; 803 struct cfg_psoc_ctx *psoc_ctx; 804 805 cfg_enter(); 806 807 psoc_ctx = cfg_psoc_get_ctx(psoc); 808 status = cfg_psoc_unset_priv(psoc, psoc_ctx); 809 810 cfg_store_put(psoc_ctx->store); 811 qdf_mem_free(psoc_ctx); 812 813 return status; 814 } 815 816 QDF_STATUS cfg_dispatcher_init(void) 817 { 818 QDF_STATUS status; 819 820 cfg_enter(); 821 822 QDF_BUG(!__cfg_is_init); 823 if (__cfg_is_init) 824 return QDF_STATUS_E_INVAL; 825 826 qdf_list_create(&__cfg_stores_list, 0); 827 qdf_spinlock_create(&__cfg_stores_lock); 828 829 status = cfg_psoc_register_create(cfg_on_psoc_create); 830 if (QDF_IS_STATUS_ERROR(status)) 831 return status; 832 833 status = cfg_psoc_register_destroy(cfg_on_psoc_destroy); 834 if (QDF_IS_STATUS_ERROR(status)) 835 goto unreg_create; 836 837 __cfg_is_init = true; 838 839 return QDF_STATUS_SUCCESS; 840 841 unreg_create: 842 cfg_assert_success(cfg_psoc_unregister_create(cfg_on_psoc_create)); 843 844 return status; 845 } 846 847 QDF_STATUS cfg_dispatcher_deinit(void) 848 { 849 cfg_enter(); 850 851 QDF_BUG(__cfg_is_init); 852 if (!__cfg_is_init) 853 return QDF_STATUS_E_INVAL; 854 855 __cfg_is_init = false; 856 857 cfg_assert_success(cfg_psoc_unregister_create(cfg_on_psoc_create)); 858 cfg_assert_success(cfg_psoc_unregister_destroy(cfg_on_psoc_destroy)); 859 860 qdf_spin_lock_bh(&__cfg_stores_lock); 861 QDF_BUG(qdf_list_empty(&__cfg_stores_list)); 862 qdf_spin_unlock_bh(&__cfg_stores_lock); 863 864 qdf_spinlock_destroy(&__cfg_stores_lock); 865 qdf_list_destroy(&__cfg_stores_list); 866 867 return QDF_STATUS_SUCCESS; 868 } 869 870 QDF_STATUS cfg_parse(const char *path) 871 { 872 QDF_STATUS status; 873 struct cfg_value_store *store; 874 875 cfg_enter(); 876 877 if (!__cfg_global_store) { 878 status = cfg_store_alloc(path, &store); 879 if (QDF_IS_STATUS_ERROR(status)) 880 return status; 881 882 cfg_store_set_defaults(store); 883 status = cfg_ini_parse_to_store(path, store); 884 if (QDF_IS_STATUS_ERROR(status)) 885 goto free_store; 886 __cfg_global_store = store; 887 888 return QDF_STATUS_SUCCESS; 889 } 890 store = __cfg_global_store; 891 status = cfg_ini_parse_to_store(path, store); 892 return status; 893 894 free_store: 895 cfg_store_free(store); 896 897 return status; 898 } 899 900 bool cfg_valid_ini_check(const char *path) 901 { 902 cfg_enter(); 903 904 return qdf_valid_ini_check(path); 905 } 906 907 void cfg_release(void) 908 { 909 cfg_enter(); 910 911 QDF_BUG(__cfg_global_store); 912 if (!__cfg_global_store) 913 return; 914 915 cfg_store_put(__cfg_global_store); 916 __cfg_global_store = NULL; 917 } 918 919 QDF_STATUS cfg_psoc_parse(struct wlan_objmgr_psoc *psoc, const char *path) 920 { 921 QDF_STATUS status; 922 struct cfg_value_store *store; 923 struct cfg_psoc_ctx *psoc_ctx; 924 925 cfg_enter(); 926 927 QDF_BUG(__cfg_global_store); 928 if (!__cfg_global_store) 929 return QDF_STATUS_E_INVAL; 930 931 QDF_BUG(__cfg_is_init); 932 if (!__cfg_is_init) 933 return QDF_STATUS_E_INVAL; 934 935 QDF_BUG(psoc); 936 if (!psoc) 937 return QDF_STATUS_E_INVAL; 938 939 QDF_BUG(path); 940 if (!path) 941 return QDF_STATUS_E_INVAL; 942 943 psoc_ctx = cfg_psoc_get_ctx(psoc); 944 945 QDF_BUG(psoc_ctx->store == __cfg_global_store); 946 if (psoc_ctx->store != __cfg_global_store) 947 return QDF_STATUS_SUCCESS; 948 949 /* check if @path has been parsed before */ 950 status = cfg_store_get(path, &store); 951 if (QDF_IS_STATUS_ERROR(status)) { 952 status = cfg_store_alloc(path, &store); 953 if (QDF_IS_STATUS_ERROR(status)) 954 return status; 955 956 /* inherit global configuration */ 957 qdf_mem_copy(&store->values, &__cfg_global_store->values, 958 sizeof(store->values)); 959 960 status = cfg_ini_parse_to_store(path, store); 961 if (QDF_IS_STATUS_ERROR(status)) 962 goto put_store; 963 } 964 965 psoc_ctx->store = store; 966 cfg_store_put(__cfg_global_store); 967 968 return QDF_STATUS_SUCCESS; 969 970 put_store: 971 cfg_store_put(store); 972 973 return status; 974 } 975 976 qdf_export_symbol(cfg_psoc_parse); 977