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 a separate file
11  * to avoid naming conflicts between host and zephyr network stacks.
12  * This file is built with the host libC in the native simulator runner context.
13  */
14 
15 /* Host include files */
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stdarg.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <stdbool.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
26 #include <sys/select.h>
27 #include <net/if.h>
28 #include <time.h>
29 #include <inttypes.h>
30 #include <nsi_tracing.h>
31 
32 #ifdef __linux
33 #include <linux/if.h>
34 #include <linux/if_tun.h>
35 #endif
36 
37 #include "eth_native_tap_priv.h"
38 
39 /* Note that we cannot create the TUN/TAP device from the setup script
40  * as we need to get a file descriptor to communicate with the interface.
41  */
eth_iface_create(const char * dev_name,const char * if_name,bool tun_only)42 int eth_iface_create(const char *dev_name, const char *if_name, bool tun_only)
43 {
44 	struct ifreq ifr;
45 	int fd, ret = -EINVAL;
46 
47 	fd = open(dev_name, O_RDWR);
48 	if (fd < 0) {
49 		return -errno;
50 	}
51 
52 	(void)memset(&ifr, 0, sizeof(ifr));
53 
54 #ifdef __linux
55 	ifr.ifr_flags = (tun_only ? IFF_TUN : IFF_TAP) | IFF_NO_PI;
56 
57 	strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1);
58 
59 	ret = ioctl(fd, TUNSETIFF, (void *)&ifr);
60 	if (ret < 0) {
61 		ret = -errno;
62 		close(fd);
63 		return ret;
64 	}
65 #endif
66 
67 	return fd;
68 }
69 
eth_iface_remove(int fd)70 int eth_iface_remove(int fd)
71 {
72 	return close(fd);
73 }
74 
75 static int ssystem(const char *fmt, ...)
76 	__attribute__((__format__(__printf__, 1, 2)));
77 
ssystem(const char * fmt,...)78 static int ssystem(const char *fmt, ...)
79 {
80 	char cmd[255];
81 	va_list ap;
82 	int ret;
83 
84 	va_start(ap, fmt);
85 	vsnprintf(cmd, sizeof(cmd), fmt, ap);
86 	va_end(ap);
87 
88 	nsi_print_trace("%s\n", cmd);
89 
90 	ret = system(cmd);
91 
92 	return -WEXITSTATUS(ret);
93 }
94 
eth_wait_data(int fd)95 int eth_wait_data(int fd)
96 {
97 	struct timeval timeout;
98 	fd_set rset;
99 	int ret;
100 
101 	FD_ZERO(&rset);
102 
103 	FD_SET(fd, &rset);
104 
105 	timeout.tv_sec = 0;
106 	timeout.tv_usec = 0;
107 
108 	ret = select(fd + 1, &rset, NULL, NULL, &timeout);
109 	if (ret < 0 && errno != EINTR) {
110 		return -errno;
111 	} else if (ret > 0) {
112 		if (FD_ISSET(fd, &rset)) {
113 			return 0;
114 		}
115 	}
116 
117 	return -EAGAIN;
118 }
119 
eth_clock_gettime(uint64_t * second,uint32_t * nanosecond)120 int eth_clock_gettime(uint64_t *second, uint32_t *nanosecond)
121 {
122 	struct timespec tp;
123 	int ret;
124 
125 	ret = clock_gettime(CLOCK_MONOTONIC_RAW, &tp);
126 	if (ret < 0) {
127 		return -errno;
128 	}
129 
130 	*second = (uint64_t)tp.tv_sec;
131 	*nanosecond = (uint32_t)tp.tv_nsec;
132 
133 	return 0;
134 }
135 
eth_promisc_mode(const char * if_name,bool enable)136 int eth_promisc_mode(const char *if_name, bool enable)
137 {
138 	return ssystem("ip link set dev %s promisc %s",
139 		       if_name, enable ? "on" : "off");
140 }
141