1 /////////////////////////////////////////////////////////////////////////
2 // $Id: eth_tuntap.cc,v 1.29 2008/12/11 18:01:56 vruppert Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2001 MandrakeSoft S.A.
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.
36 #define NO_DEVICE_INCLUDES
39 #if BX_NETWORKING && defined(HAVE_TUNTAP)
43 #define LOG_THIS bx_devices.pluginNE2kDevice->
46 #include <sys/param.h>
47 #include <sys/ioctl.h>
52 #include <sys/resource.h>
54 #include <asm/types.h>
56 #include <sys/types.h>
58 #include <sys/socket.h>
62 #include <linux/netlink.h>
64 #include <linux/if_tun.h>
67 #if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
68 #include <net/if_tap.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
{
84 bx_tuntap_pktmover_c(const char *netif
, const char *macaddr
,
86 void *rxarg
, const char *script
);
87 void sendpkt(void *buf
, unsigned io_len
);
91 static void rx_timer_handler(void *);
93 Bit8u guest_macaddr
[6];
94 #if BX_ETH_TUNTAP_LOGGING
95 FILE *txlog
, *txlog_txt
, *rxlog
, *rxlog_txt
;
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
{
106 bx_tuntap_locator_c(void) : eth_locator_c("tuntap") {}
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
));
117 // Define the methods for the bx_tuntap_pktmover derived class
121 bx_tuntap_pktmover_c::bx_tuntap_pktmover_c(const char *netif
,
123 eth_rx_handler_t rxh
,
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);
140 BX_PANIC (("socket creation: %s", strerror(errno
)));
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
)));
151 if (!(ifr
.ifr_flags
& IFF_RUNNING
)) {
152 BX_PANIC (("%s device is not running", netif
));
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
)));
167 fd
= open (filename
, O_RDWR
);
169 char intname
[IFNAMSIZ
];
170 strcpy(intname
,netif
);
171 fd
=tun_alloc(intname
);
173 BX_PANIC(("open failed on %s: %s", netif
, strerror (errno
)));
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
)));
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
));
196 this->rx_timer_index
=
197 bx_pc_system
.register_timer(this, this->rx_timer_handler
, 1000,
198 1, 1, "eth_tuntap"); // continuous, active
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");
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");
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
)));
239 BX_DEBUG (("wrote %d bytes on tuntap - 14 bytes Ethernet header", io_len
));
242 Bit8u txbuf
[BX_PACKET_BUFSIZE
];
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
)));
250 BX_DEBUG (("wrote %d bytes + 2 byte pad on tuntap", io_len
));
253 unsigned int size
= write (fd
, buf
, io_len
);
254 if (size
!= io_len
) {
255 BX_PANIC (("write on tuntap device: %s", strerror (errno
)));
257 BX_DEBUG (("wrote %d bytes on tuntap", io_len
));
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
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 ()
290 Bit8u buf
[BX_PACKET_BUFSIZE
];
294 #ifdef __APPLE__ //FIXME:hack
297 buf
[0] = buf
[6] = 0xFE;
298 buf
[1] = buf
[7] = 0xFD;
300 nbytes
+= read (fd
, buf
+nbytes
, sizeof(buf
)-nbytes
);
303 nbytes
= read (fd
, buf
, sizeof(buf
));
304 // hack: discard first two bytes
308 nbytes
= read (fd
, buf
, sizeof(buf
));
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
324 BX_DEBUG (("tuntap read returned %d bytes", nbytes
));
325 #ifdef __APPLE__ //FIXME:hack
331 BX_ERROR (("tuntap read error: %s", strerror(errno
)));
334 #if BX_ETH_TUNTAP_LOGGING
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
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]));
356 BX_INFO (("packet too short (%d), padding to 60", nbytes
));
359 (*rxh
)(rxarg
, rxbuf
, nbytes
);
362 int tun_alloc(char *dev
)
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
== ':') {
376 if ((fd
= open(dev
, O_RDWR
)) < 0)
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) {
392 strncpy(dev
, ifr
.ifr_name
, IFNAMSIZ
);
395 ioctl(fd
, TUNSETNOCSUM
, 1);
401 #endif /* if BX_NETWORKING && defined HAVE_TUNTAP */