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