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