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