1 /** @file
2 * @brief Network initialization
3 *
4 * Initialize the network IP stack. Create one thread for reading data
5 * from IP stack and passing that data to applications (Rx thread).
6 */
7
8 /*
9 * Copyright (c) 2016 Intel Corporation
10 * Copyright (c) 2025 Aerlync Labs Inc.
11 *
12 * SPDX-License-Identifier: Apache-2.0
13 */
14
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(net_core, CONFIG_NET_CORE_LOG_LEVEL);
17
18 #include <zephyr/init.h>
19 #include <zephyr/kernel.h>
20 #include <zephyr/tracing/tracing.h>
21 #include <zephyr/toolchain.h>
22 #include <zephyr/linker/sections.h>
23 #include <string.h>
24 #include <errno.h>
25
26 #include <zephyr/net/conn_mgr_connectivity.h>
27 #include <zephyr/net/ipv4_autoconf.h>
28 #include <zephyr/net/net_if.h>
29 #include <zephyr/net/net_mgmt.h>
30 #include <zephyr/net/net_pkt.h>
31 #include <zephyr/net/net_core.h>
32 #include <zephyr/net/dns_resolve.h>
33 #include <zephyr/net/gptp.h>
34 #include <zephyr/net/websocket.h>
35 #include <zephyr/net/ethernet.h>
36 #if defined(CONFIG_NET_DSA) && !defined(CONFIG_NET_DSA_DEPRECATED)
37 #include <zephyr/net/dsa_core.h>
38 #endif
39 #include <zephyr/net/capture.h>
40
41 #if defined(CONFIG_NET_LLDP)
42 #include <zephyr/net/lldp.h>
43 #endif
44
45 #include "net_private.h"
46 #include "shell/net_shell.h"
47
48 #include "pmtu.h"
49
50 #include "icmpv6.h"
51 #include "ipv6.h"
52
53 #include "icmpv4.h"
54 #include "ipv4.h"
55
56 #include "dhcpv4/dhcpv4_internal.h"
57 #include "dhcpv6/dhcpv6_internal.h"
58
59 #include "route.h"
60
61 #include "packet_socket.h"
62 #include "canbus_socket.h"
63
64 #include "connection.h"
65 #include "udp_internal.h"
66 #include "tcp_internal.h"
67
68 #include "net_stats.h"
69
70 #if defined(CONFIG_NET_NATIVE)
process_data(struct net_pkt * pkt)71 static inline enum net_verdict process_data(struct net_pkt *pkt)
72 {
73 int ret;
74
75 net_packet_socket_input(pkt, ETH_P_ALL, NET_SOCK_RAW);
76
77 /* If there is no data, then drop the packet. */
78 if (!pkt->frags) {
79 NET_DBG("Corrupted packet (frags %p)", pkt->frags);
80 net_stats_update_processing_error(net_pkt_iface(pkt));
81
82 return NET_DROP;
83 }
84
85 if (!net_pkt_is_l2_processed(pkt)) {
86 ret = net_if_recv_data(net_pkt_iface(pkt), pkt);
87 if (ret != NET_CONTINUE) {
88 if (ret == NET_DROP) {
89 NET_DBG("Packet %p discarded by L2", pkt);
90 net_stats_update_processing_error(
91 net_pkt_iface(pkt));
92 }
93
94 return ret;
95 }
96 }
97
98 net_pkt_set_l2_processed(pkt, true);
99
100 /* L2 has modified the buffer starting point, it is easier
101 * to re-initialize the cursor rather than updating it.
102 */
103 net_pkt_cursor_init(pkt);
104
105 if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET_DGRAM)) {
106 net_packet_socket_input(pkt, net_pkt_ll_proto_type(pkt), NET_SOCK_DGRAM);
107 }
108
109 uint8_t family = net_pkt_family(pkt);
110
111 if (IS_ENABLED(CONFIG_NET_IP) && (family == NET_AF_INET || family == NET_AF_INET6 ||
112 family == NET_AF_UNSPEC || family == NET_AF_PACKET)) {
113 /* IP version and header length. */
114 uint8_t vtc_vhl = NET_IPV6_HDR(pkt)->vtc & 0xf0;
115
116 if (IS_ENABLED(CONFIG_NET_IPV6) && vtc_vhl == 0x60) {
117 return net_ipv6_input(pkt);
118 } else if (IS_ENABLED(CONFIG_NET_IPV4) && vtc_vhl == 0x40) {
119 return net_ipv4_input(pkt);
120 }
121
122 NET_DBG("Unknown IP family packet (0x%x)", NET_IPV6_HDR(pkt)->vtc & 0xf0);
123 net_stats_update_ip_errors_protoerr(net_pkt_iface(pkt));
124 net_stats_update_ip_errors_vhlerr(net_pkt_iface(pkt));
125 return NET_DROP;
126 } else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) && family == NET_AF_CAN) {
127 return net_canbus_socket_input(pkt);
128 }
129
130 NET_DBG("Unknown protocol family packet (0x%x)", family);
131 return NET_DROP;
132 }
133
processing_data(struct net_pkt * pkt)134 static void processing_data(struct net_pkt *pkt)
135 {
136 again:
137 switch (process_data(pkt)) {
138 case NET_CONTINUE:
139 if (IS_ENABLED(CONFIG_NET_L2_VIRTUAL)) {
140 /* If we have a tunneling packet, feed it back
141 * to the stack in this case.
142 */
143 goto again;
144 } else {
145 NET_DBG("Dropping pkt %p", pkt);
146 net_pkt_unref(pkt);
147 }
148 break;
149 case NET_OK:
150 NET_DBG("Consumed pkt %p", pkt);
151 break;
152 case NET_DROP:
153 default:
154 NET_DBG("Dropping pkt %p", pkt);
155 net_pkt_unref(pkt);
156 break;
157 }
158 }
159
160 /* Things to setup after we are able to RX and TX */
net_post_init(void)161 static void net_post_init(void)
162 {
163 #if defined(CONFIG_NET_LLDP)
164 net_lldp_init();
165 #endif
166 #if defined(CONFIG_NET_GPTP)
167 net_gptp_init();
168 #endif
169 }
170
copy_ll_addr(struct net_pkt * pkt)171 static inline void copy_ll_addr(struct net_pkt *pkt)
172 {
173 memcpy(net_pkt_lladdr_src(pkt), net_pkt_lladdr_if(pkt),
174 sizeof(struct net_linkaddr));
175 memcpy(net_pkt_lladdr_dst(pkt), net_pkt_lladdr_if(pkt),
176 sizeof(struct net_linkaddr));
177 }
178
179 /* Check if the IPv{4|6} addresses are proper. As this can be expensive,
180 * make this optional. We still check the IPv4 TTL and IPv6 hop limit
181 * if the corresponding protocol family is enabled.
182 */
check_ip(struct net_pkt * pkt)183 static inline int check_ip(struct net_pkt *pkt)
184 {
185 uint8_t family;
186 int ret;
187
188 if (!IS_ENABLED(CONFIG_NET_IP)) {
189 return 0;
190 }
191
192 family = net_pkt_family(pkt);
193 ret = 0;
194
195 if (IS_ENABLED(CONFIG_NET_IPV6) && family == NET_AF_INET6 &&
196 net_pkt_ll_proto_type(pkt) == NET_ETH_PTYPE_IPV6) {
197 /* Drop IPv6 packet if hop limit is 0 */
198 if (NET_IPV6_HDR(pkt)->hop_limit == 0) {
199 NET_DBG("DROP: IPv6 hop limit");
200 ret = -ENOMSG; /* silently drop the pkt, not an error */
201 goto drop;
202 }
203
204 if (!IS_ENABLED(CONFIG_NET_IP_ADDR_CHECK)) {
205 return 0;
206 }
207
208 #if defined(CONFIG_NET_LOOPBACK)
209 /* If loopback driver is enabled, then send packets to it
210 * as the address check is not needed.
211 */
212 if (net_if_l2(net_pkt_iface(pkt)) == &NET_L2_GET_NAME(DUMMY)) {
213 return 0;
214 }
215 #endif
216 if (net_ipv6_addr_cmp_raw(NET_IPV6_HDR(pkt)->dst,
217 (const uint8_t *)net_ipv6_unspecified_address())) {
218 NET_DBG("DROP: IPv6 dst address missing");
219 ret = -EADDRNOTAVAIL;
220 goto drop;
221 }
222
223 /* If the destination address is our own, then route it
224 * back to us (if it is not already forwarded).
225 */
226 if ((net_ipv6_is_addr_loopback_raw(NET_IPV6_HDR(pkt)->dst) ||
227 net_ipv6_is_my_addr_raw(NET_IPV6_HDR(pkt)->dst)) &&
228 !net_pkt_forwarding(pkt)) {
229 struct net_in6_addr addr;
230
231 /* Swap the addresses so that in receiving side
232 * the packet is accepted.
233 */
234 net_ipv6_addr_copy_raw((uint8_t *)&addr, NET_IPV6_HDR(pkt)->src);
235 net_ipv6_addr_copy_raw(NET_IPV6_HDR(pkt)->src,
236 NET_IPV6_HDR(pkt)->dst);
237 net_ipv6_addr_copy_raw(NET_IPV6_HDR(pkt)->dst, (uint8_t *)&addr);
238
239 net_pkt_set_ll_proto_type(pkt, ETH_P_IPV6);
240 copy_ll_addr(pkt);
241
242 return 1;
243 }
244
245 /* If the destination address is interface local scope
246 * multicast address, then loop the data back to us.
247 * The FF01:: multicast addresses are only meant to be used
248 * in local host, so this is similar as how ::1 unicast
249 * addresses are handled. See RFC 3513 ch 2.7 for details.
250 */
251 if (net_ipv6_is_addr_mcast_iface_raw(NET_IPV6_HDR(pkt)->dst)) {
252 NET_DBG("IPv6 interface scope mcast dst address");
253 return 1;
254 }
255
256 /* The source check must be done after the destination check
257 * as having src ::1 is perfectly ok if dst is ::1 too.
258 */
259 if (net_ipv6_is_addr_loopback_raw(NET_IPV6_HDR(pkt)->src)) {
260 NET_DBG("DROP: IPv6 loopback src address");
261 ret = -EADDRNOTAVAIL;
262 goto drop;
263 }
264
265 } else if (IS_ENABLED(CONFIG_NET_IPV4) && family == NET_AF_INET &&
266 net_pkt_ll_proto_type(pkt) == NET_ETH_PTYPE_IP) {
267 /* Drop IPv4 packet if ttl is 0 */
268 if (NET_IPV4_HDR(pkt)->ttl == 0) {
269 NET_DBG("DROP: IPv4 ttl");
270 ret = -ENOMSG; /* silently drop the pkt, not an error */
271 goto drop;
272 }
273
274 if (!IS_ENABLED(CONFIG_NET_IP_ADDR_CHECK)) {
275 return 0;
276 }
277
278 #if defined(CONFIG_NET_LOOPBACK)
279 /* If loopback driver is enabled, then send packets to it
280 * as the address check is not needed.
281 */
282 if (net_if_l2(net_pkt_iface(pkt)) == &NET_L2_GET_NAME(DUMMY)) {
283 return 0;
284 }
285 #endif
286 if (net_ipv4_addr_cmp_raw(NET_IPV4_HDR(pkt)->dst,
287 net_ipv4_unspecified_address()->s4_addr)) {
288 NET_DBG("DROP: IPv4 dst address missing");
289 ret = -EADDRNOTAVAIL;
290 goto drop;
291 }
292
293 /* If the destination address is our own, then route it
294 * back to us.
295 */
296 if (net_ipv4_is_addr_loopback_raw(NET_IPV4_HDR(pkt)->dst) ||
297 (net_ipv4_is_addr_bcast_raw(net_pkt_iface(pkt),
298 NET_IPV4_HDR(pkt)->dst) == false &&
299 net_ipv4_is_my_addr_raw(NET_IPV4_HDR(pkt)->dst))) {
300 struct net_in_addr addr;
301
302 /* Swap the addresses so that in receiving side
303 * the packet is accepted.
304 */
305 net_ipv4_addr_copy_raw((uint8_t *)&addr, NET_IPV4_HDR(pkt)->src);
306 net_ipv4_addr_copy_raw(NET_IPV4_HDR(pkt)->src,
307 NET_IPV4_HDR(pkt)->dst);
308 net_ipv4_addr_copy_raw(NET_IPV4_HDR(pkt)->dst, (uint8_t *)&addr);
309
310 net_pkt_set_ll_proto_type(pkt, ETH_P_IP);
311 copy_ll_addr(pkt);
312
313 return 1;
314 }
315
316 /* The source check must be done after the destination check
317 * as having src 127.0.0.0/8 is perfectly ok if dst is in
318 * localhost subnet too.
319 */
320 if (net_ipv4_is_addr_loopback_raw(NET_IPV4_HDR(pkt)->src)) {
321 NET_DBG("DROP: IPv4 loopback src address");
322 ret = -EADDRNOTAVAIL;
323 goto drop;
324 }
325 }
326
327 return ret;
328
329 drop:
330 if (IS_ENABLED(CONFIG_NET_STATISTICS)) {
331 if (family == NET_AF_INET6) {
332 net_stats_update_ipv6_drop(net_pkt_iface(pkt));
333 } else {
334 net_stats_update_ipv4_drop(net_pkt_iface(pkt));
335 }
336 }
337
338 return ret;
339 }
340
341 #if defined(CONFIG_NET_IPV4) || defined(CONFIG_NET_IPV6)
process_multicast(struct net_pkt * pkt)342 static inline bool process_multicast(struct net_pkt *pkt)
343 {
344 struct net_context *ctx = net_pkt_context(pkt);
345 net_sa_family_t family = net_pkt_family(pkt);
346
347 if (ctx == NULL) {
348 return false;
349 }
350
351 #if defined(CONFIG_NET_IPV4)
352 if (family == NET_AF_INET) {
353 const struct net_in_addr *dst = (const struct net_in_addr *)&NET_IPV4_HDR(pkt)->dst;
354
355 return net_ipv4_is_addr_mcast(dst) && net_context_get_ipv4_mcast_loop(ctx);
356 }
357 #endif
358 #if defined(CONFIG_NET_IPV6)
359 if (family == NET_AF_INET6) {
360 return net_ipv6_is_addr_mcast_raw(NET_IPV6_HDR(pkt)->dst) &&
361 net_context_get_ipv6_mcast_loop(ctx);
362 }
363 #endif
364 return false;
365 }
366 #endif
367
net_try_send_data(struct net_pkt * pkt,k_timeout_t timeout)368 int net_try_send_data(struct net_pkt *pkt, k_timeout_t timeout)
369 {
370 struct net_if *iface;
371 int family;
372 int status;
373 int ret;
374
375 SYS_PORT_TRACING_FUNC_ENTER(net, send_data, pkt);
376
377 if (!pkt || !pkt->frags) {
378 ret = -ENODATA;
379 goto err;
380 }
381
382 if (!net_pkt_iface(pkt)) {
383 ret = -EINVAL;
384 goto err;
385 }
386
387 if (!net_if_is_up(net_pkt_iface(pkt))) {
388 ret = -ENETDOWN;
389 goto err;
390 }
391
392 net_pkt_trim_buffer(pkt);
393 net_pkt_cursor_init(pkt);
394
395 status = check_ip(pkt);
396 if (status < 0) {
397 /* Special handling for ENOMSG which is returned if packet
398 * TTL is 0 or hop limit is 0. This is not an error as it is
399 * perfectly valid case to set the limit to 0. In this case
400 * we just silently drop the packet by returning 0.
401 */
402 if (status == -ENOMSG) {
403 net_pkt_unref(pkt);
404 ret = 0;
405 goto err;
406 }
407
408 return status;
409 } else if (status > 0) {
410 /* Packet is destined back to us so send it directly
411 * to RX processing.
412 */
413 NET_DBG("Loopback pkt %p back to us", pkt);
414 net_pkt_set_loopback(pkt, true);
415 net_pkt_set_l2_processed(pkt, true);
416 processing_data(pkt);
417 ret = 0;
418 goto err;
419 }
420
421 #if defined(CONFIG_NET_IPV4) || defined(CONFIG_NET_IPV6)
422 if (process_multicast(pkt)) {
423 struct net_pkt *clone = net_pkt_clone(pkt, K_NO_WAIT);
424
425 if (clone != NULL) {
426 net_pkt_set_iface(clone, net_pkt_iface(pkt));
427 if (net_recv_data(net_pkt_iface(clone), clone) < 0) {
428 if (IS_ENABLED(CONFIG_NET_STATISTICS)) {
429 switch (net_pkt_family(pkt)) {
430 #if defined(CONFIG_NET_IPV4)
431 case NET_AF_INET:
432 net_stats_update_ipv4_sent(net_pkt_iface(pkt));
433 break;
434 #endif
435 #if defined(CONFIG_NET_IPV6)
436 case NET_AF_INET6:
437 net_stats_update_ipv6_sent(net_pkt_iface(pkt));
438 break;
439 #endif
440 }
441 }
442 net_pkt_unref(clone);
443 }
444 } else {
445 NET_DBG("Failed to clone multicast packet");
446 }
447 }
448 #endif
449
450 /* The pkt might contain garbage already after the call to
451 * net_if_try_send_data(), so do not use pkt after that call.
452 * Remember the iface and family for statistics update.
453 */
454 if (IS_ENABLED(CONFIG_NET_STATISTICS)) {
455 iface = net_pkt_iface(pkt);
456 family = net_pkt_family(pkt);
457 }
458
459 if (net_if_try_send_data(net_pkt_iface(pkt), pkt, timeout) == NET_DROP) {
460 ret = -EIO;
461 goto err;
462 }
463
464 if (IS_ENABLED(CONFIG_NET_STATISTICS)) {
465 switch (family) {
466 case NET_AF_INET:
467 net_stats_update_ipv4_sent(iface);
468 break;
469 case NET_AF_INET6:
470 net_stats_update_ipv6_sent(iface);
471 break;
472 }
473 }
474
475 ret = 0;
476
477 err:
478 SYS_PORT_TRACING_FUNC_EXIT(net, send_data, pkt, ret);
479
480 return ret;
481 }
482
net_rx(struct net_if * iface,struct net_pkt * pkt)483 static void net_rx(struct net_if *iface, struct net_pkt *pkt)
484 {
485 size_t pkt_len;
486
487 pkt_len = net_pkt_get_len(pkt);
488
489 NET_DBG("Received pkt %p len %zu", pkt, pkt_len);
490
491 net_stats_update_bytes_recv(iface, pkt_len);
492 conn_mgr_if_used(iface);
493
494 if (IS_ENABLED(CONFIG_NET_LOOPBACK)) {
495 #ifdef CONFIG_NET_L2_DUMMY
496 if (net_if_l2(iface) == &NET_L2_GET_NAME(DUMMY)) {
497 net_pkt_set_loopback(pkt, true);
498 net_pkt_set_l2_processed(pkt, true);
499 }
500 #endif
501 }
502
503 processing_data(pkt);
504
505 net_print_statistics();
506 net_pkt_print();
507 }
508
net_process_rx_packet(struct net_pkt * pkt)509 void net_process_rx_packet(struct net_pkt *pkt)
510 {
511 net_pkt_set_rx_stats_tick(pkt, k_cycle_get_32());
512
513 net_capture_pkt(net_pkt_iface(pkt), pkt);
514
515 net_rx(net_pkt_iface(pkt), pkt);
516 }
517
net_queue_rx(struct net_if * iface,struct net_pkt * pkt)518 static void net_queue_rx(struct net_if *iface, struct net_pkt *pkt)
519 {
520 size_t len = net_pkt_get_len(pkt);
521 uint8_t prio = net_pkt_priority(pkt);
522 uint8_t tc = net_rx_priority2tc(prio);
523
524 #if NET_TC_RX_COUNT > 1
525 NET_DBG("TC %d with prio %d pkt %p", tc, prio, pkt);
526 #endif
527 if (net_tc_rx_is_immediate(tc, prio)) {
528 net_process_rx_packet(pkt);
529 } else {
530 if (net_tc_submit_to_rx_queue(tc, pkt) != NET_OK) {
531 goto drop;
532 }
533 }
534
535 net_stats_update_tc_recv_pkt(iface, tc);
536 net_stats_update_tc_recv_bytes(iface, tc, len);
537 net_stats_update_tc_recv_priority(iface, tc, prio);
538 return;
539
540 drop:
541 net_pkt_unref(pkt);
542 net_stats_update_tc_recv_dropped(iface, tc);
543 return;
544 }
545
546 /* Called by driver when a packet has been received */
net_recv_data(struct net_if * iface,struct net_pkt * pkt)547 int net_recv_data(struct net_if *iface, struct net_pkt *pkt)
548 {
549 int ret;
550 #if defined(CONFIG_NET_DSA) && !defined(CONFIG_NET_DSA_DEPRECATED)
551 struct ethernet_context *eth_ctx = net_if_l2_data(iface);
552
553 /* DSA driver handles first to untag and to redirect to user interface. */
554 if (eth_ctx != NULL && (eth_ctx->dsa_port == DSA_CONDUIT_PORT)) {
555 iface = dsa_recv(iface, pkt);
556 }
557 #endif
558
559 SYS_PORT_TRACING_FUNC_ENTER(net, recv_data, iface, pkt);
560
561 if (!pkt || !iface) {
562 ret = -EINVAL;
563 goto err;
564 }
565
566 if (net_pkt_is_empty(pkt)) {
567 ret = -ENODATA;
568 goto err;
569 }
570
571 if (!net_if_flag_is_set(iface, NET_IF_UP)) {
572 ret = -ENETDOWN;
573 goto err;
574 }
575
576 net_pkt_set_overwrite(pkt, true);
577 net_pkt_cursor_init(pkt);
578
579 NET_DBG("prio %d iface %p pkt %p len %zu", net_pkt_priority(pkt),
580 iface, pkt, net_pkt_get_len(pkt));
581
582 if (IS_ENABLED(CONFIG_NET_ROUTING)) {
583 net_pkt_set_orig_iface(pkt, iface);
584 }
585
586 net_pkt_set_iface(pkt, iface);
587
588 if (!net_pkt_filter_recv_ok(pkt)) {
589 /* Silently drop the packet, but update the statistics in order
590 * to be able to monitor filter activity.
591 */
592 net_stats_update_filter_rx_drop(net_pkt_iface(pkt));
593 net_pkt_unref(pkt);
594 } else {
595 net_queue_rx(iface, pkt);
596 }
597
598 ret = 0;
599
600 err:
601 SYS_PORT_TRACING_FUNC_EXIT(net, recv_data, iface, pkt, ret);
602
603 return ret;
604 }
605
l3_init(void)606 static inline void l3_init(void)
607 {
608 net_pmtu_init();
609 net_icmpv4_init();
610 net_icmpv6_init();
611 net_ipv4_init();
612 net_ipv6_init();
613
614 net_ipv4_autoconf_init();
615
616 if (IS_ENABLED(CONFIG_NET_UDP) ||
617 IS_ENABLED(CONFIG_NET_TCP) ||
618 IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) ||
619 IS_ENABLED(CONFIG_NET_SOCKETS_CAN)) {
620 net_conn_init();
621 }
622
623 net_tcp_init();
624
625 net_route_init();
626
627 NET_DBG("Network L3 init done");
628 }
629 #else /* CONFIG_NET_NATIVE */
630 #define l3_init(...)
631 #define net_post_init(...)
net_try_send_data(struct net_pkt * pkt,k_timeout_t timeout)632 int net_try_send_data(struct net_pkt *pkt, k_timeout_t timeout)
633 {
634 ARG_UNUSED(pkt);
635 ARG_UNUSED(timeout);
636
637 return -ENOTSUP;
638 }
net_recv_data(struct net_if * iface,struct net_pkt * pkt)639 int net_recv_data(struct net_if *iface, struct net_pkt *pkt)
640 {
641 ARG_UNUSED(iface);
642 ARG_UNUSED(pkt);
643
644 return -ENOTSUP;
645 }
646 #endif /* CONFIG_NET_NATIVE */
647
init_rx_queues(void)648 static void init_rx_queues(void)
649 {
650 net_tc_rx_init();
651
652 /* Starting TX side. The ordering is important here and the TX
653 * can only be started when RX side is ready to receive packets.
654 */
655 net_if_init();
656
657 /* This will take the interface up and start everything. */
658 net_if_post_init();
659
660 /* Things to init after network interface is working */
661 net_post_init();
662 }
663
services_init(void)664 static inline int services_init(void)
665 {
666 int status;
667
668 socket_service_init();
669
670 status = net_dhcpv4_init();
671 if (status) {
672 return status;
673 }
674
675 status = net_dhcpv6_init();
676 if (status != 0) {
677 return status;
678 }
679
680 net_dhcpv4_server_init();
681
682 dns_dispatcher_init();
683 dns_init_resolver();
684 mdns_init_responder();
685
686 websocket_init();
687
688 net_coap_init();
689
690 net_shell_init();
691
692 return status;
693 }
694
net_init(void)695 static int net_init(void)
696 {
697 net_hostname_init();
698
699 NET_DBG("Priority %d", CONFIG_NET_INIT_PRIO);
700
701 net_pkt_init();
702
703 net_context_init();
704
705 l3_init();
706
707 net_mgmt_event_init();
708
709 init_rx_queues();
710
711 return services_init();
712 }
713
714 SYS_INIT(net_init, POST_KERNEL, CONFIG_NET_INIT_PRIO);
715