1 /** @file
2  * @brief Misc network utility functions
3  *
4  */
5 
6 /*
7  * Copyright (c) 2016 Intel Corporation
8  *
9  * SPDX-License-Identifier: Apache-2.0
10  */
11 
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(net_utils, CONFIG_NET_UTILS_LOG_LEVEL);
14 
15 #include <zephyr/kernel.h>
16 #include <stdlib.h>
17 #include <zephyr/internal/syscall_handler.h>
18 #include <zephyr/types.h>
19 #include <stdbool.h>
20 #include <string.h>
21 #include <ctype.h>
22 #include <errno.h>
23 
24 #include <zephyr/sys/byteorder.h>
25 #include <zephyr/net/net_ip.h>
26 #include <zephyr/net/net_pkt.h>
27 #include <zephyr/net/net_core.h>
28 #include <zephyr/net/socketcan.h>
29 
net_sprint_addr(sa_family_t af,const void * addr)30 char *net_sprint_addr(sa_family_t af, const void *addr)
31 {
32 #define NBUFS 3
33 	static char buf[NBUFS][NET_IPV6_ADDR_LEN];
34 	static int i;
35 	char *s = buf[++i % NBUFS];
36 
37 	return net_addr_ntop(af, addr, s, NET_IPV6_ADDR_LEN);
38 }
39 
net_verdict2str(enum net_verdict verdict)40 const char *net_verdict2str(enum net_verdict verdict)
41 {
42 	if (verdict == NET_OK) {
43 		return "NET_OK";
44 	} else if (verdict == NET_CONTINUE) {
45 		return "NET_CONTINUE";
46 	} else if (verdict == NET_DROP) {
47 		return "NET_DROP";
48 	}
49 
50 	return "<unknown>";
51 }
52 
net_proto2str(int family,int proto)53 const char *net_proto2str(int family, int proto)
54 {
55 	if (family == AF_INET || family == AF_INET6) {
56 		switch (proto) {
57 		case IPPROTO_ICMP:
58 			return "ICMPv4";
59 		case IPPROTO_TCP:
60 			return "TCP";
61 		case IPPROTO_UDP:
62 			return "UDP";
63 		case IPPROTO_ICMPV6:
64 			return "ICMPv6";
65 		default:
66 			break;
67 		}
68 	} else if (family == AF_CAN) {
69 		switch (proto) {
70 		case CAN_RAW:
71 			return "CAN_RAW";
72 		default:
73 			break;
74 		}
75 	}
76 
77 	return "UNK_PROTO";
78 }
79 
net_byte_to_hex(char * ptr,uint8_t byte,char base,bool pad)80 char *net_byte_to_hex(char *ptr, uint8_t byte, char base, bool pad)
81 {
82 	uint8_t high = (byte >> 4) & 0x0f;
83 	uint8_t low = byte & 0x0f;
84 
85 	if (pad || (high > 0)) {
86 		*ptr++ = (high < 10) ? (char) (high + '0') : (char) (high - 10 + base);
87 	}
88 
89 	*ptr++ = (low < 10) ? (char) (low + '0') : (char) (low - 10 + base);
90 
91 	*ptr = '\0';
92 
93 	return ptr;
94 }
95 
net_sprint_ll_addr_buf(const uint8_t * ll,uint8_t ll_len,char * buf,int buflen)96 char *net_sprint_ll_addr_buf(const uint8_t *ll, uint8_t ll_len,
97 			     char *buf, int buflen)
98 {
99 	uint8_t i, len, blen;
100 	char *ptr = buf;
101 
102 	if (ll == NULL) {
103 		return "<unknown>";
104 	}
105 
106 	switch (ll_len) {
107 	case 8:
108 		len = 8U;
109 		break;
110 	case 6:
111 		len = 6U;
112 		break;
113 	case 2:
114 		len = 2U;
115 		break;
116 	default:
117 		len = 6U;
118 		break;
119 	}
120 
121 	for (i = 0U, blen = buflen; i < len && blen > 0; i++) {
122 		ptr = net_byte_to_hex(ptr, (char)ll[i], 'A', true);
123 		*ptr++ = ':';
124 		blen -= 3U;
125 	}
126 
127 	if (!(ptr - buf)) {
128 		return NULL;
129 	}
130 
131 	*(ptr - 1) = '\0';
132 	return buf;
133 }
134 
net_value_to_udec(char * buf,uint32_t value,int precision)135 static int net_value_to_udec(char *buf, uint32_t value, int precision)
136 {
137 	uint32_t divisor;
138 	int i;
139 	int temp;
140 	char *start = buf;
141 
142 	divisor = 1000000000U;
143 	if (precision < 0) {
144 		precision = 1;
145 	}
146 
147 	for (i = 9; i >= 0; i--, divisor /= 10U) {
148 		temp = value / divisor;
149 		value = value % divisor;
150 		if ((precision > i) || (temp != 0)) {
151 			precision = i;
152 			*buf++ = (char) (temp + '0');
153 		}
154 	}
155 	*buf = 0;
156 
157 	return buf - start;
158 }
159 
z_impl_net_addr_ntop(sa_family_t family,const void * src,char * dst,size_t size)160 char *z_impl_net_addr_ntop(sa_family_t family, const void *src,
161 			   char *dst, size_t size)
162 {
163 	struct in_addr *addr = NULL;
164 	struct in6_addr *addr6 = NULL;
165 	uint16_t *w = NULL;
166 	int i;
167 	uint8_t longest = 1U;
168 	int pos = -1;
169 	char delim = ':';
170 	uint8_t zeros[8] = { 0 };
171 	char *ptr = dst;
172 	int len = -1;
173 	uint16_t value;
174 	bool needcolon = false;
175 	bool mapped = false;
176 
177 	if (family == AF_INET6) {
178 		addr6 = (struct in6_addr *)src;
179 		w = (uint16_t *)addr6->s6_addr16;
180 		len = 8;
181 
182 		if (net_ipv6_addr_is_v4_mapped(addr6)) {
183 			mapped = true;
184 		}
185 
186 		for (i = 0; i < 8; i++) {
187 			for (int j = i; j < 8; j++) {
188 				if (UNALIGNED_GET(&w[j]) != 0) {
189 					break;
190 				}
191 
192 				zeros[i]++;
193 			}
194 		}
195 
196 		for (i = 0; i < 8; i++) {
197 			if (zeros[i] > longest) {
198 				longest = zeros[i];
199 				pos = i;
200 			}
201 		}
202 
203 		if (longest == 1U) {
204 			pos = -1;
205 		}
206 
207 	} else if (family == AF_INET) {
208 		addr = (struct in_addr *)src;
209 		len = 4;
210 		delim = '.';
211 	} else {
212 		return NULL;
213 	}
214 
215 print_mapped:
216 	for (i = 0; i < len; i++) {
217 		/* IPv4 address a.b.c.d */
218 		if (len == 4) {
219 			uint8_t l;
220 
221 			value = (uint16_t)addr->s4_addr[i];
222 
223 			/* net_byte_to_udec() eats 0 */
224 			if (value == 0U) {
225 				*ptr++ = '0';
226 				*ptr++ = delim;
227 				continue;
228 			}
229 
230 			l = net_value_to_udec(ptr, value, 0);
231 
232 			ptr += l;
233 			*ptr++ = delim;
234 
235 			continue;
236 		}
237 
238 		if (mapped && (i > 5)) {
239 			delim = '.';
240 			len = 4;
241 			addr = (struct in_addr *)(&addr6->s6_addr32[3]);
242 			*ptr++ = ':';
243 			family = AF_INET;
244 			goto print_mapped;
245 		}
246 
247 		/* IPv6 address */
248 		if (i == pos) {
249 			if (needcolon || i == 0U) {
250 				*ptr++ = ':';
251 			}
252 
253 			*ptr++ = ':';
254 			needcolon = false;
255 			i += (int)longest - 1;
256 
257 			continue;
258 		}
259 
260 		if (needcolon) {
261 			*ptr++ = ':';
262 		}
263 
264 		value = sys_be16_to_cpu(UNALIGNED_GET(&w[i]));
265 		uint8_t bh = value >> 8;
266 		uint8_t bl = value & 0xff;
267 
268 		if (bh) {
269 			/* Convert high byte to hex without padding */
270 			ptr = net_byte_to_hex(ptr, bh, 'a', false);
271 
272 			/* Always pad the low byte, since high byte is non - zero */
273 			ptr = net_byte_to_hex(ptr, bl, 'a', true);
274 		} else {
275 			/* For the case where the high byte is zero, only process the low byte
276 			 * Do not pad the low byte, since high byte is zero
277 			 */
278 			ptr = net_byte_to_hex(ptr, bl, 'a', false);
279 		}
280 
281 		needcolon = true;
282 	}
283 
284 	if (!(ptr - dst)) {
285 		return NULL;
286 	}
287 
288 	if (family == AF_INET) {
289 		*(ptr - 1) = '\0';
290 	} else {
291 		*ptr = '\0';
292 	}
293 
294 	return dst;
295 }
296 
297 #if defined(CONFIG_USERSPACE)
z_vrfy_net_addr_ntop(sa_family_t family,const void * src,char * dst,size_t size)298 char *z_vrfy_net_addr_ntop(sa_family_t family, const void *src,
299 			   char *dst, size_t size)
300 {
301 	char str[INET6_ADDRSTRLEN];
302 	struct in6_addr addr6;
303 	struct in_addr addr4;
304 	char *out;
305 	const void *addr;
306 
307 	K_OOPS(K_SYSCALL_MEMORY_WRITE(dst, size));
308 
309 	if (family == AF_INET) {
310 		K_OOPS(k_usermode_from_copy(&addr4, (const void *)src,
311 					sizeof(addr4)));
312 		addr = &addr4;
313 	} else if (family == AF_INET6) {
314 		K_OOPS(k_usermode_from_copy(&addr6, (const void *)src,
315 					sizeof(addr6)));
316 		addr = &addr6;
317 	} else {
318 		return 0;
319 	}
320 
321 	out = z_impl_net_addr_ntop(family, addr, str, sizeof(str));
322 	if (!out) {
323 		return 0;
324 	}
325 
326 	K_OOPS(k_usermode_to_copy((void *)dst, str, MIN(size, sizeof(str))));
327 
328 	return dst;
329 }
330 #include <zephyr/syscalls/net_addr_ntop_mrsh.c>
331 #endif /* CONFIG_USERSPACE */
332 
z_impl_net_addr_pton(sa_family_t family,const char * src,void * dst)333 int z_impl_net_addr_pton(sa_family_t family, const char *src,
334 			 void *dst)
335 {
336 	if (family == AF_INET) {
337 		struct in_addr *addr = (struct in_addr *)dst;
338 		uint8_t index = 0, digits = 0;
339 		uint16_t value = 0, count = 0;
340 
341 		(void)memset(addr, 0, sizeof(struct in_addr));
342 
343 		/* A valid IPv4 address that can be used with inet_pton
344 		 * must be in the standard dotted-decimal notation:
345 		 *
346 		 *    - Four octets, each ranging from 0 to 255
347 		 *    - Separated by dots (.)
348 		 *    - No leading zeros in each octet
349 		 */
350 
351 		while (index < sizeof(struct in_addr)) {
352 			if (*src == '\0' || *src == '.') {
353 				if (*src == '.') {
354 					count++;
355 				}
356 
357 				if ((digits > 1 && value < 10) ||
358 				    (digits > 2 && value < 100)) {
359 					/* Preceding zeroes */
360 					return -EINVAL;
361 				}
362 
363 				if (digits == 0 || value > UINT8_MAX) {
364 					return -EINVAL;
365 				}
366 
367 				addr->s4_addr[index] = value;
368 
369 				if (*src == '\0') {
370 					break;
371 				}
372 
373 				index++;
374 				digits = 0;
375 				value = 0;
376 			} else if ('0' <= *src && *src <= '9') {
377 				if (++digits > 3) {
378 					/* Number too large */
379 					return -EINVAL;
380 				}
381 
382 				value *= 10;
383 				value += *src - '0';
384 			} else {
385 				/* Invalid character */
386 				return -EINVAL;
387 			}
388 
389 			src++;
390 		}
391 
392 		if (count != 3) {
393 			/* Three dots needed */
394 			return -EINVAL;
395 		}
396 
397 	} else if (family == AF_INET6) {
398 		/* If the string contains a '.', it means it's of the form
399 		 * X:X:X:X:X:X:x.x.x.x, and contains only 6 16-bit pieces
400 		 */
401 		int expected_groups = strchr(src, '.') ? 6 : 8;
402 		struct in6_addr *addr = (struct in6_addr *)dst;
403 		int i, len;
404 
405 		if (*src == ':') {
406 			/* Ignore a leading colon, makes parsing neater */
407 			src++;
408 		}
409 
410 		len = strlen(src);
411 		for (i = 0; i < len; i++) {
412 			if (!(src[i] >= '0' && src[i] <= '9') &&
413 			    !(src[i] >= 'A' && src[i] <= 'F') &&
414 			    !(src[i] >= 'a' && src[i] <= 'f') &&
415 			    src[i] != '.' && src[i] != ':') {
416 				return -EINVAL;
417 			}
418 		}
419 
420 		for (i = 0; i < expected_groups; i++) {
421 			char *tmp;
422 
423 			if (!src || *src == '\0') {
424 				return -EINVAL;
425 			}
426 
427 			if (*src != ':') {
428 				/* Normal IPv6 16-bit piece */
429 				UNALIGNED_PUT(htons(strtol(src, NULL, 16)),
430 					      &addr->s6_addr16[i]);
431 				src = strchr(src, ':');
432 				if (src) {
433 					src++;
434 				} else {
435 					if (i < expected_groups - 1) {
436 						return -EINVAL;
437 					}
438 				}
439 
440 				continue;
441 			}
442 
443 			/* Two colons in a row */
444 
445 			for (; i < expected_groups; i++) {
446 				UNALIGNED_PUT(0, &addr->s6_addr16[i]);
447 			}
448 
449 			tmp = strrchr(src, ':');
450 			if (src == tmp && (expected_groups == 6 || !src[1])) {
451 				src++;
452 				break;
453 			}
454 
455 			if (expected_groups == 6) {
456 				/* we need to drop the trailing
457 				 * colon since it's between the
458 				 * ipv6 and ipv4 addresses, rather than being
459 				 * a part of the ipv6 address
460 				 */
461 				tmp--;
462 			}
463 
464 			/* Calculate the amount of skipped zeros */
465 			i = expected_groups - 1;
466 			do {
467 				if (*tmp == ':') {
468 					i--;
469 				}
470 
471 				if (i < 0) {
472 					return -EINVAL;
473 				}
474 			} while (tmp-- != src);
475 
476 			src++;
477 		}
478 
479 		if (expected_groups == 6) {
480 			/* Parse the IPv4 part */
481 			for (i = 0; i < 4; i++) {
482 				if (!src || !*src) {
483 					return -EINVAL;
484 				}
485 
486 				addr->s6_addr[12 + i] = strtol(src, NULL, 10);
487 
488 				src = strchr(src, '.');
489 				if (src) {
490 					src++;
491 				} else {
492 					if (i < 3) {
493 						return -EINVAL;
494 					}
495 				}
496 			}
497 		}
498 	} else {
499 		return -EINVAL;
500 	}
501 
502 	return 0;
503 }
504 
505 #if defined(CONFIG_USERSPACE)
z_vrfy_net_addr_pton(sa_family_t family,const char * src,void * dst)506 int z_vrfy_net_addr_pton(sa_family_t family, const char *src,
507 			 void *dst)
508 {
509 	char str[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)] = {};
510 	struct in6_addr addr6;
511 	struct in_addr addr4;
512 	void *addr;
513 	size_t size;
514 	int err;
515 
516 	if (family == AF_INET) {
517 		size = sizeof(struct in_addr);
518 		addr = &addr4;
519 	} else if (family == AF_INET6) {
520 		size = sizeof(struct in6_addr);
521 		addr = &addr6;
522 	} else {
523 		return -EINVAL;
524 	}
525 
526 	if (k_usermode_string_copy(str, (char *)src, sizeof(str)) != 0) {
527 		return -EINVAL;
528 	}
529 
530 	K_OOPS(K_SYSCALL_MEMORY_WRITE(dst, size));
531 
532 	err = z_impl_net_addr_pton(family, str, addr);
533 	if (err) {
534 		return err;
535 	}
536 
537 	K_OOPS(k_usermode_to_copy((void *)dst, addr, size));
538 
539 	return 0;
540 }
541 #include <zephyr/syscalls/net_addr_pton_mrsh.c>
542 #endif /* CONFIG_USERSPACE */
543 
544 
545 #ifdef CONFIG_LITTLE_ENDIAN
546 #define CHECKSUM_BIG_ENDIAN 0
547 #else
548 #define CHECKSUM_BIG_ENDIAN 1
549 #endif
550 
offset_based_swap8(const uint8_t * data)551 static uint16_t offset_based_swap8(const uint8_t *data)
552 {
553 	uint16_t data16 = (uint16_t)*data;
554 
555 	if (((uintptr_t)(data) & 1) == CHECKSUM_BIG_ENDIAN) {
556 		return data16;
557 	} else {
558 		return data16 << 8;
559 	}
560 }
561 
562 /* Word based checksum calculation based on:
563  * https://blogs.igalia.com/dpino/2018/06/14/fast-checksum-computation/
564  * It’s not necessary to add octets as 16-bit words. Due to the associative property of addition,
565  * it is possible to do parallel addition using larger word sizes such as 32-bit or 64-bit words.
566  * In those cases the variable that stores the accumulative sum has to be bigger too.
567  * Once the sum is computed a final step folds the sum to a 16-bit word (adding carry if any).
568  */
calc_chksum(uint16_t sum_in,const uint8_t * data,size_t len)569 uint16_t calc_chksum(uint16_t sum_in, const uint8_t *data, size_t len)
570 {
571 	uint64_t sum;
572 	uint32_t *p;
573 	size_t i = 0;
574 	size_t pending = len;
575 	int odd_start = ((uintptr_t)data & 0x01);
576 
577 	/* Sum in is in host endianness, working order endianness is both dependent on endianness
578 	 * and the offset of starting
579 	 */
580 	if (odd_start == CHECKSUM_BIG_ENDIAN) {
581 		sum = BSWAP_16(sum_in);
582 	} else {
583 		sum = sum_in;
584 	}
585 
586 	/* Process up to 3 data elements up front, so the data is aligned further down the line */
587 	if ((((uintptr_t)data & 0x01) != 0) && (pending >= 1)) {
588 		sum += offset_based_swap8(data);
589 		data++;
590 		pending--;
591 	}
592 	if ((((uintptr_t)data & 0x02) != 0) && (pending >= sizeof(uint16_t))) {
593 		pending -= sizeof(uint16_t);
594 		sum = sum + *((uint16_t *)data);
595 		data += sizeof(uint16_t);
596 	}
597 	p = (uint32_t *)data;
598 
599 	/* Do loop unrolling for the very large data sets */
600 	while (pending >= sizeof(uint32_t) * 4) {
601 		uint64_t sum_a = p[i];
602 		uint64_t sum_b = p[i + 1];
603 
604 		pending -= sizeof(uint32_t) * 4;
605 		sum_a += p[i + 2];
606 		sum_b += p[i + 3];
607 		i += 4;
608 		sum += sum_a + sum_b;
609 	}
610 	while (pending >= sizeof(uint32_t)) {
611 		pending -= sizeof(uint32_t);
612 		sum = sum + p[i++];
613 	}
614 	data = (uint8_t *)(p + i);
615 	if (pending >= 2) {
616 		pending -= sizeof(uint16_t);
617 		sum = sum + *((uint16_t *)data);
618 		data += sizeof(uint16_t);
619 	}
620 	if (pending == 1) {
621 		sum += offset_based_swap8(data);
622 	}
623 
624 	/* Fold sum into 16-bit word. */
625 	while (sum >> 16) {
626 		sum = (sum & 0xffff) + (sum >> 16);
627 	}
628 
629 	/* Sum in is in host endianness, working order endianness is both dependent on endianness
630 	 * and the offset of starting
631 	 */
632 	if (odd_start == CHECKSUM_BIG_ENDIAN) {
633 		return BSWAP_16((uint16_t)sum);
634 	} else {
635 		return sum;
636 	}
637 }
638 
639 #if defined(CONFIG_NET_NATIVE_IP)
pkt_calc_chksum(struct net_pkt * pkt,uint16_t sum)640 static inline uint16_t pkt_calc_chksum(struct net_pkt *pkt, uint16_t sum)
641 {
642 	struct net_pkt_cursor *cur = &pkt->cursor;
643 	size_t len;
644 
645 	if (!cur->buf || !cur->pos) {
646 		return sum;
647 	}
648 
649 	len = cur->buf->len - (cur->pos - cur->buf->data);
650 
651 	while (cur->buf) {
652 		sum = calc_chksum(sum, cur->pos, len);
653 
654 		cur->buf = cur->buf->frags;
655 		if (!cur->buf || !cur->buf->len) {
656 			break;
657 		}
658 
659 		cur->pos = cur->buf->data;
660 
661 		if (len % 2) {
662 			sum += *cur->pos;
663 			if (sum < *cur->pos) {
664 				sum++;
665 			}
666 
667 			cur->pos++;
668 			len = cur->buf->len - 1;
669 		} else {
670 			len = cur->buf->len;
671 		}
672 	}
673 
674 	return sum;
675 }
676 
net_calc_chksum(struct net_pkt * pkt,uint8_t proto)677 uint16_t net_calc_chksum(struct net_pkt *pkt, uint8_t proto)
678 {
679 	size_t len = 0U;
680 	uint16_t sum = 0U;
681 	struct net_pkt_cursor backup;
682 	bool ow;
683 
684 	if (IS_ENABLED(CONFIG_NET_IPV4) &&
685 	    net_pkt_family(pkt) == AF_INET) {
686 		if (proto != IPPROTO_ICMP && proto != IPPROTO_IGMP) {
687 			len = 2 * sizeof(struct in_addr);
688 			sum = net_pkt_get_len(pkt) -
689 				net_pkt_ip_hdr_len(pkt) -
690 				net_pkt_ipv4_opts_len(pkt) + proto;
691 		}
692 	} else if (IS_ENABLED(CONFIG_NET_IPV6) &&
693 		   net_pkt_family(pkt) == AF_INET6) {
694 		len = 2 * sizeof(struct in6_addr);
695 		sum =  net_pkt_get_len(pkt) -
696 			net_pkt_ip_hdr_len(pkt) -
697 			net_pkt_ipv6_ext_len(pkt) + proto;
698 	} else {
699 		NET_DBG("Unknown protocol family %d", net_pkt_family(pkt));
700 		return 0;
701 	}
702 
703 	net_pkt_cursor_backup(pkt, &backup);
704 	net_pkt_cursor_init(pkt);
705 
706 	ow = net_pkt_is_being_overwritten(pkt);
707 	net_pkt_set_overwrite(pkt, true);
708 
709 	net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) - len);
710 
711 	sum = calc_chksum(sum, pkt->cursor.pos, len);
712 	net_pkt_skip(pkt, len + net_pkt_ip_opts_len(pkt));
713 
714 	sum = pkt_calc_chksum(pkt, sum);
715 
716 	sum = (sum == 0U) ? 0xffff : htons(sum);
717 
718 	net_pkt_cursor_restore(pkt, &backup);
719 
720 	net_pkt_set_overwrite(pkt, ow);
721 
722 	return ~sum;
723 }
724 #endif
725 
726 #if defined(CONFIG_NET_NATIVE_IPV4)
net_calc_chksum_ipv4(struct net_pkt * pkt)727 uint16_t net_calc_chksum_ipv4(struct net_pkt *pkt)
728 {
729 	uint16_t sum;
730 
731 	sum = calc_chksum(0, pkt->buffer->data,
732 			  net_pkt_ip_hdr_len(pkt) +
733 			  net_pkt_ipv4_opts_len(pkt));
734 
735 	sum = (sum == 0U) ? 0xffff : htons(sum);
736 
737 	return ~sum;
738 }
739 #endif /* CONFIG_NET_NATIVE_IPV4 */
740 
741 #if defined(CONFIG_NET_IPV4_IGMP)
net_calc_chksum_igmp(struct net_pkt * pkt)742 uint16_t net_calc_chksum_igmp(struct net_pkt *pkt)
743 {
744 	return net_calc_chksum(pkt, IPPROTO_IGMP);
745 }
746 #endif /* CONFIG_NET_IPV4_IGMP */
747 
748 #if defined(CONFIG_NET_IP)
convert_port(const char * buf,uint16_t * port)749 static bool convert_port(const char *buf, uint16_t *port)
750 {
751 	unsigned long tmp;
752 	char *endptr;
753 
754 	tmp = strtoul(buf, &endptr, 10);
755 	if ((endptr == buf && tmp == 0) ||
756 	    !(*buf != '\0' && *endptr == '\0') ||
757 	    ((unsigned long)(unsigned short)tmp != tmp)) {
758 		return false;
759 	}
760 
761 	*port = tmp;
762 
763 	return true;
764 }
765 #endif /* CONFIG_NET_IP */
766 
767 #if defined(CONFIG_NET_IPV6)
parse_ipv6(const char * str,size_t str_len,struct sockaddr * addr,bool has_port)768 static bool parse_ipv6(const char *str, size_t str_len,
769 		       struct sockaddr *addr, bool has_port)
770 {
771 	char *ptr = NULL;
772 	struct in6_addr *addr6;
773 	char ipaddr[INET6_ADDRSTRLEN + 1];
774 	int end, len, ret, i;
775 	uint16_t port;
776 
777 	len = MIN(INET6_ADDRSTRLEN, str_len);
778 
779 	for (i = 0; i < len; i++) {
780 		if (!str[i]) {
781 			len = i;
782 			break;
783 		}
784 	}
785 
786 	if (has_port) {
787 		/* IPv6 address with port number */
788 		ptr = memchr(str, ']', len);
789 		if (!ptr) {
790 			return false;
791 		}
792 
793 		end = MIN(len, ptr - (str + 1));
794 		memcpy(ipaddr, str + 1, end);
795 	} else {
796 		end = len;
797 		memcpy(ipaddr, str, end);
798 	}
799 
800 	ipaddr[end] = '\0';
801 
802 	addr6 = &net_sin6(addr)->sin6_addr;
803 
804 	ret = net_addr_pton(AF_INET6, ipaddr, addr6);
805 	if (ret < 0) {
806 		return false;
807 	}
808 
809 	net_sin6(addr)->sin6_family = AF_INET6;
810 
811 	if (!has_port) {
812 		return true;
813 	}
814 
815 	if ((ptr + 1) < (str + str_len) && *(ptr + 1) == ':') {
816 		/* -1 as end does not contain first [
817 		 * -2 as pointer is advanced by 2, skipping ]:
818 		 */
819 		len = str_len - end - 1 - 2;
820 
821 		ptr += 2;
822 
823 		for (i = 0; i < len; i++) {
824 			if (!ptr[i]) {
825 				len = i;
826 				break;
827 			}
828 		}
829 
830 		/* Re-use the ipaddr buf for port conversion */
831 		memcpy(ipaddr, ptr, len);
832 		ipaddr[len] = '\0';
833 
834 		ret = convert_port(ipaddr, &port);
835 		if (!ret) {
836 			return false;
837 		}
838 
839 		net_sin6(addr)->sin6_port = htons(port);
840 
841 		NET_DBG("IPv6 host %s port %d",
842 			net_addr_ntop(AF_INET6, addr6, ipaddr, sizeof(ipaddr) - 1),
843 			port);
844 	} else {
845 		NET_DBG("IPv6 host %s",
846 			net_addr_ntop(AF_INET6, addr6, ipaddr, sizeof(ipaddr) - 1));
847 	}
848 
849 	return true;
850 }
851 #else
parse_ipv6(const char * str,size_t str_len,struct sockaddr * addr,bool has_port)852 static inline bool parse_ipv6(const char *str, size_t str_len,
853 			      struct sockaddr *addr, bool has_port)
854 {
855 	return false;
856 }
857 #endif /* CONFIG_NET_IPV6 */
858 
859 #if defined(CONFIG_NET_IPV4)
parse_ipv4(const char * str,size_t str_len,struct sockaddr * addr,bool has_port)860 static bool parse_ipv4(const char *str, size_t str_len,
861 		       struct sockaddr *addr, bool has_port)
862 {
863 	char *ptr = NULL;
864 	char ipaddr[NET_IPV4_ADDR_LEN + 1];
865 	struct in_addr *addr4;
866 	int end, len, ret, i;
867 	uint16_t port;
868 
869 	len = MIN(NET_IPV4_ADDR_LEN, str_len);
870 
871 	for (i = 0; i < len; i++) {
872 		if (!str[i]) {
873 			len = i;
874 			break;
875 		}
876 	}
877 
878 	if (has_port) {
879 		/* IPv4 address with port number */
880 		ptr = memchr(str, ':', len);
881 		if (!ptr) {
882 			return false;
883 		}
884 
885 		end = MIN(len, ptr - str);
886 	} else {
887 		end = len;
888 	}
889 
890 	memcpy(ipaddr, str, end);
891 	ipaddr[end] = '\0';
892 
893 	addr4 = &net_sin(addr)->sin_addr;
894 
895 	ret = net_addr_pton(AF_INET, ipaddr, addr4);
896 	if (ret < 0) {
897 		return false;
898 	}
899 
900 	net_sin(addr)->sin_family = AF_INET;
901 
902 	if (!has_port) {
903 		return true;
904 	}
905 
906 	memcpy(ipaddr, ptr + 1, str_len - end - 1);
907 	ipaddr[str_len - end - 1] = '\0';
908 
909 	ret = convert_port(ipaddr, &port);
910 	if (!ret) {
911 		return false;
912 	}
913 
914 	net_sin(addr)->sin_port = htons(port);
915 
916 	NET_DBG("IPv4 host %s port %d",
917 		net_addr_ntop(AF_INET, addr4, ipaddr, sizeof(ipaddr) - 1),
918 		port);
919 	return true;
920 }
921 #else
parse_ipv4(const char * str,size_t str_len,struct sockaddr * addr,bool has_port)922 static inline bool parse_ipv4(const char *str, size_t str_len,
923 			      struct sockaddr *addr, bool has_port)
924 {
925 	return false;
926 }
927 #endif /* CONFIG_NET_IPV4 */
928 
net_ipaddr_parse(const char * str,size_t str_len,struct sockaddr * addr)929 bool net_ipaddr_parse(const char *str, size_t str_len, struct sockaddr *addr)
930 {
931 	int i, count;
932 
933 	if (!str || str_len == 0) {
934 		return false;
935 	}
936 
937 	/* We cannot accept empty string here */
938 	if (*str == '\0') {
939 		return false;
940 	}
941 
942 	if (*str == '[') {
943 		return parse_ipv6(str, str_len, addr, true);
944 	}
945 
946 	for (count = i = 0; i < str_len && str[i]; i++) {
947 		if (str[i] == ':') {
948 			count++;
949 		}
950 	}
951 
952 	if (count == 1) {
953 		return parse_ipv4(str, str_len, addr, true);
954 	}
955 
956 #if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_IPV6)
957 	if (!parse_ipv4(str, str_len, addr, false)) {
958 		return parse_ipv6(str, str_len, addr, false);
959 	}
960 
961 	return true;
962 #endif
963 
964 #if defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
965 	return parse_ipv4(str, str_len, addr, false);
966 #endif
967 
968 #if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4)
969 	return parse_ipv6(str, str_len, addr, false);
970 #endif
971 	return false;
972 }
973 
net_port_set_default(struct sockaddr * addr,uint16_t default_port)974 int net_port_set_default(struct sockaddr *addr, uint16_t default_port)
975 {
976 	if (IS_ENABLED(CONFIG_NET_IPV4) && addr->sa_family == AF_INET &&
977 	    net_sin(addr)->sin_port == 0) {
978 		net_sin(addr)->sin_port = htons(default_port);
979 	} else if (IS_ENABLED(CONFIG_NET_IPV6) && addr->sa_family == AF_INET6 &&
980 		   net_sin6(addr)->sin6_port == 0) {
981 		net_sin6(addr)->sin6_port = htons(default_port);
982 	} else if ((IS_ENABLED(CONFIG_NET_IPV4) && addr->sa_family == AF_INET) ||
983 		   (IS_ENABLED(CONFIG_NET_IPV6) && addr->sa_family == AF_INET6)) {
984 		; /* Port is already set */
985 	} else {
986 		LOG_ERR("Unknown address family");
987 		return -EINVAL;
988 	}
989 
990 	return 0;
991 }
992 
net_bytes_from_str(uint8_t * buf,int buf_len,const char * src)993 int net_bytes_from_str(uint8_t *buf, int buf_len, const char *src)
994 {
995 	size_t i;
996 	size_t src_len = strlen(src);
997 	char *endptr;
998 
999 	for (i = 0U; i < src_len; i++) {
1000 		if (!isxdigit((unsigned char)src[i]) &&
1001 		    src[i] != ':') {
1002 			return -EINVAL;
1003 		}
1004 	}
1005 
1006 	(void)memset(buf, 0, buf_len);
1007 
1008 	for (i = 0U; i < (size_t)buf_len; i++) {
1009 		buf[i] = (uint8_t)strtol(src, &endptr, 16);
1010 		src = ++endptr;
1011 	}
1012 
1013 	return 0;
1014 }
1015 
net_family2str(sa_family_t family)1016 const char *net_family2str(sa_family_t family)
1017 {
1018 	switch (family) {
1019 	case AF_UNSPEC:
1020 		return "AF_UNSPEC";
1021 	case AF_INET:
1022 		return "AF_INET";
1023 	case AF_INET6:
1024 		return "AF_INET6";
1025 	case AF_PACKET:
1026 		return "AF_PACKET";
1027 	case AF_CAN:
1028 		return "AF_CAN";
1029 	}
1030 
1031 	return NULL;
1032 }
1033 
net_ipv4_unspecified_address(void)1034 const struct in_addr *net_ipv4_unspecified_address(void)
1035 {
1036 	static const struct in_addr addr;
1037 
1038 	return &addr;
1039 }
1040 
net_ipv4_broadcast_address(void)1041 const struct in_addr *net_ipv4_broadcast_address(void)
1042 {
1043 	static const struct in_addr addr = { { { 255, 255, 255, 255 } } };
1044 
1045 	return &addr;
1046 }
1047 
1048 /* IPv6 wildcard and loopback address defined by RFC2553 */
1049 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
1050 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
1051 
net_ipv6_unspecified_address(void)1052 const struct in6_addr *net_ipv6_unspecified_address(void)
1053 {
1054 	return &in6addr_any;
1055 }
1056