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