1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  *
10  * Routines setting up the host system. Those are placed in separate file
11  * because there is naming conflicts between host and zephyr network stacks.
12  */
13 
14 /* Host include files */
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <stdarg.h>
18 #include <errno.h>
19 #include <string.h>
20 #include <stdbool.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
25 #include <sys/select.h>
26 #include <net/if.h>
27 #include <time.h>
28 #include <zephyr/arch/posix/posix_trace.h>
29 
30 #ifdef __linux
31 #include <linux/if_tun.h>
32 #endif
33 
34 /* Zephyr include files. Be very careful here and only include minimum
35  * things needed.
36  */
37 #define LOG_MODULE_NAME eth_posix_adapt
38 #define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL
39 
40 #include <zephyr/logging/log.h>
41 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
42 
43 #include <zephyr/types.h>
44 #include <zephyr/sys_clock.h>
45 
46 #if defined(CONFIG_NET_GPTP)
47 #include <zephyr/net/gptp.h>
48 #endif
49 
50 #include "eth_native_posix_priv.h"
51 
52 /* Note that we cannot create the TUN/TAP device from the setup script
53  * as we need to get a file descriptor to communicate with the interface.
54  */
eth_iface_create(const char * if_name,bool tun_only)55 int eth_iface_create(const char *if_name, bool tun_only)
56 {
57 	struct ifreq ifr;
58 	int fd, ret = -EINVAL;
59 
60 	fd = open(ETH_NATIVE_POSIX_DEV_NAME, O_RDWR);
61 	if (fd < 0) {
62 		return -errno;
63 	}
64 
65 	(void)memset(&ifr, 0, sizeof(ifr));
66 
67 #ifdef __linux
68 	ifr.ifr_flags = (tun_only ? IFF_TUN : IFF_TAP) | IFF_NO_PI;
69 
70 	strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1);
71 
72 	ret = ioctl(fd, TUNSETIFF, (void *)&ifr);
73 	if (ret < 0) {
74 		ret = -errno;
75 		close(fd);
76 		return ret;
77 	}
78 #endif
79 
80 	return fd;
81 }
82 
eth_iface_remove(int fd)83 int eth_iface_remove(int fd)
84 {
85 	return close(fd);
86 }
87 
88 static int ssystem(const char *fmt, ...)
89 	__attribute__((__format__(__printf__, 1, 2)));
90 
ssystem(const char * fmt,...)91 static int ssystem(const char *fmt, ...)
92 {
93 	char cmd[255];
94 	va_list ap;
95 	int ret;
96 
97 	va_start(ap, fmt);
98 	vsnprintf(cmd, sizeof(cmd), fmt, ap);
99 	va_end(ap);
100 
101 	posix_print_trace("%s\n", cmd);
102 
103 	ret = system(cmd);
104 
105 	return -WEXITSTATUS(ret);
106 }
107 
eth_setup_host(const char * if_name)108 int eth_setup_host(const char *if_name)
109 {
110 	if (!IS_ENABLED(CONFIG_ETH_NATIVE_POSIX_STARTUP_AUTOMATIC)) {
111 		return 0;
112 	}
113 
114 	/* User might have added -i option to setup script string, so
115 	 * check that situation in the script itself so that the -i option
116 	 * we add here is ignored in that case.
117 	 */
118 	return ssystem("%s -i %s", ETH_NATIVE_POSIX_SETUP_SCRIPT,
119 		       if_name);
120 }
121 
eth_start_script(const char * if_name)122 int eth_start_script(const char *if_name)
123 {
124 	if (!IS_ENABLED(CONFIG_ETH_NATIVE_POSIX_STARTUP_AUTOMATIC)) {
125 		return 0;
126 	}
127 
128 	if (ETH_NATIVE_POSIX_STARTUP_SCRIPT[0] == '\0') {
129 		return 0;
130 	}
131 
132 	if (ETH_NATIVE_POSIX_STARTUP_SCRIPT_USER[0] == '\0') {
133 		return ssystem("%s %s", ETH_NATIVE_POSIX_STARTUP_SCRIPT,
134 			       if_name);
135 	} else {
136 		return ssystem("sudo -u %s %s %s",
137 			       ETH_NATIVE_POSIX_STARTUP_SCRIPT_USER,
138 			       ETH_NATIVE_POSIX_STARTUP_SCRIPT,
139 			       if_name);
140 	}
141 }
142 
eth_wait_data(int fd)143 int eth_wait_data(int fd)
144 {
145 	struct timeval timeout;
146 	fd_set rset;
147 	int ret;
148 
149 	FD_ZERO(&rset);
150 
151 	FD_SET(fd, &rset);
152 
153 	timeout.tv_sec = 0;
154 	timeout.tv_usec = 0;
155 
156 	ret = select(fd + 1, &rset, NULL, NULL, &timeout);
157 	if (ret < 0 && errno != EINTR) {
158 		return -errno;
159 	} else if (ret > 0) {
160 		if (FD_ISSET(fd, &rset)) {
161 			return 0;
162 		}
163 	}
164 
165 	return -EAGAIN;
166 }
167 
eth_read_data(int fd,void * buf,size_t buf_len)168 ssize_t eth_read_data(int fd, void *buf, size_t buf_len)
169 {
170 	return read(fd, buf, buf_len);
171 }
172 
eth_write_data(int fd,void * buf,size_t buf_len)173 ssize_t eth_write_data(int fd, void *buf, size_t buf_len)
174 {
175 	return write(fd, buf, buf_len);
176 }
177 
178 #if defined(CONFIG_NET_GPTP)
eth_clock_gettime(struct net_ptp_time * time)179 int eth_clock_gettime(struct net_ptp_time *time)
180 {
181 	struct timespec tp;
182 	int ret;
183 
184 	ret = clock_gettime(CLOCK_MONOTONIC_RAW, &tp);
185 	if (ret < 0) {
186 		return -errno;
187 	}
188 
189 	time->second = tp.tv_sec;
190 	time->nanosecond = tp.tv_nsec;
191 
192 	return 0;
193 }
194 #endif /* CONFIG_NET_GPTP */
195 
196 #if defined(CONFIG_NET_PROMISCUOUS_MODE)
eth_promisc_mode(const char * if_name,bool enable)197 int eth_promisc_mode(const char *if_name, bool enable)
198 {
199 	if (!IS_ENABLED(CONFIG_ETH_NATIVE_POSIX_STARTUP_AUTOMATIC)) {
200 		return 0;
201 	}
202 
203 	return ssystem("ip link set dev %s promisc %s",
204 		       if_name, enable ? "on" : "off");
205 }
206 #endif /* CONFIG_NET_PROMISCUOUS_MODE */
207 
208 /* If we have enabled manual setup, then interface cannot be
209  * taken up or down by the driver as we normally do not have
210  * enough permissions.
211  */
212 
eth_if_up(const char * if_name)213 int eth_if_up(const char *if_name)
214 {
215 	if (!IS_ENABLED(CONFIG_ETH_NATIVE_POSIX_STARTUP_AUTOMATIC)) {
216 		return 0;
217 	}
218 
219 	return ssystem("ip link set dev %s up", if_name);
220 }
221 
eth_if_down(const char * if_name)222 int eth_if_down(const char *if_name)
223 {
224 	if (!IS_ENABLED(CONFIG_ETH_NATIVE_POSIX_STARTUP_AUTOMATIC)) {
225 		return 0;
226 	}
227 
228 	return ssystem("ip link set dev %s down", if_name);
229 }
230