xref: /wlan-dirver/qca-wifi-host-cmn/cfg/src/cfg.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
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