xref: /wlan-driver/qca-wifi-host-cmn/qdf/src/qdf_parse.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name #include "qdf_file.h"
21*5113495bSYour Name #include "qdf_module.h"
22*5113495bSYour Name #include "qdf_parse.h"
23*5113495bSYour Name #include "qdf_status.h"
24*5113495bSYour Name #include "qdf_str.h"
25*5113495bSYour Name #include "qdf_trace.h"
26*5113495bSYour Name #include "qdf_types.h"
27*5113495bSYour Name 
28*5113495bSYour Name #ifdef WLAN_USE_CONFIG_PARAMS
29*5113495bSYour Name #define QDF_SECTION_FOUND break
30*5113495bSYour Name #else
31*5113495bSYour Name #define QDF_SECTION_FOUND continue
32*5113495bSYour Name #endif
33*5113495bSYour Name 
qdf_ini_read_values(char ** main_cursor,char ** read_key,char ** read_value,bool * section_item)34*5113495bSYour Name static QDF_STATUS qdf_ini_read_values(char **main_cursor,
35*5113495bSYour Name 				      char **read_key, char **read_value,
36*5113495bSYour Name 				      bool *section_item)
37*5113495bSYour Name {
38*5113495bSYour Name 	char *cursor = *main_cursor;
39*5113495bSYour Name 
40*5113495bSYour Name 	/* foreach line */
41*5113495bSYour Name 	while (*cursor != '\0') {
42*5113495bSYour Name 		char *key = cursor;
43*5113495bSYour Name 		char *value = NULL;
44*5113495bSYour Name 		bool comment = false;
45*5113495bSYour Name 		bool eol = false;
46*5113495bSYour Name 
47*5113495bSYour Name 		/*
48*5113495bSYour Name 		 * Look for the end of the line, while noting any
49*5113495bSYour Name 		 * value ('=') or comment ('#') indicators
50*5113495bSYour Name 		 */
51*5113495bSYour Name 		while (!eol) {
52*5113495bSYour Name 			switch (*cursor) {
53*5113495bSYour Name 			case '\r':
54*5113495bSYour Name 			case '\n':
55*5113495bSYour Name 				*cursor = '\0';
56*5113495bSYour Name 				cursor++;
57*5113495bSYour Name 				fallthrough;
58*5113495bSYour Name 			case '\0':
59*5113495bSYour Name 				eol = true;
60*5113495bSYour Name 				break;
61*5113495bSYour Name 
62*5113495bSYour Name 			case '=':
63*5113495bSYour Name 				/*
64*5113495bSYour Name 				 * The first '=' is the value indicator.
65*5113495bSYour Name 				 * Subsequent '=' are valid value characters.
66*5113495bSYour Name 				 */
67*5113495bSYour Name 				if (!value && !comment) {
68*5113495bSYour Name 					value = cursor + 1;
69*5113495bSYour Name 					*cursor = '\0';
70*5113495bSYour Name 				}
71*5113495bSYour Name 
72*5113495bSYour Name 				cursor++;
73*5113495bSYour Name 				break;
74*5113495bSYour Name 
75*5113495bSYour Name 			case '#':
76*5113495bSYour Name 				/*
77*5113495bSYour Name 				 * We don't process comments, so we can null-
78*5113495bSYour Name 				 * terminate unconditionally here (unlike '=').
79*5113495bSYour Name 				 */
80*5113495bSYour Name 				comment = true;
81*5113495bSYour Name 				*cursor = '\0';
82*5113495bSYour Name 				fallthrough;
83*5113495bSYour Name 			default:
84*5113495bSYour Name 				cursor++;
85*5113495bSYour Name 				break;
86*5113495bSYour Name 			}
87*5113495bSYour Name 		}
88*5113495bSYour Name 
89*5113495bSYour Name 		key = qdf_str_trim(key);
90*5113495bSYour Name 		/*
91*5113495bSYour Name 		 * Ignoring comments, a valid ini line contains one of:
92*5113495bSYour Name 		 *	1) some 'key=value' config item
93*5113495bSYour Name 		 *	2) section header
94*5113495bSYour Name 		 *	3) a line containing whitespace
95*5113495bSYour Name 		 */
96*5113495bSYour Name 		if (value) {
97*5113495bSYour Name 			*read_key = key;
98*5113495bSYour Name 			*read_value = value;
99*5113495bSYour Name 			*section_item = 0;
100*5113495bSYour Name 			*main_cursor = cursor;
101*5113495bSYour Name 			return QDF_STATUS_SUCCESS;
102*5113495bSYour Name 		} else if (key[0] == '[') {
103*5113495bSYour Name 			qdf_size_t len = qdf_str_len(key);
104*5113495bSYour Name 
105*5113495bSYour Name 			if (key[len - 1] != ']') {
106*5113495bSYour Name 				qdf_err("Invalid *.ini syntax '%s'", key);
107*5113495bSYour Name 				return QDF_STATUS_E_INVAL;
108*5113495bSYour Name 			} else {
109*5113495bSYour Name 				key[len - 1] = '\0';
110*5113495bSYour Name 				*read_key = key + 1;
111*5113495bSYour Name 				*section_item = 1;
112*5113495bSYour Name 				*main_cursor = cursor;
113*5113495bSYour Name 				return QDF_STATUS_SUCCESS;
114*5113495bSYour Name 			}
115*5113495bSYour Name 		} else if (key[0] != '\0') {
116*5113495bSYour Name 			if (!__qdf_str_cmp(key, "END")) {
117*5113495bSYour Name 				key[3] = '\0';
118*5113495bSYour Name 				*section_item = 0;
119*5113495bSYour Name 				*main_cursor = cursor;
120*5113495bSYour Name 				*read_key = key;
121*5113495bSYour Name 				return QDF_STATUS_SUCCESS;
122*5113495bSYour Name 			}
123*5113495bSYour Name 			qdf_err("Invalid *.ini syntax '%s'", key);
124*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
125*5113495bSYour Name 		}
126*5113495bSYour Name 
127*5113495bSYour Name 		/* skip remaining EoL characters */
128*5113495bSYour Name 		while (*cursor == '\n' || *cursor == '\r')
129*5113495bSYour Name 			cursor++;
130*5113495bSYour Name 	}
131*5113495bSYour Name 
132*5113495bSYour Name 	return QDF_STATUS_E_INVAL;
133*5113495bSYour Name }
134*5113495bSYour Name 
qdf_ini_parse(const char * ini_path,void * context,qdf_ini_item_cb item_cb,qdf_ini_section_cb section_cb)135*5113495bSYour Name QDF_STATUS qdf_ini_parse(const char *ini_path, void *context,
136*5113495bSYour Name 			 qdf_ini_item_cb item_cb, qdf_ini_section_cb section_cb)
137*5113495bSYour Name {
138*5113495bSYour Name 	QDF_STATUS status;
139*5113495bSYour Name 	char *read_key;
140*5113495bSYour Name 	char *read_value;
141*5113495bSYour Name 	bool section_item;
142*5113495bSYour Name 	int ini_read_count = 0;
143*5113495bSYour Name 	char *fbuf;
144*5113495bSYour Name 	char *cursor;
145*5113495bSYour Name 
146*5113495bSYour Name 	if (qdf_str_eq(QDF_WIFI_MODULE_PARAMS_FILE, ini_path))
147*5113495bSYour Name 		status = qdf_module_param_file_read(ini_path, &fbuf);
148*5113495bSYour Name 	else
149*5113495bSYour Name 		status = qdf_file_read(ini_path, &fbuf);
150*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
151*5113495bSYour Name 		qdf_err("Failed to read *.ini file @ %s", ini_path);
152*5113495bSYour Name 		return status;
153*5113495bSYour Name 	}
154*5113495bSYour Name 
155*5113495bSYour Name 	/* foreach line */
156*5113495bSYour Name 	cursor = fbuf;
157*5113495bSYour Name 
158*5113495bSYour Name 	while (qdf_ini_read_values(&cursor, &read_key, &read_value,
159*5113495bSYour Name 				   &section_item) == QDF_STATUS_SUCCESS) {
160*5113495bSYour Name 		if (!__qdf_str_cmp(read_key, "END"))
161*5113495bSYour Name 			break;
162*5113495bSYour Name 
163*5113495bSYour Name 		if (!section_item) {
164*5113495bSYour Name 			status = item_cb(context, read_key, read_value);
165*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status))
166*5113495bSYour Name 				break;
167*5113495bSYour Name 			else
168*5113495bSYour Name 				ini_read_count++;
169*5113495bSYour Name 		} else  {
170*5113495bSYour Name 			qdf_debug("Section started in global file");
171*5113495bSYour Name 		/* Currently AP Platforms supports and uses Sections,
172*5113495bSYour Name 		 * hence break the loop, sections will be parsed separately,
173*5113495bSYour Name 		 * in case of non AP platforms, sections are used as
174*5113495bSYour Name 		 * logical separators hence continue reading the values.
175*5113495bSYour Name 		 */
176*5113495bSYour Name 			QDF_SECTION_FOUND;
177*5113495bSYour Name 		}
178*5113495bSYour Name 	}
179*5113495bSYour Name 
180*5113495bSYour Name 	qdf_info("INI values read: %d", ini_read_count);
181*5113495bSYour Name 	if (ini_read_count != 0) {
182*5113495bSYour Name 		qdf_info("INI file parse successful");
183*5113495bSYour Name 		status = QDF_STATUS_SUCCESS;
184*5113495bSYour Name 	} else {
185*5113495bSYour Name 		qdf_info("INI file parse fail: invalid file format");
186*5113495bSYour Name 		status = QDF_STATUS_E_INVAL;
187*5113495bSYour Name 	}
188*5113495bSYour Name 
189*5113495bSYour Name 	if (qdf_str_eq(QDF_WIFI_MODULE_PARAMS_FILE, ini_path))
190*5113495bSYour Name 		qdf_module_param_file_free(fbuf);
191*5113495bSYour Name 	else
192*5113495bSYour Name 		qdf_file_buf_free(fbuf);
193*5113495bSYour Name 
194*5113495bSYour Name 	return status;
195*5113495bSYour Name }
196*5113495bSYour Name 
197*5113495bSYour Name qdf_export_symbol(qdf_ini_parse);
198*5113495bSYour Name 
qdf_ini_section_parse(const char * ini_path,void * context,qdf_ini_item_cb item_cb,const char * section_name)199*5113495bSYour Name QDF_STATUS qdf_ini_section_parse(const char *ini_path, void *context,
200*5113495bSYour Name 				 qdf_ini_item_cb item_cb,
201*5113495bSYour Name 				 const char *section_name)
202*5113495bSYour Name {
203*5113495bSYour Name 	QDF_STATUS status;
204*5113495bSYour Name 	char *read_key;
205*5113495bSYour Name 	char *read_value;
206*5113495bSYour Name 	bool section_item;
207*5113495bSYour Name 	bool section_found = 0;
208*5113495bSYour Name 	bool section_complete = 0;
209*5113495bSYour Name 	int ini_read_count = 0;
210*5113495bSYour Name 	char *fbuf;
211*5113495bSYour Name 	char *cursor;
212*5113495bSYour Name 
213*5113495bSYour Name 	if (qdf_str_eq(QDF_WIFI_MODULE_PARAMS_FILE, ini_path))
214*5113495bSYour Name 		status = qdf_module_param_file_read(ini_path, &fbuf);
215*5113495bSYour Name 	else
216*5113495bSYour Name 		status = qdf_file_read(ini_path, &fbuf);
217*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
218*5113495bSYour Name 		qdf_err("Failed to read *.ini file @ %s", ini_path);
219*5113495bSYour Name 		return status;
220*5113495bSYour Name 	}
221*5113495bSYour Name 
222*5113495bSYour Name 	/* foreach line */
223*5113495bSYour Name 	cursor = fbuf;
224*5113495bSYour Name 
225*5113495bSYour Name 	while (qdf_ini_read_values(&cursor, &read_key, &read_value,
226*5113495bSYour Name 				   &section_item) == QDF_STATUS_SUCCESS) {
227*5113495bSYour Name 		if (!__qdf_str_cmp(read_key, "END"))
228*5113495bSYour Name 			break;
229*5113495bSYour Name 
230*5113495bSYour Name 		if (section_item) {
231*5113495bSYour Name 			if (qdf_str_cmp(read_key, section_name) == 0) {
232*5113495bSYour Name 				section_found = 1;
233*5113495bSYour Name 				section_complete = 0;
234*5113495bSYour Name 			} else {
235*5113495bSYour Name 				if (section_found == 1)
236*5113495bSYour Name 					section_complete = 1;
237*5113495bSYour Name 				section_found = 0;
238*5113495bSYour Name 			}
239*5113495bSYour Name 		} else if (section_found) {
240*5113495bSYour Name 			status = item_cb(context, read_key, read_value);
241*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status))
242*5113495bSYour Name 				break;
243*5113495bSYour Name 			else
244*5113495bSYour Name 				ini_read_count++;
245*5113495bSYour Name 		} else if (section_complete) {
246*5113495bSYour Name 			break;
247*5113495bSYour Name 		}
248*5113495bSYour Name 	}
249*5113495bSYour Name 
250*5113495bSYour Name 	qdf_info("INI values parse successful read: %d from section %s",
251*5113495bSYour Name 		 ini_read_count, section_name);
252*5113495bSYour Name 
253*5113495bSYour Name 	if (ini_read_count != 0) {
254*5113495bSYour Name 		status = QDF_STATUS_SUCCESS;
255*5113495bSYour Name 	} else {
256*5113495bSYour Name 		qdf_debug("INI file parse fail: Section not found %s",
257*5113495bSYour Name 			  section_name);
258*5113495bSYour Name 		status = QDF_STATUS_SUCCESS;
259*5113495bSYour Name 	}
260*5113495bSYour Name 
261*5113495bSYour Name 	if (qdf_str_eq(QDF_WIFI_MODULE_PARAMS_FILE, ini_path))
262*5113495bSYour Name 		qdf_module_param_file_free(fbuf);
263*5113495bSYour Name 	else
264*5113495bSYour Name 		qdf_file_buf_free(fbuf);
265*5113495bSYour Name 
266*5113495bSYour Name 	return status;
267*5113495bSYour Name }
268*5113495bSYour Name 
269*5113495bSYour Name qdf_export_symbol(qdf_ini_section_parse);
270*5113495bSYour Name 
271*5113495bSYour Name /**
272*5113495bSYour Name  * qdf_validate_key() - Check if ini key is valid
273*5113495bSYour Name  * @key: Pointer to key
274*5113495bSYour Name  *
275*5113495bSYour Name  * Return: Return SUCCESS if key is valid else return INVALID
276*5113495bSYour Name  */
qdf_validate_key(char * key)277*5113495bSYour Name static QDF_STATUS qdf_validate_key(char *key)
278*5113495bSYour Name {
279*5113495bSYour Name 	int i;
280*5113495bSYour Name 
281*5113495bSYour Name 	for (i = 0; key[i] != '\0' ; i++) {
282*5113495bSYour Name 		if ((key[i] >= 'a' && key[i] <= 'z') ||
283*5113495bSYour Name 		    (key[i] >= 'A' && key[i] <= 'Z') ||
284*5113495bSYour Name 		    (key[i] >= '0' && key[i] <= '9') ||
285*5113495bSYour Name 		    (key[i] == '_'))
286*5113495bSYour Name 			continue;
287*5113495bSYour Name 		else
288*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
289*5113495bSYour Name 	}
290*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
291*5113495bSYour Name }
292*5113495bSYour Name 
293*5113495bSYour Name /**
294*5113495bSYour Name  * qdf_validate_value() - Validate ini value
295*5113495bSYour Name  * @value: Pointer to ini value
296*5113495bSYour Name  *
297*5113495bSYour Name  * Return: Return SUCCESS if value is valid else return INVALID
298*5113495bSYour Name  */
qdf_validate_value(char * value)299*5113495bSYour Name static QDF_STATUS qdf_validate_value(char *value)
300*5113495bSYour Name {
301*5113495bSYour Name 	int i;
302*5113495bSYour Name 
303*5113495bSYour Name 	for (i = 0; value[i] != '\0'; i++) {
304*5113495bSYour Name 		if ((value[i] >= '0' && value[i] <= '9') ||
305*5113495bSYour Name 		    (value[i] >= 'A' && value[i] <= 'Z') ||
306*5113495bSYour Name 		    (value[i] >= 'a' && value[i] <= 'z') ||
307*5113495bSYour Name 		    value[i] == ',' || value[i] == ':' ||
308*5113495bSYour Name 		    value[i] == '-' || value[i] == '+')
309*5113495bSYour Name 			continue;
310*5113495bSYour Name 		else
311*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
312*5113495bSYour Name 	}
313*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
314*5113495bSYour Name }
315*5113495bSYour Name 
316*5113495bSYour Name /**
317*5113495bSYour Name  * qdf_check_ini_validity() - Check if inis are valid
318*5113495bSYour Name  * @main_cursor: Pointer to main cursor
319*5113495bSYour Name  *
320*5113495bSYour Name  * Return: Return true if all inis are valid else false
321*5113495bSYour Name  */
qdf_check_ini_validity(char ** main_cursor)322*5113495bSYour Name static bool qdf_check_ini_validity(char **main_cursor)
323*5113495bSYour Name {
324*5113495bSYour Name 	char *cursor = *main_cursor;
325*5113495bSYour Name 	char *read_key;
326*5113495bSYour Name 	char *read_value;
327*5113495bSYour Name 	bool section_item;
328*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
329*5113495bSYour Name 
330*5113495bSYour Name 	while (*cursor != '\0') {
331*5113495bSYour Name 		unsigned char *val = (unsigned char *)cursor;
332*5113495bSYour Name 
333*5113495bSYour Name 		switch (*cursor) {
334*5113495bSYour Name 		case '\r':
335*5113495bSYour Name 		case '\n':
336*5113495bSYour Name 			cursor++;
337*5113495bSYour Name 			break;
338*5113495bSYour Name 		case '\0':
339*5113495bSYour Name 			break;
340*5113495bSYour Name 		case '=':
341*5113495bSYour Name 		case '#':
342*5113495bSYour Name 		case ']':
343*5113495bSYour Name 		case '[':
344*5113495bSYour Name 		case '_':
345*5113495bSYour Name 		case '-':
346*5113495bSYour Name 		case ' ':
347*5113495bSYour Name 		case ':':
348*5113495bSYour Name 		case ',':
349*5113495bSYour Name 			cursor++;
350*5113495bSYour Name 			break;
351*5113495bSYour Name 
352*5113495bSYour Name 		default:
353*5113495bSYour Name 			if (!isalnum(*val)) {
354*5113495bSYour Name 				qdf_err("Found invalid character %c", *cursor);
355*5113495bSYour Name 				return false;
356*5113495bSYour Name 			}
357*5113495bSYour Name 			cursor++;
358*5113495bSYour Name 			break;
359*5113495bSYour Name 		}
360*5113495bSYour Name 	}
361*5113495bSYour Name 
362*5113495bSYour Name 	cursor = *main_cursor;
363*5113495bSYour Name 	while ((status = qdf_ini_read_values(main_cursor, &read_key,
364*5113495bSYour Name 			&read_value, &section_item)) == QDF_STATUS_SUCCESS) {
365*5113495bSYour Name 		if (!section_item) {
366*5113495bSYour Name 			if (!__qdf_str_cmp(read_key, "END"))
367*5113495bSYour Name 				return true;
368*5113495bSYour Name 			status = qdf_validate_key(read_key);
369*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status)) {
370*5113495bSYour Name 				status = QDF_STATUS_E_INVAL;
371*5113495bSYour Name 				goto out;
372*5113495bSYour Name 			}
373*5113495bSYour Name 			status = qdf_validate_value(read_value);
374*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status)) {
375*5113495bSYour Name 				status = QDF_STATUS_E_INVAL;
376*5113495bSYour Name 				goto out;
377*5113495bSYour Name 			}
378*5113495bSYour Name 		}
379*5113495bSYour Name 	}
380*5113495bSYour Name 
381*5113495bSYour Name out:
382*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
383*5113495bSYour Name 		return false;
384*5113495bSYour Name 	return true;
385*5113495bSYour Name }
386*5113495bSYour Name 
qdf_valid_ini_check(const char * ini_path)387*5113495bSYour Name bool qdf_valid_ini_check(const char  *ini_path)
388*5113495bSYour Name {
389*5113495bSYour Name 	QDF_STATUS status;
390*5113495bSYour Name 	char *fbuf;
391*5113495bSYour Name 	char *cursor;
392*5113495bSYour Name 	bool is_valid = false;
393*5113495bSYour Name 
394*5113495bSYour Name 	if (qdf_str_eq(QDF_WIFI_MODULE_PARAMS_FILE, ini_path))
395*5113495bSYour Name 		status = qdf_module_param_file_read(ini_path, &fbuf);
396*5113495bSYour Name 	else
397*5113495bSYour Name 		status = qdf_file_read(ini_path, &fbuf);
398*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
399*5113495bSYour Name 		qdf_err("Failed to read *.ini file @ %s", ini_path);
400*5113495bSYour Name 		return false;
401*5113495bSYour Name 	}
402*5113495bSYour Name 
403*5113495bSYour Name 	/* foreach line */
404*5113495bSYour Name 	cursor = fbuf;
405*5113495bSYour Name 
406*5113495bSYour Name 	is_valid = qdf_check_ini_validity(&cursor);
407*5113495bSYour Name 
408*5113495bSYour Name 	if (qdf_str_eq(QDF_WIFI_MODULE_PARAMS_FILE, ini_path))
409*5113495bSYour Name 		qdf_module_param_file_free(fbuf);
410*5113495bSYour Name 	else
411*5113495bSYour Name 		qdf_file_buf_free(fbuf);
412*5113495bSYour Name 
413*5113495bSYour Name 	return is_valid;
414*5113495bSYour Name }
415*5113495bSYour Name 
416*5113495bSYour Name qdf_export_symbol(qdf_valid_ini_check);
417