1 /*
2  * Copyright (c) 2021 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_DECLARE(net_echo_server_sample, LOG_LEVEL_DBG);
9 
10 #include <zephyr/kernel.h>
11 
12 #include <zephyr/net/ethernet.h>
13 #include <zephyr/net/virtual_mgmt.h>
14 #include <zephyr/net/conn_mgr_monitor.h>
15 
16 /* User data for the interface callback */
17 struct ud {
18 	struct net_if *tunnel;
19 	struct net_if *peer;
20 };
21 
is_tunnel(struct net_if * iface)22 bool is_tunnel(struct net_if *iface)
23 {
24 	if (net_if_l2(iface) == &NET_L2_GET_NAME(VIRTUAL) &&
25 	    strncmp(net_if_get_device(iface)->name, "IP_TUNNEL0",
26 		    strlen(net_if_get_device(iface)->name)) == 0) {
27 		return true;
28 	}
29 
30 	return false;
31 }
32 
iface_cb(struct net_if * iface,void * user_data)33 static void iface_cb(struct net_if *iface, void *user_data)
34 {
35 	struct ud *ud = user_data;
36 
37 	if (!ud->tunnel && is_tunnel(iface)) {
38 		ud->tunnel = iface;
39 		return;
40 	}
41 }
42 
setup_iface(struct net_if * iface,const char * ipaddr)43 static int setup_iface(struct net_if *iface, const char *ipaddr)
44 {
45 	struct net_if_addr *ifaddr;
46 	struct sockaddr addr;
47 
48 	/* Before setting up tunnel, make sure it will be ignored by conn_mgr */
49 	conn_mgr_ignore_iface(iface);
50 
51 	if (!net_ipaddr_parse(ipaddr, strlen(ipaddr), &addr)) {
52 		LOG_ERR("Tunnel peer address \"%s\" invalid.", ipaddr);
53 		return -EINVAL;
54 	}
55 
56 	if (IS_ENABLED(CONFIG_NET_IPV6) && addr.sa_family == AF_INET6) {
57 		ifaddr = net_if_ipv6_addr_add(iface,
58 					      &net_sin6(&addr)->sin6_addr,
59 					      NET_ADDR_MANUAL, 0);
60 		if (!ifaddr) {
61 			LOG_ERR("Cannot add %s to interface %d",
62 				ipaddr, net_if_get_by_iface(iface));
63 			return -EINVAL;
64 		}
65 	}
66 
67 	if (IS_ENABLED(CONFIG_NET_IPV4) && addr.sa_family == AF_INET) {
68 		ifaddr = net_if_ipv4_addr_add(iface,
69 					      &net_sin(&addr)->sin_addr,
70 					      NET_ADDR_MANUAL, 0);
71 		if (!ifaddr) {
72 			LOG_ERR("Cannot add %s to interface %d",
73 				ipaddr, net_if_get_by_iface(iface));
74 			return -EINVAL;
75 		}
76 	}
77 
78 	return 0;
79 }
80 
init_tunnel(void)81 int init_tunnel(void)
82 {
83 	struct virtual_interface_req_params params = { 0 };
84 	struct sockaddr peer = { 0 };
85 	struct ud ud;
86 	int ret;
87 	int mtu;
88 
89 	memset(&ud, 0, sizeof(ud));
90 
91 	if (CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR[0] == '\0') {
92 		LOG_INF("Tunnel peer address not set.");
93 		return 0;
94 	}
95 
96 	if (!net_ipaddr_parse(CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR,
97 			      strlen(CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR),
98 			      &peer)) {
99 		LOG_ERR("Tunnel peer address \"%s\" invalid.",
100 			CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR);
101 		return -EINVAL;
102 	}
103 
104 	if (IS_ENABLED(CONFIG_NET_IPV6) && peer.sa_family == AF_INET6) {
105 		struct net_if *iface;
106 
107 		iface = net_if_ipv6_select_src_iface(
108 					&net_sin6(&peer)->sin6_addr);
109 		ud.peer = iface;
110 		params.family = AF_INET6;
111 		net_ipaddr_copy(&params.peer6addr,
112 				&net_sin6(&peer)->sin6_addr);
113 		mtu = NET_ETH_MTU - sizeof(struct net_ipv6_hdr);
114 
115 	} else if (IS_ENABLED(CONFIG_NET_IPV4) && peer.sa_family == AF_INET) {
116 		struct net_if *iface;
117 
118 		iface = net_if_ipv4_select_src_iface(
119 					&net_sin(&peer)->sin_addr);
120 		ud.peer = iface;
121 		params.family = AF_INET;
122 		net_ipaddr_copy(&params.peer4addr,
123 				&net_sin(&peer)->sin_addr);
124 		mtu = NET_ETH_MTU - sizeof(struct net_ipv4_hdr);
125 
126 	} else {
127 		LOG_ERR("Invalid address family %d", peer.sa_family);
128 		return -EINVAL;
129 	}
130 
131 	if (ud.peer == NULL) {
132 		LOG_ERR("Peer address %s unreachable",
133 			CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR);
134 		return -ENETUNREACH;
135 	}
136 
137 	net_if_foreach(iface_cb, &ud);
138 
139 	if (ud.tunnel == NULL) {
140 		LOG_ERR("Tunnel interface not found.");
141 		return -ENOENT;
142 	}
143 
144 	ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_SET_PEER_ADDRESS,
145 		       ud.tunnel, &params, sizeof(params));
146 	if (ret < 0 && ret != -ENOTSUP) {
147 		LOG_ERR("Cannot set peer address %s to "
148 			"interface %d (%d)",
149 			CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR,
150 			net_if_get_by_iface(ud.tunnel),
151 			ret);
152 	}
153 
154 	params.mtu = mtu;
155 
156 	ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_SET_MTU,
157 		       ud.tunnel, &params, sizeof(params));
158 	if (ret < 0 && ret != -ENOTSUP) {
159 		LOG_ERR("Cannot set interface %d MTU to %d (%d)",
160 			net_if_get_by_iface(ud.tunnel), params.mtu, ret);
161 	}
162 
163 	ret = setup_iface(ud.tunnel,
164 			  CONFIG_NET_SAMPLE_TUNNEL_MY_ADDR);
165 	if (ret < 0) {
166 		LOG_ERR("Cannot set IP address %s to tunnel interface",
167 			CONFIG_NET_SAMPLE_TUNNEL_MY_ADDR);
168 		return -EINVAL;
169 	}
170 
171 	return 0;
172 }
173