Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
ethertap.c
Go to the documentation of this file.
1 /* Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
2  Copyright (C)2018,2020-2021 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17 
18 
19 /* NOTES - NOTES - NOTES - NOTES
20 
21 Ether-TAP interface handling for Linux. Currently, I don't know
22 if other OSes has some kind of TAP interface as well (MacOS
23 - AFAIK - supports only TUN, but not TAP, what we need here,
24 I have no idea about Windows).
25 
26 Assuming that you have Linux which is needed:
27 
28  First, please set the TAP device up, like:
29 
30 lgb@oxygene:~$ sudo ip tuntap add mode tap user lgb mega65
31 lgb@oxygene:~$ sudo ip addr add 10.10.10.1/24 dev mega65
32 lgb@oxygene:~$ sudo ip link set mega65 up
33 
34 Here, I choose 'mega65' as the interface name, and 'lgb' is my
35 user name. The user name is needed so an unprivileged process
36 then (this program, or later Xemu) can use the TAP inteface
37 without needing to run the program as root, which would be
38 very dangerous especially for a program not designed to be
39 security aware, like an emulator (Xemu) otherwise. Also, the
40 10.10.10.1 is set for the interface address, with netmask of
41 /24 (255.255.255.0).
42 
43 Here, mega65 parameter is the device name we configured above.
44 I run as user lgb, what I configured the device for (note:
45 the program can run without it, but then it allocates a new
46 interface, it won't work a user only as root, but I want to
47 avoid that, as the TAP handling part needed for the Xemu
48 and it's really a bad idea to run Xemu as root for obvious
49 security reasons! Even if it would mean that Xemu would be
50 able to configure the device for itself, hmmm ...) */
51 
52 #ifdef HAVE_ETHERTAP
53 
55 #include "xemu/ethertap.h"
56 
57 #include <string.h>
58 #include <sys/types.h>
59 #include <sys/stat.h>
60 #include <sys/ioctl.h>
61 #include <sys/time.h>
62 #include <sys/select.h>
63 #include <fcntl.h>
64 #include <unistd.h>
65 // net/if.h is not needed in my Linux box, but it seems it is needed on older Ubuntu versions at least, so ...
66 #include <net/if.h>
67 // disabling linux/if.h works for Ubuntu 14.04 / GCC 6.4.0
68 // HOWEVER it seems without this, it will fail on Ubuntu 20.04. Eh, enabling it again ...
69 #include <linux/if.h>
70 #include <linux/if_tun.h>
71 #include <errno.h>
72 
73 
74 #define CLONE_TUNTAP_NAME "/dev/net/tun"
75 
76 
77 static volatile int tuntap_fd = -1;
78 static int nonblocking = 0;
79 
80 
81 static int xemu_tuntap_set_nonblocking ( int fd, int is_nonblocking )
82 {
83  int flags;
84  if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
85  flags = 0;
86  if (is_nonblocking)
87  flags |= O_NONBLOCK;
88  else
89  flags &= ~O_NONBLOCK;
90  nonblocking = is_nonblocking;
91  return fcntl(fd, F_SETFL, flags);
92 }
93 
94 
95 int xemu_tuntap_close ( void )
96 {
97  if (tuntap_fd >= 0) {
98  int fd = tuntap_fd;
99  tuntap_fd = -1;
100  if (nonblocking)
101  xemu_tuntap_set_nonblocking(fd, 0);
102  return close(fd);
103  }
104  return 0;
105 }
106 
107 
108 int xemu_tuntap_read ( void *buffer, int min_size, int max_size )
109 {
110  int got = 0;
111  if (tuntap_fd < 0)
112  return 0;
113  while (got < min_size) {
114  int r = read(tuntap_fd, buffer, max_size);
115  printf("ETH-LOW: read ret %d %s\n", r, r >= 0 ? "NO-ERROR-CONDITION" : strerror(errno));
116  if (!r) {
117  return got;
118  } else if (r < 0) {
119  if (errno == EINTR) {
120  continue; // try again if it's interrupted. I am not sure if it's the correct behaviour
121  } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
122  if (nonblocking)
123  return (got > 0) ? got : -2; // -2: signal initial EAGAIN situation
124  else
125  return -1;
126  } else {
127  return -1;
128  }
129  }
130  max_size -= r;
131  got += r;
132  buffer += r;
133  }
134  return got;
135 }
136 
137 
138 int xemu_tuntap_write ( void *buffer, int size )
139 {
140  int did = 0;
141  if (tuntap_fd < 0)
142  return 0;
143  while (size > 0) {
144  int w = write(tuntap_fd, buffer, size);
145  if (!w) {
146  return did;
147  } else if (w < 0) {
148  if (errno == EINTR) {
149  continue;
150  } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
151  if (nonblocking)
152  return (did > 0) ? did : -2;
153  else
154  return -1;
155  } else {
156  return -1;
157  }
158  }
159  size -= w;
160  did += w;
161  buffer += w;
162  }
163  return did;
164 }
165 
166 
167 int xemu_tuntap_select ( int flags, int timeout_usecs )
168 {
169  int r;
170  fd_set fdsr, fdsw;
171  do {
172  struct timeval timeout, *timeout_p;
173  FD_ZERO(&fdsr);
174  FD_ZERO(&fdsw);
175  FD_SET(tuntap_fd, &fdsr);
176  FD_SET(tuntap_fd, &fdsw);
177  if (timeout_usecs >= 0) {
178  timeout.tv_sec = timeout_usecs / 1000000;
179  timeout.tv_usec = timeout_usecs % 1000000;
180  timeout_p = &timeout;
181  } else
182  timeout_p = NULL;
183  r = select(
184  tuntap_fd + 1,
185  (flags & XEMU_TUNTAP_SELECT_R) ? &fdsr : NULL,
186  (flags & XEMU_TUNTAP_SELECT_W) ? &fdsw : NULL,
187  NULL,
188  timeout_p
189  );
190  } while (r < 0 && errno == EINTR);
191  return (r > 0) ? ((FD_ISSET(tuntap_fd, &fdsr) ? XEMU_TUNTAP_SELECT_R : 0) | (FD_ISSET(tuntap_fd, &fdsw) ? XEMU_TUNTAP_SELECT_W : 0)) : r;
192 }
193 
194 
195 /* dev_in: device name to attach too, if it's zero sized string or NULL,
196  the kernel will allocate a new name,
197  but for that Xemu needs network admin capability (typically being 'root')
198  which is not so much a good idea!
199  dev_out: a large enough buffer where name will be written back to. If it's
200  NULL pointer, it won't be used.
201  dev_out_size: size of dev_out buffer storage
202  flags: XEMU_TUNTAP_IS_TAP / XEMU_TUNTAP_IS_TUN, only one, but one is compulsory!
203  XEMU_TUNTAP_NO_PI can be OR'ed to the type above though
204  Some core concepts are nicely summarized here:
205  http://backreference.org/2010/03/26/tuntap-interface-tutorial/
206 */
207 
208 int xemu_tuntap_alloc ( const char *dev_in, char *dev_out, int dev_out_size, unsigned int flags )
209 {
210  if (tuntap_fd >= 0)
211  return tuntap_fd;
212  if (dev_in && strlen(dev_in) > IFNAMSIZ - 1)
213  return -1;
214  struct ifreq ifr;
215  int fd, err;
216  nonblocking = 0;
217  memset(&ifr, 0, sizeof(ifr));
218  ifr.ifr_flags = 0;
219  switch (flags & 0xFF) {
220  case XEMU_TUNTAP_IS_TAP:
221  ifr.ifr_flags = IFF_TAP;
222  break;
223  case XEMU_TUNTAP_IS_TUN:
224  ifr.ifr_flags = IFF_TUN;
225  break;
226  default:
227  return -1;
228  }
229  if (flags & XEMU_TUNTAP_NO_PI)
230  ifr.ifr_flags |= IFF_NO_PI;
231  if ((fd = open(CLONE_TUNTAP_NAME, O_RDWR)) < 0)
232  return fd;
233  if (dev_in && *dev_in)
234  strncpy(ifr.ifr_name, dev_in, IFNAMSIZ - 1);
235  else
236  ifr.ifr_name[0] = 0;
237  if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) {
238  close(fd);
239  return err;
240  }
241  if (dev_out) {
242  if (strlen(ifr.ifr_name) >= dev_out_size) {
243  close(fd);
244  return -1;
245  } else
246  strcpy(dev_out, ifr.ifr_name);
247  }
248  if (flags & XEMU_TUNTAP_NONBLOCKING_IO) {
249  // sets non blocking I/O up, if requested
250  if (xemu_tuntap_set_nonblocking(fd, 1)) {
251  close(fd);
252  return -1;
253  }
254  }
255  tuntap_fd = fd; // file descriptor is available now, good
256  return fd; // also return the FD, but note, that it should not be used too much currently outside of this source
257 }
258 
259 #endif
flags
Uint8 flags
Definition: z8k1.c:126
fd
int fd
Definition: hdos.c:62
ethertap.h
emutools_basicdefs.h
compress_sd_image.r
def r
Definition: compress_sd_image.py:76
size
int size
Definition: inject.c:37