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