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