xref: /wlan-dirver/qca-wifi-host-cmn/qdf/src/qdf_types.c (revision 302a1d9701784af5f4797b1a9fe07ae820b51907)
1 /*
2  * Copyright (c) 2018 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 "qdf_mem.h"
20 #include "qdf_module.h"
21 #include "qdf_status.h"
22 #include "qdf_str.h"
23 #include "qdf_trace.h"
24 #include "qdf_types.h"
25 
26 static QDF_STATUS qdf_consume_char(const char **str, char c)
27 {
28 	if ((*str)[0] != c)
29 		return QDF_STATUS_E_FAILURE;
30 
31 	(*str)++;
32 
33 	return QDF_STATUS_SUCCESS;
34 }
35 
36 static QDF_STATUS qdf_consume_dec(const char **str, uint8_t *out_digit)
37 {
38 	uint8_t c = (*str)[0];
39 
40 	if (c >= '0' && c <= '9')
41 		*out_digit = c - '0';
42 	else
43 		return QDF_STATUS_E_FAILURE;
44 
45 	(*str)++;
46 
47 	return QDF_STATUS_SUCCESS;
48 }
49 
50 static QDF_STATUS qdf_consume_hex(const char **str, uint8_t *out_nibble)
51 {
52 	uint8_t c = (*str)[0];
53 
54 	if (c >= '0' && c <= '9')
55 		*out_nibble = c - '0';
56 	else if (c >= 'a' && c <= 'f')
57 		*out_nibble = c - 'a' + 10;
58 	else if (c >= 'A' && c <= 'F')
59 		*out_nibble = c - 'A' + 10;
60 	else
61 		return QDF_STATUS_E_FAILURE;
62 
63 	(*str)++;
64 
65 	return QDF_STATUS_SUCCESS;
66 }
67 
68 static QDF_STATUS qdf_consume_octet_dec(const char **str, uint8_t *out_octet)
69 {
70 	uint8_t len = 0;
71 	uint16_t octet = 0;
72 	int i;
73 
74 	/* consume up to 3 decimal digits */
75 	for (i = 0; i < 3; i++) {
76 		uint8_t digit;
77 
78 		if (QDF_IS_STATUS_ERROR(qdf_consume_dec(str, &digit)))
79 			break;
80 
81 		len++;
82 		octet = octet * 10 + digit;
83 	}
84 
85 	/* require at least 1 digit */
86 	if (!len)
87 		return QDF_STATUS_E_FAILURE;
88 
89 	if (octet > 255) {
90 		(*str) -= len;
91 		return QDF_STATUS_E_FAILURE;
92 	}
93 
94 	*out_octet = octet;
95 
96 	return QDF_STATUS_SUCCESS;
97 }
98 
99 static QDF_STATUS qdf_consume_hex_pair(const char **str, uint8_t *out_byte)
100 {
101 	QDF_STATUS status;
102 	uint8_t hi, low;
103 
104 	status = qdf_consume_hex(str, &hi);
105 	if (QDF_IS_STATUS_ERROR(status))
106 		return status;
107 
108 	status = qdf_consume_hex(str, &low);
109 	if (QDF_IS_STATUS_ERROR(status)) {
110 		(*str)--;
111 		return status;
112 	}
113 
114 	*out_byte = hi << 4 | low;
115 
116 	return QDF_STATUS_SUCCESS;
117 }
118 
119 static QDF_STATUS qdf_consume_hextet(const char **str, uint16_t *out_hextet)
120 {
121 	uint8_t len = 0;
122 	uint16_t hextet = 0;
123 	int i;
124 
125 	/* consume up to 4 hex digits */
126 	for (i = 0; i < 4; i++) {
127 		uint8_t digit;
128 
129 		if (QDF_IS_STATUS_ERROR(qdf_consume_hex(str, &digit)))
130 			break;
131 
132 		len++;
133 		hextet = (hextet << 4) + digit;
134 	}
135 
136 	/* require at least 1 digit */
137 	if (!len)
138 		return QDF_STATUS_E_FAILURE;
139 
140 	/* no need to check for overflow */
141 
142 	*out_hextet = hextet;
143 
144 	return QDF_STATUS_SUCCESS;
145 }
146 
147 static QDF_STATUS qdf_consume_radix(const char **str, uint8_t *out_radix)
148 {
149 	if ((*str)[0] == '0') {
150 		switch ((*str)[1]) {
151 		case 'b':
152 			*out_radix = 2;
153 			*str += 2;
154 			break;
155 		case 'o':
156 			*out_radix = 8;
157 			*str += 2;
158 			break;
159 		case 'x':
160 			*out_radix = 16;
161 			*str += 2;
162 			break;
163 		default:
164 			*out_radix = 10;
165 			break;
166 		}
167 
168 		return QDF_STATUS_SUCCESS;
169 	}
170 
171 	if (*str[0] >= '0' && *str[0] <= '9') {
172 		*out_radix = 10;
173 		return QDF_STATUS_SUCCESS;
174 	}
175 
176 	return QDF_STATUS_E_FAILURE;
177 }
178 
179 static QDF_STATUS
180 __qdf_int_parse_lazy(const char **int_str, uint64_t *out_int, bool *out_negate)
181 {
182 	QDF_STATUS status;
183 	bool negate = false;
184 	uint8_t radix;
185 	uint8_t digit;
186 	uint64_t value = 0;
187 	uint64_t next_value;
188 	const char *str = *int_str;
189 
190 	str = qdf_str_left_trim(str);
191 
192 	status = qdf_consume_char(&str, '-');
193 	if (QDF_IS_STATUS_SUCCESS(status))
194 		negate = true;
195 	else
196 		qdf_consume_char(&str, '+');
197 
198 	status = qdf_consume_radix(&str, &radix);
199 	if (QDF_IS_STATUS_ERROR(status))
200 		return status;
201 
202 	while (QDF_IS_STATUS_SUCCESS(qdf_consume_hex(&str, &digit))) {
203 		if (digit >= radix)
204 			return QDF_STATUS_E_FAILURE;
205 
206 		next_value = value * radix + digit;
207 		if (next_value < value)
208 			return QDF_STATUS_E_RANGE;
209 
210 		value = next_value;
211 	}
212 
213 	*int_str = str;
214 	*out_negate = negate;
215 	*out_int = value;
216 
217 	return QDF_STATUS_SUCCESS;
218 }
219 
220 static QDF_STATUS
221 qdf_int_parse(const char *int_str, uint64_t *out_int, bool *out_negate)
222 {
223 	QDF_STATUS status;
224 	bool negate;
225 	uint64_t value;
226 
227 	QDF_BUG(int_str);
228 	if (!int_str)
229 		return QDF_STATUS_E_INVAL;
230 
231 	QDF_BUG(out_int);
232 	if (!out_int)
233 		return QDF_STATUS_E_INVAL;
234 
235 	status = __qdf_int_parse_lazy(&int_str, &value, &negate);
236 	if (QDF_IS_STATUS_ERROR(status))
237 		return status;
238 
239 	int_str = qdf_str_left_trim(int_str);
240 	if (int_str[0] != '\0')
241 		return QDF_STATUS_E_FAILURE;
242 
243 	*out_negate = negate;
244 	*out_int = value;
245 
246 	return QDF_STATUS_SUCCESS;
247 }
248 
249 QDF_STATUS qdf_int32_parse(const char *int_str, int32_t *out_int)
250 {
251 	QDF_STATUS status;
252 	int64_t value;
253 
254 	status = qdf_int64_parse(int_str, &value);
255 	if (QDF_IS_STATUS_ERROR(status))
256 		return status;
257 
258 	if ((int32_t)value != value)
259 		return QDF_STATUS_E_RANGE;
260 
261 	*out_int = value;
262 
263 	return QDF_STATUS_SUCCESS;
264 }
265 qdf_export_symbol(qdf_int32_parse);
266 
267 QDF_STATUS qdf_uint32_parse(const char *int_str, uint32_t *out_int)
268 {
269 	QDF_STATUS status;
270 	uint64_t value;
271 
272 	status = qdf_uint64_parse(int_str, &value);
273 	if (QDF_IS_STATUS_ERROR(status))
274 		return status;
275 
276 	if ((uint32_t)value != value)
277 		return QDF_STATUS_E_RANGE;
278 
279 	*out_int = value;
280 
281 	return QDF_STATUS_SUCCESS;
282 }
283 qdf_export_symbol(qdf_uint32_parse);
284 
285 QDF_STATUS qdf_int64_parse(const char *int_str, int64_t *out_int)
286 {
287 	QDF_STATUS status;
288 	bool negate;
289 	uint64_t value;
290 	int64_t signed_value;
291 
292 	status = qdf_int_parse(int_str, &value, &negate);
293 	if (QDF_IS_STATUS_ERROR(status))
294 		return status;
295 
296 	if (negate) {
297 		signed_value = -value;
298 		if (signed_value > 0)
299 			return QDF_STATUS_E_RANGE;
300 	} else {
301 		signed_value = value;
302 		if (signed_value < 0)
303 			return QDF_STATUS_E_RANGE;
304 	}
305 
306 	*out_int = signed_value;
307 
308 	return QDF_STATUS_SUCCESS;
309 }
310 qdf_export_symbol(qdf_int64_parse);
311 
312 QDF_STATUS qdf_uint64_parse(const char *int_str, uint64_t *out_int)
313 {
314 	QDF_STATUS status;
315 	bool negate;
316 	uint64_t value;
317 
318 	status = qdf_int_parse(int_str, &value, &negate);
319 	if (QDF_IS_STATUS_ERROR(status))
320 		return status;
321 
322 	if (negate)
323 		return QDF_STATUS_E_RANGE;
324 
325 	*out_int = value;
326 
327 	return QDF_STATUS_SUCCESS;
328 }
329 qdf_export_symbol(qdf_uint64_parse);
330 
331 QDF_STATUS qdf_bool_parse(const char *bool_str, bool *out_bool)
332 {
333 	bool value;
334 
335 	QDF_BUG(bool_str);
336 	if (!bool_str)
337 		return QDF_STATUS_E_INVAL;
338 
339 	QDF_BUG(out_bool);
340 	if (!out_bool)
341 		return QDF_STATUS_E_INVAL;
342 
343 	bool_str = qdf_str_left_trim(bool_str);
344 
345 	switch (bool_str[0]) {
346 	case '1':
347 	case 'y':
348 	case 'Y':
349 		value = true;
350 		break;
351 	case '0':
352 	case 'n':
353 	case 'N':
354 		value = false;
355 		break;
356 	default:
357 		return QDF_STATUS_E_FAILURE;
358 	}
359 
360 	bool_str++;
361 	bool_str = qdf_str_left_trim(bool_str);
362 	if (bool_str[0] != '\0')
363 		return QDF_STATUS_E_FAILURE;
364 
365 	*out_bool = value;
366 
367 	return QDF_STATUS_SUCCESS;
368 }
369 qdf_export_symbol(qdf_bool_parse);
370 
371 QDF_STATUS qdf_mac_parse(const char *mac_str, struct qdf_mac_addr *out_addr)
372 {
373 	QDF_STATUS status;
374 	struct qdf_mac_addr addr;
375 	bool colons;
376 	int i;
377 
378 	QDF_BUG(mac_str);
379 	if (!mac_str)
380 		return QDF_STATUS_E_INVAL;
381 
382 	QDF_BUG(out_addr);
383 	if (!out_addr)
384 		return QDF_STATUS_E_INVAL;
385 
386 	mac_str = qdf_str_left_trim(mac_str);
387 
388 	/* parse leading hex pair */
389 	status = qdf_consume_hex_pair(&mac_str, &addr.bytes[0]);
390 	if (QDF_IS_STATUS_ERROR(status))
391 		return status;
392 
393 	/* dynamically detect colons */
394 	colons = mac_str[0] == ':';
395 
396 	for (i = 1; i < QDF_MAC_ADDR_SIZE; i++) {
397 		/* ensure colon separator if previously detected */
398 		if (colons) {
399 			status = qdf_consume_char(&mac_str, ':');
400 			if (QDF_IS_STATUS_ERROR(status))
401 				return status;
402 		}
403 
404 		/* parse next hex pair */
405 		status = qdf_consume_hex_pair(&mac_str, &addr.bytes[i]);
406 		if (QDF_IS_STATUS_ERROR(status))
407 			return status;
408 	}
409 
410 	mac_str = qdf_str_left_trim(mac_str);
411 	if (mac_str[0] != '\0')
412 		return QDF_STATUS_E_FAILURE;
413 
414 	*out_addr = addr;
415 
416 	return QDF_STATUS_SUCCESS;
417 }
418 qdf_export_symbol(qdf_mac_parse);
419 
420 QDF_STATUS qdf_ipv4_parse(const char *ipv4_str, struct qdf_ipv4_addr *out_addr)
421 {
422 	QDF_STATUS status;
423 	struct qdf_ipv4_addr addr;
424 	int i;
425 
426 	QDF_BUG(ipv4_str);
427 	if (!ipv4_str)
428 		return QDF_STATUS_E_INVAL;
429 
430 	QDF_BUG(out_addr);
431 	if (!out_addr)
432 		return QDF_STATUS_E_INVAL;
433 
434 	ipv4_str = qdf_str_left_trim(ipv4_str);
435 
436 	/* parse leading octet */
437 	status = qdf_consume_octet_dec(&ipv4_str, &addr.bytes[0]);
438 	if (QDF_IS_STATUS_ERROR(status))
439 		return status;
440 
441 	for (i = 1; i < QDF_IPV4_ADDR_SIZE; i++) {
442 		/* ensure dot separator */
443 		status = qdf_consume_char(&ipv4_str, '.');
444 		if (QDF_IS_STATUS_ERROR(status))
445 			return status;
446 
447 		/* parse next octet */
448 		status = qdf_consume_octet_dec(&ipv4_str, &addr.bytes[i]);
449 		if (QDF_IS_STATUS_ERROR(status))
450 			return status;
451 	}
452 
453 	ipv4_str = qdf_str_left_trim(ipv4_str);
454 	if (ipv4_str[0] != '\0')
455 		return QDF_STATUS_E_FAILURE;
456 
457 	*out_addr = addr;
458 
459 	return QDF_STATUS_SUCCESS;
460 }
461 qdf_export_symbol(qdf_ipv4_parse);
462 
463 QDF_STATUS qdf_ipv6_parse(const char *ipv6_str, struct qdf_ipv6_addr *out_addr)
464 {
465 	QDF_STATUS status;
466 	struct qdf_ipv6_addr addr;
467 	int8_t zero_comp = -1;
468 	uint8_t hextets_found = 0;
469 
470 	QDF_BUG(ipv6_str);
471 	if (!ipv6_str)
472 		return QDF_STATUS_E_INVAL;
473 
474 	QDF_BUG(out_addr);
475 	if (!out_addr)
476 		return QDF_STATUS_E_INVAL;
477 
478 	ipv6_str = qdf_str_left_trim(ipv6_str);
479 
480 	/* check for leading zero-compression ("::") */
481 	status = qdf_consume_char(&ipv6_str, ':');
482 	if (QDF_IS_STATUS_SUCCESS(status)) {
483 		status = qdf_consume_char(&ipv6_str, ':');
484 		if (QDF_IS_STATUS_SUCCESS(status))
485 			zero_comp = 0;
486 		else
487 			return QDF_STATUS_E_FAILURE;
488 	}
489 
490 	while (hextets_found < QDF_IPV6_ADDR_HEXTET_COUNT) {
491 		uint16_t hextet;
492 
493 		/* parse hextet */
494 		status = qdf_consume_hextet(&ipv6_str, &hextet);
495 		if (QDF_IS_STATUS_ERROR(status)) {
496 			/* we must end with hextet or zero compression */
497 			if (hextets_found != zero_comp)
498 				return QDF_STATUS_E_FAILURE;
499 
500 			break;
501 		}
502 
503 		addr.bytes[hextets_found * 2] = hextet >> 8;
504 		addr.bytes[hextets_found * 2 + 1] = hextet;
505 		hextets_found++;
506 
507 		/* parse ':' char */
508 		status = qdf_consume_char(&ipv6_str, ':');
509 		if (QDF_IS_STATUS_ERROR(status))
510 			break;
511 
512 		/* check for zero compression ("::") */
513 		status = qdf_consume_char(&ipv6_str, ':');
514 		if (QDF_IS_STATUS_SUCCESS(status)) {
515 			/* only one zero compression is allowed */
516 			if (zero_comp >= 0)
517 				return QDF_STATUS_E_FAILURE;
518 
519 			zero_comp = hextets_found;
520 		}
521 	}
522 
523 	/* we must have max hextets or a zero compression */
524 	if (hextets_found < QDF_IPV6_ADDR_HEXTET_COUNT && zero_comp == -1)
525 		return QDF_STATUS_E_FAILURE;
526 
527 	ipv6_str = qdf_str_left_trim(ipv6_str);
528 	if (ipv6_str[0] != '\0')
529 		return QDF_STATUS_E_FAILURE;
530 
531 	/* shift lower hextets if zero compressed */
532 	if (zero_comp >= 0) {
533 		uint8_t shift = QDF_IPV6_ADDR_HEXTET_COUNT - hextets_found;
534 		void *to = &addr.bytes[(zero_comp + shift) * 2];
535 		void *from = &addr.bytes[zero_comp * 2];
536 
537 		qdf_mem_move(to, from, (hextets_found - zero_comp) * 2);
538 		qdf_mem_set(from, shift * 2, 0);
539 	}
540 
541 	*out_addr = addr;
542 
543 	return QDF_STATUS_SUCCESS;
544 }
545 qdf_export_symbol(qdf_ipv6_parse);
546 
547 QDF_STATUS qdf_uint8_array_parse(const char *in_str, uint8_t *out_array,
548 				 qdf_size_t array_size, qdf_size_t *out_size)
549 {
550 	QDF_STATUS status;
551 	bool negate;
552 	qdf_size_t size = 0;
553 	uint64_t value;
554 
555 	QDF_BUG(in_str);
556 	if (!in_str)
557 		return QDF_STATUS_E_INVAL;
558 
559 	QDF_BUG(out_array);
560 	if (!out_array)
561 		return QDF_STATUS_E_INVAL;
562 
563 	QDF_BUG(out_size);
564 	if (!out_size)
565 		return QDF_STATUS_E_INVAL;
566 
567 	while (size < array_size) {
568 		status = __qdf_int_parse_lazy(&in_str, &value, &negate);
569 		if (QDF_IS_STATUS_ERROR(status))
570 			return status;
571 
572 		if ((uint8_t)value != value || negate)
573 			return QDF_STATUS_E_RANGE;
574 
575 		in_str = qdf_str_left_trim(in_str);
576 
577 		switch (in_str[0]) {
578 		case ',':
579 			out_array[size++] = value;
580 			in_str++;
581 			break;
582 		case '\0':
583 			out_array[size++] = value;
584 			*out_size = size;
585 			return QDF_STATUS_SUCCESS;
586 		default:
587 			return QDF_STATUS_E_FAILURE;
588 		}
589 	}
590 
591 	return QDF_STATUS_E_FAILURE;
592 }
593 
594 qdf_export_symbol(qdf_uint8_array_parse);
595