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