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/ipv4_autoconf.h>
27 #include <zephyr/net/net_if.h>
28 #include <zephyr/net/net_mgmt.h>
29 #include <zephyr/net/net_pkt.h>
30 #include <zephyr/net/net_core.h>
31 #include <zephyr/net/dns_resolve.h>
32 #include <zephyr/net/gptp.h>
33 #include <zephyr/net/websocket.h>
34 #include <zephyr/net/ethernet.h>
35 #include <zephyr/net/capture.h>
36
37 #if defined(CONFIG_NET_LLDP)
38 #include <zephyr/net/lldp.h>
39 #endif
40
41 #include "net_private.h"
42 #include "shell/net_shell.h"
43
44 #include "pmtu.h"
45
46 #include "icmpv6.h"
47 #include "ipv6.h"
48
49 #include "icmpv4.h"
50 #include "ipv4.h"
51
52 #include "dhcpv4/dhcpv4_internal.h"
53 #include "dhcpv6/dhcpv6_internal.h"
54
55 #include "route.h"
56
57 #include "packet_socket.h"
58 #include "canbus_socket.h"
59
60 #include "connection.h"
61 #include "udp_internal.h"
62 #include "tcp_internal.h"
63
64 #include "net_stats.h"
65
66 #if defined(CONFIG_NET_NATIVE)
process_data(struct net_pkt * pkt,bool is_loopback)67 static inline enum net_verdict process_data(struct net_pkt *pkt,
68 bool is_loopback)
69 {
70 int ret;
71 bool locally_routed = false;
72
73 net_pkt_set_l2_processed(pkt, false);
74
75 /* Initial call will forward packets to SOCK_RAW packet sockets. */
76 ret = net_packet_socket_input(pkt, ETH_P_ALL);
77 if (ret != NET_CONTINUE) {
78 return ret;
79 }
80
81 /* If the packet is routed back to us when we have reassembled an IPv4 or IPv6 packet,
82 * then do not pass it to L2 as the packet does not have link layer headers in it.
83 */
84 if (net_pkt_is_ip_reassembled(pkt)) {
85 locally_routed = true;
86 }
87
88 /* If there is no data, then drop the packet. */
89 if (!pkt->frags) {
90 NET_DBG("Corrupted packet (frags %p)", pkt->frags);
91 net_stats_update_processing_error(net_pkt_iface(pkt));
92
93 return NET_DROP;
94 }
95
96 if (!is_loopback && !locally_routed) {
97 ret = net_if_recv_data(net_pkt_iface(pkt), pkt);
98 if (ret != NET_CONTINUE) {
99 if (ret == NET_DROP) {
100 NET_DBG("Packet %p discarded by L2", pkt);
101 net_stats_update_processing_error(
102 net_pkt_iface(pkt));
103 }
104
105 return ret;
106 }
107 }
108
109 net_pkt_set_l2_processed(pkt, true);
110
111 /* L2 has modified the buffer starting point, it is easier
112 * to re-initialize the cursor rather than updating it.
113 */
114 net_pkt_cursor_init(pkt);
115
116 if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET_DGRAM)) {
117 /* Consecutive call will forward packets to SOCK_DGRAM packet sockets
118 * (after L2 removed header).
119 */
120 ret = net_packet_socket_input(pkt, net_pkt_ll_proto_type(pkt));
121 if (ret != NET_CONTINUE) {
122 return ret;
123 }
124 }
125
126 uint8_t family = net_pkt_family(pkt);
127
128 if (IS_ENABLED(CONFIG_NET_IP) && (family == AF_INET || family == AF_INET6 ||
129 family == AF_UNSPEC || family == AF_PACKET)) {
130 /* IP version and header length. */
131 uint8_t vtc_vhl = NET_IPV6_HDR(pkt)->vtc & 0xf0;
132
133 if (IS_ENABLED(CONFIG_NET_IPV6) && vtc_vhl == 0x60) {
134 return net_ipv6_input(pkt, is_loopback);
135 } else if (IS_ENABLED(CONFIG_NET_IPV4) && vtc_vhl == 0x40) {
136 return net_ipv4_input(pkt, is_loopback);
137 }
138
139 NET_DBG("Unknown IP family packet (0x%x)", NET_IPV6_HDR(pkt)->vtc & 0xf0);
140 net_stats_update_ip_errors_protoerr(net_pkt_iface(pkt));
141 net_stats_update_ip_errors_vhlerr(net_pkt_iface(pkt));
142 return NET_DROP;
143 } else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) && family == AF_CAN) {
144 return net_canbus_socket_input(pkt);
145 }
146
147 NET_DBG("Unknown protocol family packet (0x%x)", family);
148 return NET_DROP;
149 }
150
processing_data(struct net_pkt * pkt,bool is_loopback)151 static void processing_data(struct net_pkt *pkt, bool is_loopback)
152 {
153 again:
154 switch (process_data(pkt, is_loopback)) {
155 case NET_CONTINUE:
156 if (IS_ENABLED(CONFIG_NET_L2_VIRTUAL)) {
157 /* If we have a tunneling packet, feed it back
158 * to the stack in this case.
159 */
160 goto again;
161 } else {
162 NET_DBG("Dropping pkt %p", pkt);
163 net_pkt_unref(pkt);
164 }
165 break;
166 case NET_OK:
167 NET_DBG("Consumed pkt %p", pkt);
168 break;
169 case NET_DROP:
170 default:
171 NET_DBG("Dropping pkt %p", pkt);
172 net_pkt_unref(pkt);
173 break;
174 }
175 }
176
177 /* Things to setup after we are able to RX and TX */
net_post_init(void)178 static void net_post_init(void)
179 {
180 #if defined(CONFIG_NET_LLDP)
181 net_lldp_init();
182 #endif
183 #if defined(CONFIG_NET_GPTP)
184 net_gptp_init();
185 #endif
186 }
187
copy_ll_addr(struct net_pkt * pkt)188 static inline void copy_ll_addr(struct net_pkt *pkt)
189 {
190 memcpy(net_pkt_lladdr_src(pkt), net_pkt_lladdr_if(pkt),
191 sizeof(struct net_linkaddr));
192 memcpy(net_pkt_lladdr_dst(pkt), net_pkt_lladdr_if(pkt),
193 sizeof(struct net_linkaddr));
194 }
195
196 /* Check if the IPv{4|6} addresses are proper. As this can be expensive,
197 * make this optional. We still check the IPv4 TTL and IPv6 hop limit
198 * if the corresponding protocol family is enabled.
199 */
check_ip(struct net_pkt * pkt)200 static inline int check_ip(struct net_pkt *pkt)
201 {
202 uint8_t family;
203 int ret;
204
205 if (!IS_ENABLED(CONFIG_NET_IP)) {
206 return 0;
207 }
208
209 family = net_pkt_family(pkt);
210 ret = 0;
211
212 if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6 &&
213 net_pkt_ll_proto_type(pkt) == NET_ETH_PTYPE_IPV6) {
214 /* Drop IPv6 packet if hop limit is 0 */
215 if (NET_IPV6_HDR(pkt)->hop_limit == 0) {
216 NET_DBG("DROP: IPv6 hop limit");
217 ret = -ENOMSG; /* silently drop the pkt, not an error */
218 goto drop;
219 }
220
221 if (!IS_ENABLED(CONFIG_NET_IP_ADDR_CHECK)) {
222 return 0;
223 }
224
225 #if defined(CONFIG_NET_LOOPBACK)
226 /* If loopback driver is enabled, then send packets to it
227 * as the address check is not needed.
228 */
229 if (net_if_l2(net_pkt_iface(pkt)) == &NET_L2_GET_NAME(DUMMY)) {
230 return 0;
231 }
232 #endif
233 if (net_ipv6_addr_cmp_raw(NET_IPV6_HDR(pkt)->dst,
234 (const uint8_t *)net_ipv6_unspecified_address())) {
235 NET_DBG("DROP: IPv6 dst address missing");
236 ret = -EADDRNOTAVAIL;
237 goto drop;
238 }
239
240 /* If the destination address is our own, then route it
241 * back to us (if it is not already forwarded).
242 */
243 if ((net_ipv6_is_addr_loopback_raw(NET_IPV6_HDR(pkt)->dst) ||
244 net_ipv6_is_my_addr_raw(NET_IPV6_HDR(pkt)->dst)) &&
245 !net_pkt_forwarding(pkt)) {
246 struct in6_addr addr;
247
248 /* Swap the addresses so that in receiving side
249 * the packet is accepted.
250 */
251 net_ipv6_addr_copy_raw((uint8_t *)&addr, NET_IPV6_HDR(pkt)->src);
252 net_ipv6_addr_copy_raw(NET_IPV6_HDR(pkt)->src,
253 NET_IPV6_HDR(pkt)->dst);
254 net_ipv6_addr_copy_raw(NET_IPV6_HDR(pkt)->dst, (uint8_t *)&addr);
255
256 net_pkt_set_ll_proto_type(pkt, ETH_P_IPV6);
257 copy_ll_addr(pkt);
258
259 return 1;
260 }
261
262 /* If the destination address is interface local scope
263 * multicast address, then loop the data back to us.
264 * The FF01:: multicast addresses are only meant to be used
265 * in local host, so this is similar as how ::1 unicast
266 * addresses are handled. See RFC 3513 ch 2.7 for details.
267 */
268 if (net_ipv6_is_addr_mcast_iface_raw(NET_IPV6_HDR(pkt)->dst)) {
269 NET_DBG("IPv6 interface scope mcast dst address");
270 return 1;
271 }
272
273 /* The source check must be done after the destination check
274 * as having src ::1 is perfectly ok if dst is ::1 too.
275 */
276 if (net_ipv6_is_addr_loopback_raw(NET_IPV6_HDR(pkt)->src)) {
277 NET_DBG("DROP: IPv6 loopback src address");
278 ret = -EADDRNOTAVAIL;
279 goto drop;
280 }
281
282 } else if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET &&
283 net_pkt_ll_proto_type(pkt) == NET_ETH_PTYPE_IP) {
284 /* Drop IPv4 packet if ttl is 0 */
285 if (NET_IPV4_HDR(pkt)->ttl == 0) {
286 NET_DBG("DROP: IPv4 ttl");
287 ret = -ENOMSG; /* silently drop the pkt, not an error */
288 goto drop;
289 }
290
291 if (!IS_ENABLED(CONFIG_NET_IP_ADDR_CHECK)) {
292 return 0;
293 }
294
295 #if defined(CONFIG_NET_LOOPBACK)
296 /* If loopback driver is enabled, then send packets to it
297 * as the address check is not needed.
298 */
299 if (net_if_l2(net_pkt_iface(pkt)) == &NET_L2_GET_NAME(DUMMY)) {
300 return 0;
301 }
302 #endif
303 if (net_ipv4_addr_cmp_raw(NET_IPV4_HDR(pkt)->dst,
304 net_ipv4_unspecified_address()->s4_addr)) {
305 NET_DBG("DROP: IPv4 dst address missing");
306 ret = -EADDRNOTAVAIL;
307 goto drop;
308 }
309
310 /* If the destination address is our own, then route it
311 * back to us.
312 */
313 if (net_ipv4_is_addr_loopback_raw(NET_IPV4_HDR(pkt)->dst) ||
314 (net_ipv4_is_addr_bcast_raw(net_pkt_iface(pkt),
315 NET_IPV4_HDR(pkt)->dst) == false &&
316 net_ipv4_is_my_addr_raw(NET_IPV4_HDR(pkt)->dst))) {
317 struct in_addr addr;
318
319 /* Swap the addresses so that in receiving side
320 * the packet is accepted.
321 */
322 net_ipv4_addr_copy_raw((uint8_t *)&addr, NET_IPV4_HDR(pkt)->src);
323 net_ipv4_addr_copy_raw(NET_IPV4_HDR(pkt)->src,
324 NET_IPV4_HDR(pkt)->dst);
325 net_ipv4_addr_copy_raw(NET_IPV4_HDR(pkt)->dst, (uint8_t *)&addr);
326
327 net_pkt_set_ll_proto_type(pkt, ETH_P_IP);
328 copy_ll_addr(pkt);
329
330 return 1;
331 }
332
333 /* The source check must be done after the destination check
334 * as having src 127.0.0.0/8 is perfectly ok if dst is in
335 * localhost subnet too.
336 */
337 if (net_ipv4_is_addr_loopback_raw(NET_IPV4_HDR(pkt)->src)) {
338 NET_DBG("DROP: IPv4 loopback src address");
339 ret = -EADDRNOTAVAIL;
340 goto drop;
341 }
342 }
343
344 return ret;
345
346 drop:
347 if (IS_ENABLED(CONFIG_NET_STATISTICS)) {
348 if (family == AF_INET6) {
349 net_stats_update_ipv6_drop(net_pkt_iface(pkt));
350 } else {
351 net_stats_update_ipv4_drop(net_pkt_iface(pkt));
352 }
353 }
354
355 return ret;
356 }
357
358 #if defined(CONFIG_NET_IPV4) || defined(CONFIG_NET_IPV6)
process_multicast(struct net_pkt * pkt)359 static inline bool process_multicast(struct net_pkt *pkt)
360 {
361 struct net_context *ctx = net_pkt_context(pkt);
362 sa_family_t family = net_pkt_family(pkt);
363
364 if (ctx == NULL) {
365 return false;
366 }
367
368 #if defined(CONFIG_NET_IPV4)
369 if (family == AF_INET) {
370 const struct in_addr *dst = (const struct in_addr *)&NET_IPV4_HDR(pkt)->dst;
371
372 return net_ipv4_is_addr_mcast(dst) && net_context_get_ipv4_mcast_loop(ctx);
373 }
374 #endif
375 #if defined(CONFIG_NET_IPV6)
376 if (family == AF_INET6) {
377 return net_ipv6_is_addr_mcast_raw(NET_IPV6_HDR(pkt)->dst) &&
378 net_context_get_ipv6_mcast_loop(ctx);
379 }
380 #endif
381 return false;
382 }
383 #endif
384
net_try_send_data(struct net_pkt * pkt,k_timeout_t timeout)385 int net_try_send_data(struct net_pkt *pkt, k_timeout_t timeout)
386 {
387 int status;
388 int ret;
389
390 SYS_PORT_TRACING_FUNC_ENTER(net, send_data, pkt);
391
392 if (!pkt || !pkt->frags) {
393 ret = -ENODATA;
394 goto err;
395 }
396
397 if (!net_pkt_iface(pkt)) {
398 ret = -EINVAL;
399 goto err;
400 }
401
402 net_pkt_trim_buffer(pkt);
403 net_pkt_cursor_init(pkt);
404
405 status = check_ip(pkt);
406 if (status < 0) {
407 /* Special handling for ENOMSG which is returned if packet
408 * TTL is 0 or hop limit is 0. This is not an error as it is
409 * perfectly valid case to set the limit to 0. In this case
410 * we just silently drop the packet by returning 0.
411 */
412 if (status == -ENOMSG) {
413 net_pkt_unref(pkt);
414 ret = 0;
415 goto err;
416 }
417
418 return status;
419 } else if (status > 0) {
420 /* Packet is destined back to us so send it directly
421 * to RX processing.
422 */
423 NET_DBG("Loopback pkt %p back to us", pkt);
424 processing_data(pkt, true);
425 ret = 0;
426 goto err;
427 }
428
429 #if defined(CONFIG_NET_IPV4) || defined(CONFIG_NET_IPV6)
430 if (process_multicast(pkt)) {
431 struct net_pkt *clone = net_pkt_clone(pkt, K_NO_WAIT);
432
433 if (clone != NULL) {
434 net_pkt_set_iface(clone, net_pkt_iface(pkt));
435 if (net_recv_data(net_pkt_iface(clone), clone) < 0) {
436 if (IS_ENABLED(CONFIG_NET_STATISTICS)) {
437 switch (net_pkt_family(pkt)) {
438 #if defined(CONFIG_NET_IPV4)
439 case AF_INET:
440 net_stats_update_ipv4_sent(net_pkt_iface(pkt));
441 break;
442 #endif
443 #if defined(CONFIG_NET_IPV6)
444 case AF_INET6:
445 net_stats_update_ipv6_sent(net_pkt_iface(pkt));
446 break;
447 #endif
448 }
449 }
450 net_pkt_unref(clone);
451 }
452 } else {
453 NET_DBG("Failed to clone multicast packet");
454 }
455 }
456 #endif
457
458 if (net_if_try_send_data(net_pkt_iface(pkt), pkt, timeout) == NET_DROP) {
459 ret = -EIO;
460 goto err;
461 }
462
463 if (IS_ENABLED(CONFIG_NET_STATISTICS)) {
464 switch (net_pkt_family(pkt)) {
465 case AF_INET:
466 net_stats_update_ipv4_sent(net_pkt_iface(pkt));
467 break;
468 case AF_INET6:
469 net_stats_update_ipv6_sent(net_pkt_iface(pkt));
470 break;
471 }
472 }
473
474 ret = 0;
475
476 err:
477 SYS_PORT_TRACING_FUNC_EXIT(net, send_data, pkt, ret);
478
479 return ret;
480 }
481
net_rx(struct net_if * iface,struct net_pkt * pkt)482 static void net_rx(struct net_if *iface, struct net_pkt *pkt)
483 {
484 bool is_loopback = false;
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
493 if (IS_ENABLED(CONFIG_NET_LOOPBACK)) {
494 #ifdef CONFIG_NET_L2_DUMMY
495 if (net_if_l2(iface) == &NET_L2_GET_NAME(DUMMY)) {
496 is_loopback = true;
497 }
498 #endif
499 }
500
501 processing_data(pkt, is_loopback);
502
503 net_print_statistics();
504 net_pkt_print();
505 }
506
net_process_rx_packet(struct net_pkt * pkt)507 void net_process_rx_packet(struct net_pkt *pkt)
508 {
509 net_pkt_set_rx_stats_tick(pkt, k_cycle_get_32());
510
511 net_capture_pkt(net_pkt_iface(pkt), pkt);
512
513 net_rx(net_pkt_iface(pkt), pkt);
514 }
515
net_queue_rx(struct net_if * iface,struct net_pkt * pkt)516 static void net_queue_rx(struct net_if *iface, struct net_pkt *pkt)
517 {
518 size_t len = net_pkt_get_len(pkt);
519 uint8_t prio = net_pkt_priority(pkt);
520 uint8_t tc = net_rx_priority2tc(prio);
521
522 #if NET_TC_RX_COUNT > 1
523 NET_DBG("TC %d with prio %d pkt %p", tc, prio, pkt);
524 #endif
525
526 if ((IS_ENABLED(CONFIG_NET_TC_RX_SKIP_FOR_HIGH_PRIO) &&
527 prio >= NET_PRIORITY_CA) || NET_TC_RX_COUNT == 0) {
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 /* Starting TX side. The ordering is important here and the TX
651 * can only be started when RX side is ready to receive packets.
652 */
653 net_if_init();
654
655 net_tc_rx_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