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 size_t i, len;
339
340 len = strlen(src);
341 for (i = 0; i < len; i++) {
342 if (!(src[i] >= '0' && src[i] <= '9') &&
343 src[i] != '.') {
344 return -EINVAL;
345 }
346 }
347
348 (void)memset(addr, 0, sizeof(struct in_addr));
349
350 for (i = 0; i < sizeof(struct in_addr); i++) {
351 char *endptr;
352
353 addr->s4_addr[i] = strtol(src, &endptr, 10);
354
355 src = ++endptr;
356 }
357
358 } else if (family == AF_INET6) {
359 /* If the string contains a '.', it means it's of the form
360 * X:X:X:X:X:X:x.x.x.x, and contains only 6 16-bit pieces
361 */
362 int expected_groups = strchr(src, '.') ? 6 : 8;
363 struct in6_addr *addr = (struct in6_addr *)dst;
364 int i, len;
365
366 if (*src == ':') {
367 /* Ignore a leading colon, makes parsing neater */
368 src++;
369 }
370
371 len = strlen(src);
372 for (i = 0; i < len; i++) {
373 if (!(src[i] >= '0' && src[i] <= '9') &&
374 !(src[i] >= 'A' && src[i] <= 'F') &&
375 !(src[i] >= 'a' && src[i] <= 'f') &&
376 src[i] != '.' && src[i] != ':') {
377 return -EINVAL;
378 }
379 }
380
381 for (i = 0; i < expected_groups; i++) {
382 char *tmp;
383
384 if (!src || *src == '\0') {
385 return -EINVAL;
386 }
387
388 if (*src != ':') {
389 /* Normal IPv6 16-bit piece */
390 UNALIGNED_PUT(htons(strtol(src, NULL, 16)),
391 &addr->s6_addr16[i]);
392 src = strchr(src, ':');
393 if (src) {
394 src++;
395 } else {
396 if (i < expected_groups - 1) {
397 return -EINVAL;
398 }
399 }
400
401 continue;
402 }
403
404 /* Two colons in a row */
405
406 for (; i < expected_groups; i++) {
407 UNALIGNED_PUT(0, &addr->s6_addr16[i]);
408 }
409
410 tmp = strrchr(src, ':');
411 if (src == tmp && (expected_groups == 6 || !src[1])) {
412 src++;
413 break;
414 }
415
416 if (expected_groups == 6) {
417 /* we need to drop the trailing
418 * colon since it's between the
419 * ipv6 and ipv4 addresses, rather than being
420 * a part of the ipv6 address
421 */
422 tmp--;
423 }
424
425 /* Calculate the amount of skipped zeros */
426 i = expected_groups - 1;
427 do {
428 if (*tmp == ':') {
429 i--;
430 }
431
432 if (i < 0) {
433 return -EINVAL;
434 }
435 } while (tmp-- != src);
436
437 src++;
438 }
439
440 if (expected_groups == 6) {
441 /* Parse the IPv4 part */
442 for (i = 0; i < 4; i++) {
443 if (!src || !*src) {
444 return -EINVAL;
445 }
446
447 addr->s6_addr[12 + i] = strtol(src, NULL, 10);
448
449 src = strchr(src, '.');
450 if (src) {
451 src++;
452 } else {
453 if (i < 3) {
454 return -EINVAL;
455 }
456 }
457 }
458 }
459 } else {
460 return -EINVAL;
461 }
462
463 return 0;
464 }
465
466 #if defined(CONFIG_USERSPACE)
z_vrfy_net_addr_pton(sa_family_t family,const char * src,void * dst)467 int z_vrfy_net_addr_pton(sa_family_t family, const char *src,
468 void *dst)
469 {
470 char str[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)] = {};
471 struct in6_addr addr6;
472 struct in_addr addr4;
473 void *addr;
474 size_t size;
475 int err;
476
477 if (family == AF_INET) {
478 size = sizeof(struct in_addr);
479 addr = &addr4;
480 } else if (family == AF_INET6) {
481 size = sizeof(struct in6_addr);
482 addr = &addr6;
483 } else {
484 return -EINVAL;
485 }
486
487 if (k_usermode_string_copy(str, (char *)src, sizeof(str)) != 0) {
488 return -EINVAL;
489 }
490
491 K_OOPS(K_SYSCALL_MEMORY_WRITE(dst, size));
492
493 err = z_impl_net_addr_pton(family, str, addr);
494 if (err) {
495 return err;
496 }
497
498 K_OOPS(k_usermode_to_copy((void *)dst, addr, size));
499
500 return 0;
501 }
502 #include <zephyr/syscalls/net_addr_pton_mrsh.c>
503 #endif /* CONFIG_USERSPACE */
504
505
506 #ifdef CONFIG_LITTLE_ENDIAN
507 #define CHECKSUM_BIG_ENDIAN 0
508 #else
509 #define CHECKSUM_BIG_ENDIAN 1
510 #endif
511
offset_based_swap8(const uint8_t * data)512 static uint16_t offset_based_swap8(const uint8_t *data)
513 {
514 uint16_t data16 = (uint16_t)*data;
515
516 if (((uintptr_t)(data) & 1) == CHECKSUM_BIG_ENDIAN) {
517 return data16;
518 } else {
519 return data16 << 8;
520 }
521 }
522
523 /* Word based checksum calculation based on:
524 * https://blogs.igalia.com/dpino/2018/06/14/fast-checksum-computation/
525 * It’s not necessary to add octets as 16-bit words. Due to the associative property of addition,
526 * it is possible to do parallel addition using larger word sizes such as 32-bit or 64-bit words.
527 * In those cases the variable that stores the accumulative sum has to be bigger too.
528 * Once the sum is computed a final step folds the sum to a 16-bit word (adding carry if any).
529 */
calc_chksum(uint16_t sum_in,const uint8_t * data,size_t len)530 uint16_t calc_chksum(uint16_t sum_in, const uint8_t *data, size_t len)
531 {
532 uint64_t sum;
533 uint32_t *p;
534 size_t i = 0;
535 size_t pending = len;
536 int odd_start = ((uintptr_t)data & 0x01);
537
538 /* Sum in is in host endianness, working order endianness is both dependent on endianness
539 * and the offset of starting
540 */
541 if (odd_start == CHECKSUM_BIG_ENDIAN) {
542 sum = BSWAP_16(sum_in);
543 } else {
544 sum = sum_in;
545 }
546
547 /* Process up to 3 data elements up front, so the data is aligned further down the line */
548 if ((((uintptr_t)data & 0x01) != 0) && (pending >= 1)) {
549 sum += offset_based_swap8(data);
550 data++;
551 pending--;
552 }
553 if ((((uintptr_t)data & 0x02) != 0) && (pending >= sizeof(uint16_t))) {
554 pending -= sizeof(uint16_t);
555 sum = sum + *((uint16_t *)data);
556 data += sizeof(uint16_t);
557 }
558 p = (uint32_t *)data;
559
560 /* Do loop unrolling for the very large data sets */
561 while (pending >= sizeof(uint32_t) * 4) {
562 uint64_t sum_a = p[i];
563 uint64_t sum_b = p[i + 1];
564
565 pending -= sizeof(uint32_t) * 4;
566 sum_a += p[i + 2];
567 sum_b += p[i + 3];
568 i += 4;
569 sum += sum_a + sum_b;
570 }
571 while (pending >= sizeof(uint32_t)) {
572 pending -= sizeof(uint32_t);
573 sum = sum + p[i++];
574 }
575 data = (uint8_t *)(p + i);
576 if (pending >= 2) {
577 pending -= sizeof(uint16_t);
578 sum = sum + *((uint16_t *)data);
579 data += sizeof(uint16_t);
580 }
581 if (pending == 1) {
582 sum += offset_based_swap8(data);
583 }
584
585 /* Fold sum into 16-bit word. */
586 while (sum >> 16) {
587 sum = (sum & 0xffff) + (sum >> 16);
588 }
589
590 /* Sum in is in host endianness, working order endianness is both dependent on endianness
591 * and the offset of starting
592 */
593 if (odd_start == CHECKSUM_BIG_ENDIAN) {
594 return BSWAP_16((uint16_t)sum);
595 } else {
596 return sum;
597 }
598 }
599
pkt_calc_chksum(struct net_pkt * pkt,uint16_t sum)600 static inline uint16_t pkt_calc_chksum(struct net_pkt *pkt, uint16_t sum)
601 {
602 struct net_pkt_cursor *cur = &pkt->cursor;
603 size_t len;
604
605 if (!cur->buf || !cur->pos) {
606 return sum;
607 }
608
609 len = cur->buf->len - (cur->pos - cur->buf->data);
610
611 while (cur->buf) {
612 sum = calc_chksum(sum, cur->pos, len);
613
614 cur->buf = cur->buf->frags;
615 if (!cur->buf || !cur->buf->len) {
616 break;
617 }
618
619 cur->pos = cur->buf->data;
620
621 if (len % 2) {
622 sum += *cur->pos;
623 if (sum < *cur->pos) {
624 sum++;
625 }
626
627 cur->pos++;
628 len = cur->buf->len - 1;
629 } else {
630 len = cur->buf->len;
631 }
632 }
633
634 return sum;
635 }
636
637 #if defined(CONFIG_NET_NATIVE_IP)
net_calc_chksum(struct net_pkt * pkt,uint8_t proto)638 uint16_t net_calc_chksum(struct net_pkt *pkt, uint8_t proto)
639 {
640 size_t len = 0U;
641 uint16_t sum = 0U;
642 struct net_pkt_cursor backup;
643 bool ow;
644
645 if (IS_ENABLED(CONFIG_NET_IPV4) &&
646 net_pkt_family(pkt) == AF_INET) {
647 if (proto != IPPROTO_ICMP && proto != IPPROTO_IGMP) {
648 len = 2 * sizeof(struct in_addr);
649 sum = net_pkt_get_len(pkt) -
650 net_pkt_ip_hdr_len(pkt) -
651 net_pkt_ipv4_opts_len(pkt) + proto;
652 }
653 } else if (IS_ENABLED(CONFIG_NET_IPV6) &&
654 net_pkt_family(pkt) == AF_INET6) {
655 len = 2 * sizeof(struct in6_addr);
656 sum = net_pkt_get_len(pkt) -
657 net_pkt_ip_hdr_len(pkt) -
658 net_pkt_ipv6_ext_len(pkt) + proto;
659 } else {
660 NET_DBG("Unknown protocol family %d", net_pkt_family(pkt));
661 return 0;
662 }
663
664 net_pkt_cursor_backup(pkt, &backup);
665 net_pkt_cursor_init(pkt);
666
667 ow = net_pkt_is_being_overwritten(pkt);
668 net_pkt_set_overwrite(pkt, true);
669
670 net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) - len);
671
672 sum = calc_chksum(sum, pkt->cursor.pos, len);
673 net_pkt_skip(pkt, len + net_pkt_ip_opts_len(pkt));
674
675 sum = pkt_calc_chksum(pkt, sum);
676
677 sum = (sum == 0U) ? 0xffff : htons(sum);
678
679 net_pkt_cursor_restore(pkt, &backup);
680
681 net_pkt_set_overwrite(pkt, ow);
682
683 return ~sum;
684 }
685 #endif
686
687 #if defined(CONFIG_NET_NATIVE_IPV4)
net_calc_chksum_ipv4(struct net_pkt * pkt)688 uint16_t net_calc_chksum_ipv4(struct net_pkt *pkt)
689 {
690 uint16_t sum;
691
692 sum = calc_chksum(0, pkt->buffer->data,
693 net_pkt_ip_hdr_len(pkt) +
694 net_pkt_ipv4_opts_len(pkt));
695
696 sum = (sum == 0U) ? 0xffff : htons(sum);
697
698 return ~sum;
699 }
700 #endif /* CONFIG_NET_NATIVE_IPV4 */
701
702 #if defined(CONFIG_NET_IPV4_IGMP)
net_calc_chksum_igmp(struct net_pkt * pkt)703 uint16_t net_calc_chksum_igmp(struct net_pkt *pkt)
704 {
705 return net_calc_chksum(pkt, IPPROTO_IGMP);
706 }
707 #endif /* CONFIG_NET_IPV4_IGMP */
708
709 #if defined(CONFIG_NET_IP)
convert_port(const char * buf,uint16_t * port)710 static bool convert_port(const char *buf, uint16_t *port)
711 {
712 unsigned long tmp;
713 char *endptr;
714
715 tmp = strtoul(buf, &endptr, 10);
716 if ((endptr == buf && tmp == 0) ||
717 !(*buf != '\0' && *endptr == '\0') ||
718 ((unsigned long)(unsigned short)tmp != tmp)) {
719 return false;
720 }
721
722 *port = tmp;
723
724 return true;
725 }
726 #endif /* CONFIG_NET_IP */
727
728 #if defined(CONFIG_NET_IPV6)
parse_ipv6(const char * str,size_t str_len,struct sockaddr * addr,bool has_port)729 static bool parse_ipv6(const char *str, size_t str_len,
730 struct sockaddr *addr, bool has_port)
731 {
732 char *ptr = NULL;
733 struct in6_addr *addr6;
734 char ipaddr[INET6_ADDRSTRLEN + 1];
735 int end, len, ret, i;
736 uint16_t port;
737
738 len = MIN(INET6_ADDRSTRLEN, str_len);
739
740 for (i = 0; i < len; i++) {
741 if (!str[i]) {
742 len = i;
743 break;
744 }
745 }
746
747 if (has_port) {
748 /* IPv6 address with port number */
749 ptr = memchr(str, ']', len);
750 if (!ptr) {
751 return false;
752 }
753
754 end = MIN(len, ptr - (str + 1));
755 memcpy(ipaddr, str + 1, end);
756 } else {
757 end = len;
758 memcpy(ipaddr, str, end);
759 }
760
761 ipaddr[end] = '\0';
762
763 addr6 = &net_sin6(addr)->sin6_addr;
764
765 ret = net_addr_pton(AF_INET6, ipaddr, addr6);
766 if (ret < 0) {
767 return false;
768 }
769
770 net_sin6(addr)->sin6_family = AF_INET6;
771
772 if (!has_port) {
773 return true;
774 }
775
776 if ((ptr + 1) < (str + str_len) && *(ptr + 1) == ':') {
777 /* -1 as end does not contain first [
778 * -2 as pointer is advanced by 2, skipping ]:
779 */
780 len = str_len - end - 1 - 2;
781
782 ptr += 2;
783
784 for (i = 0; i < len; i++) {
785 if (!ptr[i]) {
786 len = i;
787 break;
788 }
789 }
790
791 /* Re-use the ipaddr buf for port conversion */
792 memcpy(ipaddr, ptr, len);
793 ipaddr[len] = '\0';
794
795 ret = convert_port(ipaddr, &port);
796 if (!ret) {
797 return false;
798 }
799
800 net_sin6(addr)->sin6_port = htons(port);
801
802 NET_DBG("IPv6 host %s port %d",
803 net_addr_ntop(AF_INET6, addr6, ipaddr, sizeof(ipaddr) - 1),
804 port);
805 } else {
806 NET_DBG("IPv6 host %s",
807 net_addr_ntop(AF_INET6, addr6, ipaddr, sizeof(ipaddr) - 1));
808 }
809
810 return true;
811 }
812 #else
parse_ipv6(const char * str,size_t str_len,struct sockaddr * addr,bool has_port)813 static inline bool parse_ipv6(const char *str, size_t str_len,
814 struct sockaddr *addr, bool has_port)
815 {
816 return false;
817 }
818 #endif /* CONFIG_NET_IPV6 */
819
820 #if defined(CONFIG_NET_IPV4)
parse_ipv4(const char * str,size_t str_len,struct sockaddr * addr,bool has_port)821 static bool parse_ipv4(const char *str, size_t str_len,
822 struct sockaddr *addr, bool has_port)
823 {
824 char *ptr = NULL;
825 char ipaddr[NET_IPV4_ADDR_LEN + 1];
826 struct in_addr *addr4;
827 int end, len, ret, i;
828 uint16_t port;
829
830 len = MIN(NET_IPV4_ADDR_LEN, str_len);
831
832 for (i = 0; i < len; i++) {
833 if (!str[i]) {
834 len = i;
835 break;
836 }
837 }
838
839 if (has_port) {
840 /* IPv4 address with port number */
841 ptr = memchr(str, ':', len);
842 if (!ptr) {
843 return false;
844 }
845
846 end = MIN(len, ptr - str);
847 } else {
848 end = len;
849 }
850
851 memcpy(ipaddr, str, end);
852 ipaddr[end] = '\0';
853
854 addr4 = &net_sin(addr)->sin_addr;
855
856 ret = net_addr_pton(AF_INET, ipaddr, addr4);
857 if (ret < 0) {
858 return false;
859 }
860
861 net_sin(addr)->sin_family = AF_INET;
862
863 if (!has_port) {
864 return true;
865 }
866
867 memcpy(ipaddr, ptr + 1, str_len - end - 1);
868 ipaddr[str_len - end - 1] = '\0';
869
870 ret = convert_port(ipaddr, &port);
871 if (!ret) {
872 return false;
873 }
874
875 net_sin(addr)->sin_port = htons(port);
876
877 NET_DBG("IPv4 host %s port %d",
878 net_addr_ntop(AF_INET, addr4, ipaddr, sizeof(ipaddr) - 1),
879 port);
880 return true;
881 }
882 #else
parse_ipv4(const char * str,size_t str_len,struct sockaddr * addr,bool has_port)883 static inline bool parse_ipv4(const char *str, size_t str_len,
884 struct sockaddr *addr, bool has_port)
885 {
886 return false;
887 }
888 #endif /* CONFIG_NET_IPV4 */
889
net_ipaddr_parse(const char * str,size_t str_len,struct sockaddr * addr)890 bool net_ipaddr_parse(const char *str, size_t str_len, struct sockaddr *addr)
891 {
892 int i, count;
893
894 if (!str || str_len == 0) {
895 return false;
896 }
897
898 /* We cannot accept empty string here */
899 if (*str == '\0') {
900 return false;
901 }
902
903 if (*str == '[') {
904 return parse_ipv6(str, str_len, addr, true);
905 }
906
907 for (count = i = 0; i < str_len && str[i]; i++) {
908 if (str[i] == ':') {
909 count++;
910 }
911 }
912
913 if (count == 1) {
914 return parse_ipv4(str, str_len, addr, true);
915 }
916
917 #if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_IPV6)
918 if (!parse_ipv4(str, str_len, addr, false)) {
919 return parse_ipv6(str, str_len, addr, false);
920 }
921
922 return true;
923 #endif
924
925 #if defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
926 return parse_ipv4(str, str_len, addr, false);
927 #endif
928
929 #if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4)
930 return parse_ipv6(str, str_len, addr, false);
931 #endif
932 return false;
933 }
934
net_port_set_default(struct sockaddr * addr,uint16_t default_port)935 int net_port_set_default(struct sockaddr *addr, uint16_t default_port)
936 {
937 if (IS_ENABLED(CONFIG_NET_IPV4) && addr->sa_family == AF_INET &&
938 net_sin(addr)->sin_port == 0) {
939 net_sin(addr)->sin_port = htons(default_port);
940 } else if (IS_ENABLED(CONFIG_NET_IPV6) && addr->sa_family == AF_INET6 &&
941 net_sin6(addr)->sin6_port == 0) {
942 net_sin6(addr)->sin6_port = htons(default_port);
943 } else if ((IS_ENABLED(CONFIG_NET_IPV4) && addr->sa_family == AF_INET) ||
944 (IS_ENABLED(CONFIG_NET_IPV6) && addr->sa_family == AF_INET6)) {
945 ; /* Port is already set */
946 } else {
947 LOG_ERR("Unknown address family");
948 return -EINVAL;
949 }
950
951 return 0;
952 }
953
net_bytes_from_str(uint8_t * buf,int buf_len,const char * src)954 int net_bytes_from_str(uint8_t *buf, int buf_len, const char *src)
955 {
956 size_t i;
957 size_t src_len = strlen(src);
958 char *endptr;
959
960 for (i = 0U; i < src_len; i++) {
961 if (!isxdigit((unsigned char)src[i]) &&
962 src[i] != ':') {
963 return -EINVAL;
964 }
965 }
966
967 (void)memset(buf, 0, buf_len);
968
969 for (i = 0U; i < (size_t)buf_len; i++) {
970 buf[i] = (uint8_t)strtol(src, &endptr, 16);
971 src = ++endptr;
972 }
973
974 return 0;
975 }
976
net_family2str(sa_family_t family)977 const char *net_family2str(sa_family_t family)
978 {
979 switch (family) {
980 case AF_UNSPEC:
981 return "AF_UNSPEC";
982 case AF_INET:
983 return "AF_INET";
984 case AF_INET6:
985 return "AF_INET6";
986 case AF_PACKET:
987 return "AF_PACKET";
988 case AF_CAN:
989 return "AF_CAN";
990 }
991
992 return NULL;
993 }
994
net_ipv4_unspecified_address(void)995 const struct in_addr *net_ipv4_unspecified_address(void)
996 {
997 static const struct in_addr addr;
998
999 return &addr;
1000 }
1001
net_ipv4_broadcast_address(void)1002 const struct in_addr *net_ipv4_broadcast_address(void)
1003 {
1004 static const struct in_addr addr = { { { 255, 255, 255, 255 } } };
1005
1006 return &addr;
1007 }
1008
1009 /* IPv6 wildcard and loopback address defined by RFC2553 */
1010 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
1011 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
1012
net_ipv6_unspecified_address(void)1013 const struct in6_addr *net_ipv6_unspecified_address(void)
1014 {
1015 return &in6addr_any;
1016 }
1017