- added instructions how to update the online documentation
[bochs-mirror.git] / iodev / eth_tuntap.cc
blob4507f5b3d2605070d30ef928b50659192abc5255
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: eth_tuntap.cc,v 1.29 2008/12/11 18:01:56 vruppert Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2001 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 /////////////////////////////////////////////////////////////////////////
29 // eth_tuntap.cc - TUN/TAP interface by Renzo Davoli <renzo@cs.unibo.it>
31 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
32 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
33 // is used to know when we are exporting symbols and when we are importing.
34 #define BX_PLUGGABLE
36 #define NO_DEVICE_INCLUDES
37 #include "iodev.h"
39 #if BX_NETWORKING && defined(HAVE_TUNTAP)
41 #include "eth.h"
43 #define LOG_THIS bx_devices.pluginNE2kDevice->
45 #include <signal.h>
46 #include <sys/param.h>
47 #include <sys/ioctl.h>
48 #ifndef __APPLE__
49 #include <sys/poll.h>
50 #endif
51 #include <sys/time.h>
52 #include <sys/resource.h>
53 #ifdef __linux__
54 #include <asm/types.h>
55 #else
56 #include <sys/types.h>
57 #endif
58 #include <sys/socket.h>
59 #include <sys/uio.h>
60 #include <sys/wait.h>
61 #ifdef __linux__
62 #include <linux/netlink.h>
63 #include <linux/if.h>
64 #include <linux/if_tun.h>
65 #else
66 #include <net/if.h>
67 #if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
68 #include <net/if_tap.h>
69 #endif
70 #endif
71 #include <assert.h>
72 #include <fcntl.h>
73 #include <errno.h>
75 #define BX_ETH_TUNTAP_LOGGING 0
77 int tun_alloc(char *dev);
80 // Define the class. This is private to this module
82 class bx_tuntap_pktmover_c : public eth_pktmover_c {
83 public:
84 bx_tuntap_pktmover_c(const char *netif, const char *macaddr,
85 eth_rx_handler_t rxh,
86 void *rxarg, const char *script);
87 void sendpkt(void *buf, unsigned io_len);
88 private:
89 int fd;
90 int rx_timer_index;
91 static void rx_timer_handler(void *);
92 void rx_timer ();
93 Bit8u guest_macaddr[6];
94 #if BX_ETH_TUNTAP_LOGGING
95 FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
96 #endif
101 // Define the static class that registers the derived pktmover class,
102 // and allocates one on request.
104 class bx_tuntap_locator_c : public eth_locator_c {
105 public:
106 bx_tuntap_locator_c(void) : eth_locator_c("tuntap") {}
107 protected:
108 eth_pktmover_c *allocate(const char *netif, const char *macaddr,
109 eth_rx_handler_t rxh,
110 void *rxarg, const char *script) {
111 return (new bx_tuntap_pktmover_c(netif, macaddr, rxh, rxarg, script));
113 } bx_tuntap_match;
117 // Define the methods for the bx_tuntap_pktmover derived class
120 // the constructor
121 bx_tuntap_pktmover_c::bx_tuntap_pktmover_c(const char *netif,
122 const char *macaddr,
123 eth_rx_handler_t rxh,
124 void *rxarg,
125 const char *script)
127 int flags;
129 #ifdef NEVERDEF
130 if (strncmp (netif, "tun", 3) != 0) {
131 BX_PANIC (("eth_tuntap: interface name (%s) must be tun", netif));
133 char filename[BX_PATHNAME_LEN];
134 sprintf (filename, "/dev/net/%s", netif);
136 // check if the TUN/TAP devices is running, and turn on ARP. This is based
137 // on code from the Mac-On-Linux project. http://http://www.maconlinux.org/
138 int sock = socket(AF_INET, SOCK_DGRAM, 0);
139 if (sock < 0) {
140 BX_PANIC (("socket creation: %s", strerror(errno)));
141 return;
143 struct ifreq ifr;
144 memset(&ifr, 0, sizeof(ifr));
145 strncpy(ifr.ifr_name, netif, sizeof(ifr.ifr_name));
146 if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
147 BX_PANIC (("SIOCGIFFLAGS on %s: %s", netif, strerror (errno)));
148 close(sock);
149 return;
151 if (!(ifr.ifr_flags & IFF_RUNNING)) {
152 BX_PANIC (("%s device is not running", netif));
153 close(sock);
154 return;
156 if ((ifr.ifr_flags & IFF_NOARP)) {
157 BX_INFO (("turn on ARP for %s device", netif));
158 ifr.ifr_flags &= ~IFF_NOARP;
159 if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
160 BX_PANIC (("SIOCSIFFLAGS: %s", strerror(errno)));
161 close(sock);
162 return;
165 close(sock);
167 fd = open (filename, O_RDWR);
168 #endif
169 char intname[IFNAMSIZ];
170 strcpy(intname,netif);
171 fd=tun_alloc(intname);
172 if (fd < 0) {
173 BX_PANIC(("open failed on %s: %s", netif, strerror (errno)));
174 return;
177 /* set O_ASYNC flag so that we can poll with read() */
178 if ((flags = fcntl(fd, F_GETFL)) < 0) {
179 BX_PANIC (("getflags on tun device: %s", strerror (errno)));
181 flags |= O_NONBLOCK;
182 if (fcntl(fd, F_SETFL, flags) < 0) {
183 BX_PANIC(("set tun device flags: %s", strerror (errno)));
186 BX_INFO(("eth_tuntap: opened %s device", netif));
188 /* Execute the configuration script */
189 if((script != NULL) && (strcmp(script, "") != 0) && (strcmp(script, "none") != 0))
191 if (execute_script(script, intname) < 0)
192 BX_ERROR (("execute script '%s' on %s failed", script, intname));
195 // Start the rx poll
196 this->rx_timer_index =
197 bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
198 1, 1, "eth_tuntap"); // continuous, active
199 this->rxh = rxh;
200 this->rxarg = rxarg;
201 memcpy(&guest_macaddr[0], macaddr, 6);
202 #if BX_ETH_TUNTAP_LOGGING
203 // eventually Bryce wants txlog to dump in pcap format so that
204 // tcpdump -r FILE can read it and interpret packets.
205 txlog = fopen ("ne2k-tx.log", "wb");
206 if (!txlog) BX_PANIC (("open ne2k-tx.log failed"));
207 txlog_txt = fopen ("ne2k-txdump.txt", "wb");
208 if (!txlog_txt) BX_PANIC (("open ne2k-txdump.txt failed"));
209 fprintf (txlog_txt, "tuntap packetmover readable log file\n");
210 fprintf (txlog_txt, "net IF = %s\n", netif);
211 fprintf (txlog_txt, "MAC address = ");
212 for (int i=0; i<6; i++)
213 fprintf (txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
214 fprintf (txlog_txt, "\n--\n");
215 fflush (txlog_txt);
217 rxlog = fopen ("ne2k-rx.log", "wb");
218 if (!rxlog) BX_PANIC (("open ne2k-rx.log failed"));
219 rxlog_txt = fopen ("ne2k-rxdump.txt", "wb");
220 if (!rxlog_txt) BX_PANIC (("open ne2k-rxdump.txt failed"));
221 fprintf (rxlog_txt, "tuntap packetmover readable log file\n");
222 fprintf (rxlog_txt, "net IF = %s\n", netif);
223 fprintf (rxlog_txt, "MAC address = ");
224 for (int i=0; i<6; i++)
225 fprintf (rxlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
226 fprintf (rxlog_txt, "\n--\n");
227 fflush (rxlog_txt);
229 #endif
232 void bx_tuntap_pktmover_c::sendpkt(void *buf, unsigned io_len)
234 #ifdef __APPLE__ //FIXME
235 unsigned int size = write (fd, (char*)buf+14, io_len-14);
236 if (size != io_len-14) {
237 BX_PANIC (("write on tuntap device: %s", strerror (errno)));
238 } else {
239 BX_DEBUG (("wrote %d bytes on tuntap - 14 bytes Ethernet header", io_len));
241 #elif NEVERDEF
242 Bit8u txbuf[BX_PACKET_BUFSIZE];
243 txbuf[0] = 0;
244 txbuf[1] = 0;
245 memcpy (txbuf+2, buf, io_len);
246 unsigned int size = write (fd, txbuf, io_len+2);
247 if (size != io_len+2) {
248 BX_PANIC (("write on tuntap device: %s", strerror (errno)));
249 } else {
250 BX_DEBUG (("wrote %d bytes + 2 byte pad on tuntap", io_len));
252 #else
253 unsigned int size = write (fd, buf, io_len);
254 if (size != io_len) {
255 BX_PANIC (("write on tuntap device: %s", strerror (errno)));
256 } else {
257 BX_DEBUG (("wrote %d bytes on tuntap", io_len));
259 #endif
260 #if BX_ETH_TUNTAP_LOGGING
261 BX_DEBUG (("sendpkt length %u", io_len));
262 // dump raw bytes to a file, eventually dump in pcap format so that
263 // tcpdump -r FILE can interpret them for us.
264 int n = fwrite (buf, io_len, 1, txlog);
265 if (n != 1) BX_ERROR (("fwrite to txlog failed", io_len));
266 // dump packet in hex into an ascii log file
267 fprintf (txlog_txt, "NE2K transmitting a packet, length %u\n", io_len);
268 Bit8u *charbuf = (Bit8u *)buf;
269 for (n=0; n<io_len; n++) {
270 if (((n % 16) == 0) && n>0)
271 fprintf (txlog_txt, "\n");
272 fprintf (txlog_txt, "%02x ", charbuf[n]);
274 fprintf (txlog_txt, "\n--\n");
275 // flush log so that we see the packets as they arrive w/o buffering
276 fflush (txlog);
277 fflush (txlog_txt);
278 #endif
281 void bx_tuntap_pktmover_c::rx_timer_handler (void *this_ptr)
283 bx_tuntap_pktmover_c *class_ptr = (bx_tuntap_pktmover_c *) this_ptr;
284 class_ptr->rx_timer();
287 void bx_tuntap_pktmover_c::rx_timer ()
289 int nbytes;
290 Bit8u buf[BX_PACKET_BUFSIZE];
291 Bit8u *rxbuf;
292 if (fd<0) return;
294 #ifdef __APPLE__ //FIXME:hack
295 nbytes = 14;
296 bzero(buf, nbytes);
297 buf[0] = buf[6] = 0xFE;
298 buf[1] = buf[7] = 0xFD;
299 buf[12] = 8;
300 nbytes += read (fd, buf+nbytes, sizeof(buf)-nbytes);
301 rxbuf=buf;
302 #elif NEVERDEF
303 nbytes = read (fd, buf, sizeof(buf));
304 // hack: discard first two bytes
305 rxbuf = buf+2;
306 nbytes-=2;
307 #else
308 nbytes = read (fd, buf, sizeof(buf));
309 rxbuf=buf;
310 #endif
312 // hack: TUN/TAP device likes to create an ethernet header which has
313 // the same source and destination address FE:FD:00:00:00:00.
314 // Change the dest address to FE:FD:00:00:00:01.
315 if (!memcmp(&rxbuf[0], &rxbuf[6], 6)) {
316 rxbuf[5] = guest_macaddr[5];
319 #ifdef __APPLE__ //FIXME:hack
320 if (nbytes>14)
321 #else
322 if (nbytes>0)
323 #endif
324 BX_DEBUG (("tuntap read returned %d bytes", nbytes));
325 #ifdef __APPLE__ //FIXME:hack
326 if (nbytes<14) {
327 #else
328 if (nbytes<0) {
329 #endif
330 if (errno != EAGAIN)
331 BX_ERROR (("tuntap read error: %s", strerror(errno)));
332 return;
334 #if BX_ETH_TUNTAP_LOGGING
335 if (nbytes > 0) {
336 BX_DEBUG (("receive packet length %u", nbytes));
337 // dump raw bytes to a file, eventually dump in pcap format so that
338 // tcpdump -r FILE can interpret them for us.
339 int n = fwrite (rxbuf, nbytes, 1, rxlog);
340 if (n != 1) BX_ERROR (("fwrite to rxlog failed", nbytes));
341 // dump packet in hex into an ascii log file
342 fprintf (rxlog_txt, "NE2K received a packet, length %u\n", nbytes);
343 for (n=0; n<nbytes; n++) {
344 if (((n % 16) == 0) && n>0)
345 fprintf (rxlog_txt, "\n");
346 fprintf (rxlog_txt, "%02x ", rxbuf[n]);
348 fprintf (rxlog_txt, "\n--\n");
349 // flush log so that we see the packets as they arrive w/o buffering
350 fflush (rxlog);
351 fflush (rxlog_txt);
353 #endif
354 BX_DEBUG(("eth_tuntap: got packet: %d bytes, dst=%02x:%02x:%02x:%02x:%02x:%02x, src=%02x:%02x:%02x:%02x:%02x:%02x", nbytes, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9], rxbuf[10], rxbuf[11]));
355 if (nbytes < 60) {
356 BX_INFO (("packet too short (%d), padding to 60", nbytes));
357 nbytes = 60;
359 (*rxh)(rxarg, rxbuf, nbytes);
362 int tun_alloc(char *dev)
364 struct ifreq ifr;
365 char *ifname;
366 int fd, err;
368 // split name into device:ifname if applicable, to allow for opening
369 // persistent tuntap devices
370 for (ifname = dev; *ifname; ifname++) {
371 if (*ifname == ':') {
372 *(ifname++) = '\0';
373 break;
376 if ((fd = open(dev, O_RDWR)) < 0)
377 return -1;
378 #ifdef __linux__
379 memset(&ifr, 0, sizeof(ifr));
381 /* Flags: IFF_TUN - TUN device (no Ethernet headers)
382 * IFF_TAP - TAP device
384 * IFF_NO_PI - Do not provide packet information
386 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
387 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
388 if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) {
389 close(fd);
390 return err;
392 strncpy(dev, ifr.ifr_name, IFNAMSIZ);
393 dev[IFNAMSIZ-1]=0;
395 ioctl(fd, TUNSETNOCSUM, 1);
396 #endif
398 return fd;
401 #endif /* if BX_NETWORKING && defined HAVE_TUNTAP */