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