xref: /wlan-dirver/qca-wifi-host-cmn/qdf/src/qdf_types.c (revision 6ecd284e5a94a1c96e26d571dd47419ac305990d)
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(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 
189 	QDF_BUG(int_str);
190 	if (!int_str)
191 		return QDF_STATUS_E_INVAL;
192 
193 	QDF_BUG(out_int);
194 	if (!out_int)
195 		return QDF_STATUS_E_INVAL;
196 
197 	int_str = qdf_str_left_trim(int_str);
198 
199 	status = qdf_consume_char(&int_str, '-');
200 	if (QDF_IS_STATUS_SUCCESS(status))
201 		negate = true;
202 	else
203 		qdf_consume_char(&int_str, '+');
204 
205 	status = qdf_consume_radix(&int_str, &radix);
206 	if (QDF_IS_STATUS_ERROR(status))
207 		return status;
208 
209 	while (QDF_IS_STATUS_SUCCESS(qdf_consume_hex(&int_str, &digit))) {
210 		if (digit >= radix)
211 			return QDF_STATUS_E_FAILURE;
212 
213 		next_value = value * radix + digit;
214 		if (next_value < value)
215 			return QDF_STATUS_E_RANGE;
216 
217 		value = next_value;
218 	}
219 
220 	int_str = qdf_str_left_trim(int_str);
221 	if (int_str[0] != '\0')
222 		return QDF_STATUS_E_FAILURE;
223 
224 	*out_negate = negate;
225 	*out_int = value;
226 
227 	return QDF_STATUS_SUCCESS;
228 }
229 
230 QDF_STATUS qdf_int32_parse(const char *int_str, int32_t *out_int)
231 {
232 	QDF_STATUS status;
233 	int64_t value;
234 
235 	status = qdf_int64_parse(int_str, &value);
236 	if (QDF_IS_STATUS_ERROR(status))
237 		return status;
238 
239 	if ((int32_t)value != value)
240 		return QDF_STATUS_E_RANGE;
241 
242 	*out_int = value;
243 
244 	return QDF_STATUS_SUCCESS;
245 }
246 qdf_export_symbol(qdf_int32_parse);
247 
248 QDF_STATUS qdf_uint32_parse(const char *int_str, uint32_t *out_int)
249 {
250 	QDF_STATUS status;
251 	uint64_t value;
252 
253 	status = qdf_uint64_parse(int_str, &value);
254 	if (QDF_IS_STATUS_ERROR(status))
255 		return status;
256 
257 	if ((uint32_t)value != value)
258 		return QDF_STATUS_E_RANGE;
259 
260 	*out_int = value;
261 
262 	return QDF_STATUS_SUCCESS;
263 }
264 qdf_export_symbol(qdf_uint32_parse);
265 
266 QDF_STATUS qdf_int64_parse(const char *int_str, int64_t *out_int)
267 {
268 	QDF_STATUS status;
269 	bool negate;
270 	uint64_t value;
271 	int64_t signed_value;
272 
273 	status = qdf_int_parse(int_str, &value, &negate);
274 	if (QDF_IS_STATUS_ERROR(status))
275 		return status;
276 
277 	if (negate) {
278 		signed_value = -value;
279 		if (signed_value > 0)
280 			return QDF_STATUS_E_RANGE;
281 	} else {
282 		signed_value = value;
283 		if (signed_value < 0)
284 			return QDF_STATUS_E_RANGE;
285 	}
286 
287 	*out_int = signed_value;
288 
289 	return QDF_STATUS_SUCCESS;
290 }
291 qdf_export_symbol(qdf_int64_parse);
292 
293 QDF_STATUS qdf_uint64_parse(const char *int_str, uint64_t *out_int)
294 {
295 	QDF_STATUS status;
296 	bool negate;
297 	uint64_t value;
298 
299 	status = qdf_int_parse(int_str, &value, &negate);
300 	if (QDF_IS_STATUS_ERROR(status))
301 		return status;
302 
303 	if (negate)
304 		return QDF_STATUS_E_RANGE;
305 
306 	*out_int = value;
307 
308 	return QDF_STATUS_SUCCESS;
309 }
310 qdf_export_symbol(qdf_uint64_parse);
311 
312 QDF_STATUS qdf_bool_parse(const char *bool_str, bool *out_bool)
313 {
314 	bool value;
315 
316 	QDF_BUG(bool_str);
317 	if (!bool_str)
318 		return QDF_STATUS_E_INVAL;
319 
320 	QDF_BUG(out_bool);
321 	if (!out_bool)
322 		return QDF_STATUS_E_INVAL;
323 
324 	bool_str = qdf_str_left_trim(bool_str);
325 
326 	switch (bool_str[0]) {
327 	case '1':
328 	case 'y':
329 	case 'Y':
330 		value = true;
331 		break;
332 	case '0':
333 	case 'n':
334 	case 'N':
335 		value = false;
336 		break;
337 	default:
338 		return QDF_STATUS_E_FAILURE;
339 	}
340 
341 	bool_str++;
342 	bool_str = qdf_str_left_trim(bool_str);
343 	if (bool_str[0] != '\0')
344 		return QDF_STATUS_E_FAILURE;
345 
346 	*out_bool = value;
347 
348 	return QDF_STATUS_SUCCESS;
349 }
350 qdf_export_symbol(qdf_bool_parse);
351 
352 QDF_STATUS qdf_mac_parse(const char *mac_str, struct qdf_mac_addr *out_addr)
353 {
354 	QDF_STATUS status;
355 	struct qdf_mac_addr addr;
356 	bool colons;
357 	int i;
358 
359 	QDF_BUG(mac_str);
360 	if (!mac_str)
361 		return QDF_STATUS_E_INVAL;
362 
363 	QDF_BUG(out_addr);
364 	if (!out_addr)
365 		return QDF_STATUS_E_INVAL;
366 
367 	mac_str = qdf_str_left_trim(mac_str);
368 
369 	/* parse leading hex pair */
370 	status = qdf_consume_hex_pair(&mac_str, &addr.bytes[0]);
371 	if (QDF_IS_STATUS_ERROR(status))
372 		return status;
373 
374 	/* dynamically detect colons */
375 	colons = mac_str[0] == ':';
376 
377 	for (i = 1; i < QDF_MAC_ADDR_SIZE; i++) {
378 		/* ensure colon separator if previously detected */
379 		if (colons) {
380 			status = qdf_consume_char(&mac_str, ':');
381 			if (QDF_IS_STATUS_ERROR(status))
382 				return status;
383 		}
384 
385 		/* parse next hex pair */
386 		status = qdf_consume_hex_pair(&mac_str, &addr.bytes[i]);
387 		if (QDF_IS_STATUS_ERROR(status))
388 			return status;
389 	}
390 
391 	mac_str = qdf_str_left_trim(mac_str);
392 	if (mac_str[0] != '\0')
393 		return QDF_STATUS_E_FAILURE;
394 
395 	*out_addr = addr;
396 
397 	return QDF_STATUS_SUCCESS;
398 }
399 qdf_export_symbol(qdf_mac_parse);
400 
401 QDF_STATUS qdf_ipv4_parse(const char *ipv4_str, struct qdf_ipv4_addr *out_addr)
402 {
403 	QDF_STATUS status;
404 	struct qdf_ipv4_addr addr;
405 	int i;
406 
407 	QDF_BUG(ipv4_str);
408 	if (!ipv4_str)
409 		return QDF_STATUS_E_INVAL;
410 
411 	QDF_BUG(out_addr);
412 	if (!out_addr)
413 		return QDF_STATUS_E_INVAL;
414 
415 	ipv4_str = qdf_str_left_trim(ipv4_str);
416 
417 	/* parse leading octet */
418 	status = qdf_consume_octet_dec(&ipv4_str, &addr.bytes[0]);
419 	if (QDF_IS_STATUS_ERROR(status))
420 		return status;
421 
422 	for (i = 1; i < QDF_IPV4_ADDR_SIZE; i++) {
423 		/* ensure dot separator */
424 		status = qdf_consume_char(&ipv4_str, '.');
425 		if (QDF_IS_STATUS_ERROR(status))
426 			return status;
427 
428 		/* parse next octet */
429 		status = qdf_consume_octet_dec(&ipv4_str, &addr.bytes[i]);
430 		if (QDF_IS_STATUS_ERROR(status))
431 			return status;
432 	}
433 
434 	ipv4_str = qdf_str_left_trim(ipv4_str);
435 	if (ipv4_str[0] != '\0')
436 		return QDF_STATUS_E_FAILURE;
437 
438 	*out_addr = addr;
439 
440 	return QDF_STATUS_SUCCESS;
441 }
442 qdf_export_symbol(qdf_ipv4_parse);
443 
444 QDF_STATUS qdf_ipv6_parse(const char *ipv6_str, struct qdf_ipv6_addr *out_addr)
445 {
446 	QDF_STATUS status;
447 	struct qdf_ipv6_addr addr;
448 	int8_t zero_comp = -1;
449 	uint8_t hextets_found = 0;
450 
451 	QDF_BUG(ipv6_str);
452 	if (!ipv6_str)
453 		return QDF_STATUS_E_INVAL;
454 
455 	QDF_BUG(out_addr);
456 	if (!out_addr)
457 		return QDF_STATUS_E_INVAL;
458 
459 	ipv6_str = qdf_str_left_trim(ipv6_str);
460 
461 	/* check for leading zero-compression ("::") */
462 	status = qdf_consume_char(&ipv6_str, ':');
463 	if (QDF_IS_STATUS_SUCCESS(status)) {
464 		status = qdf_consume_char(&ipv6_str, ':');
465 		if (QDF_IS_STATUS_SUCCESS(status))
466 			zero_comp = 0;
467 		else
468 			return QDF_STATUS_E_FAILURE;
469 	}
470 
471 	while (hextets_found < QDF_IPV6_ADDR_HEXTET_COUNT) {
472 		uint16_t hextet;
473 
474 		/* parse hextet */
475 		status = qdf_consume_hextet(&ipv6_str, &hextet);
476 		if (QDF_IS_STATUS_ERROR(status)) {
477 			/* we must end with hextet or zero compression */
478 			if (hextets_found != zero_comp)
479 				return QDF_STATUS_E_FAILURE;
480 
481 			break;
482 		}
483 
484 		addr.bytes[hextets_found * 2] = hextet >> 8;
485 		addr.bytes[hextets_found * 2 + 1] = hextet;
486 		hextets_found++;
487 
488 		/* parse ':' char */
489 		status = qdf_consume_char(&ipv6_str, ':');
490 		if (QDF_IS_STATUS_ERROR(status))
491 			break;
492 
493 		/* check for zero compression ("::") */
494 		status = qdf_consume_char(&ipv6_str, ':');
495 		if (QDF_IS_STATUS_SUCCESS(status)) {
496 			/* only one zero compression is allowed */
497 			if (zero_comp >= 0)
498 				return QDF_STATUS_E_FAILURE;
499 
500 			zero_comp = hextets_found;
501 		}
502 	}
503 
504 	/* we must have max hextets or a zero compression */
505 	if (hextets_found < QDF_IPV6_ADDR_HEXTET_COUNT && zero_comp == -1)
506 		return QDF_STATUS_E_FAILURE;
507 
508 	ipv6_str = qdf_str_left_trim(ipv6_str);
509 	if (ipv6_str[0] != '\0')
510 		return QDF_STATUS_E_FAILURE;
511 
512 	/* shift lower hextets if zero compressed */
513 	if (zero_comp >= 0) {
514 		uint8_t shift = QDF_IPV6_ADDR_HEXTET_COUNT - hextets_found;
515 		void *to = &addr.bytes[((zero_comp - 1) + shift) *2];
516 		void *from = &addr.bytes[(zero_comp - 1) *2];
517 
518 		qdf_mem_move(to, from, (hextets_found - zero_comp) * 2);
519 		qdf_mem_set(from, shift * 2, 0);
520 	}
521 
522 	*out_addr = addr;
523 
524 	return QDF_STATUS_SUCCESS;
525 }
526 qdf_export_symbol(qdf_ipv6_parse);
527