1 /*
2  * Copyright (c) 2015 Intel Corporation
3  * Copyright (c) 2017 Linaro Limited
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /**
9  * @file
10  *
11  * Network loopback interface implementation.
12  */
13 
14 #define LOG_MODULE_NAME netlo
15 #define LOG_LEVEL CONFIG_NET_LOOPBACK_LOG_LEVEL
16 
17 #include <logging/log.h>
18 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
19 
20 #include <net/net_pkt.h>
21 #include <net/buf.h>
22 #include <net/net_ip.h>
23 #include <net/net_if.h>
24 
25 #include <net/dummy.h>
26 
loopback_dev_init(const struct device * dev)27 int loopback_dev_init(const struct device *dev)
28 {
29 	ARG_UNUSED(dev);
30 
31 	return 0;
32 }
33 
loopback_init(struct net_if * iface)34 static void loopback_init(struct net_if *iface)
35 {
36 	/* RFC 7042, s.2.1.1. address to use in documentation */
37 	net_if_set_link_addr(iface, "\x00\x00\x5e\x00\x53\xff", 6,
38 			     NET_LINK_DUMMY);
39 }
40 
loopback_send(const struct device * dev,struct net_pkt * pkt)41 static int loopback_send(const struct device *dev, struct net_pkt *pkt)
42 {
43 	struct net_pkt *cloned;
44 	int res;
45 
46 	ARG_UNUSED(dev);
47 
48 	if (!pkt->frags) {
49 		LOG_ERR("No data to send");
50 		return -ENODATA;
51 	}
52 
53 	/* We need to swap the IP addresses because otherwise
54 	 * the packet will be dropped.
55 	 */
56 
57 	if (net_pkt_family(pkt) == AF_INET6) {
58 		struct in6_addr addr;
59 
60 		net_ipaddr_copy(&addr, &NET_IPV6_HDR(pkt)->src);
61 		net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src,
62 				&NET_IPV6_HDR(pkt)->dst);
63 		net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, &addr);
64 	} else {
65 		struct in_addr addr;
66 
67 		net_ipaddr_copy(&addr, &NET_IPV4_HDR(pkt)->src);
68 		net_ipaddr_copy(&NET_IPV4_HDR(pkt)->src,
69 				&NET_IPV4_HDR(pkt)->dst);
70 		net_ipaddr_copy(&NET_IPV4_HDR(pkt)->dst, &addr);
71 	}
72 
73 	/* We should simulate normal driver meaning that if the packet is
74 	 * properly sent (which is always in this driver), then the packet
75 	 * must be dropped. This is very much needed for TCP packets where
76 	 * the packet is reference counted in various stages of sending.
77 	 */
78 	cloned = net_pkt_clone(pkt, K_MSEC(100));
79 	if (!cloned) {
80 		res = -ENOMEM;
81 		goto out;
82 	}
83 
84 	res = net_recv_data(net_pkt_iface(cloned), cloned);
85 	if (res < 0) {
86 		LOG_ERR("Data receive failed.");
87 	}
88 
89 out:
90 	/* Let the receiving thread run now */
91 	k_yield();
92 
93 	return res;
94 }
95 
96 static struct dummy_api loopback_api = {
97 	.iface_api.init = loopback_init,
98 
99 	.send = loopback_send,
100 };
101 
102 NET_DEVICE_INIT(loopback, "lo",
103 		loopback_dev_init, NULL, NULL, NULL,
104 		CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
105 		&loopback_api, DUMMY_L2,
106 		NET_L2_GET_CTX_TYPE(DUMMY_L2), 536);
107