Skip to content

Commit cb60176

Browse files
mikpejohnny-mnemonic
authored andcommitted
Add support for Linux TUN/TAP devices
* configure.ac: check for Linux TUN/TAP support * src/netdev.c: rearrange, fix typos, add support for Linux TUN/TAP devices Signed-off-by: Mikael Pettersson <mikpelinux@gmail.com> Original patch from https://user.it.uu.se/~mpe22148/linux/patches/ia64/ski-1.3.2/ski-1.3.2-tuntap.patch Adapted for Ski post version 1.5.0 Signed-off-by: Johnny Mnemonic <jm@machine-hall.org>
1 parent cec0087 commit cb60176

File tree

2 files changed

+238
-41
lines changed

2 files changed

+238
-41
lines changed

configure.ac

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,26 @@ AS_IF([test "$HOST_OS" = linux], [
8383
])
8484
])
8585

86+
dnl Check that the host supports TUN/TAP devices
87+
AC_CACHE_CHECK([whether TUN/TAP is supported],
88+
ac_cv_have_tun_tap, [
89+
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
90+
#include <string.h>
91+
#include <sys/socket.h>
92+
#include <linux/if.h>
93+
#include <linux/if_tun.h>
94+
]], [[
95+
struct ifreq ifr;
96+
memset(&ifr, 0, sizeof(ifr));
97+
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
98+
]])],[ac_cv_have_tun_tap=yes],[ac_cv_have_tun_tap=no
99+
])
100+
])
101+
102+
AS_IF([test "$ac_cv_have_tun_tap" = yes], [
103+
AC_DEFINE(HAVE_TUN_TAP, 1, [define if you have TUN/TAP support])
104+
])
105+
86106
AS_IF([test "$HOST_OS" = freebsd], [
87107
LDFLAGS="$LDFLAGS -lutil"
88108
])

src/netdev.c

Lines changed: 218 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,213 @@
5353
#include "ui.h"
5454

5555

56+
BOOL ski_nonet; /* when true network is disabled, i.e. no interface is found */
57+
58+
#define ETH_DETACHED 0x0
59+
#define ETH_ATTACHED 0x1
60+
61+
typedef struct _eth_dev_t
62+
{
63+
struct _eth_dev_t *eth_next; /* linked list of devices */
64+
int eth_fd; /* current file descriptor */
65+
int eth_flags; /* attached|detached */
66+
# if !HAVE_TUN_TAP
67+
char eth_name[IFNAMSIZ]; /* real name */
68+
unsigned int eth_ipaddr; /* current ipaddress */
69+
struct sockaddr_ll eth_sa_ll; /* save extra copies on send */
70+
# endif
71+
}
72+
eth_dev_t;
73+
74+
/*
75+
* list of currently detected devices
76+
*/
77+
static eth_dev_t *eth_list;
78+
79+
static inline eth_dev_t *
80+
find_eth (int fd)
81+
{
82+
eth_dev_t *p;
83+
84+
for (p = eth_list; p; p = p->eth_next)
85+
{
86+
if (p->eth_fd == fd)
87+
return p;
88+
}
89+
return NULL;
90+
}
91+
92+
# if HAVE_TUN_TAP
93+
94+
#include <poll.h>
95+
#include <linux/if_tun.h>
96+
97+
int
98+
netdev_open (char *name, unsigned char *macaddr)
99+
{
100+
int fd;
101+
struct ifreq ifr;
102+
eth_dev_t *eth;
103+
104+
if (ski_nonet == YES)
105+
return -1;
106+
107+
fd = open ("/dev/net/tun", O_RDWR);
108+
if (fd == -1)
109+
{
110+
cmdwPrint ("netdev_open: open /dev/net/tun failed: %d\n", errno);
111+
return -1;
112+
}
113+
114+
memset (&ifr, 0, sizeof ifr);
115+
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
116+
if (name)
117+
strncpy (ifr.ifr_name, name, IFNAMSIZ);
118+
119+
if (ioctl (fd, TUNSETIFF, &ifr) < 0)
120+
{
121+
cmdwPrint ("netdev_open: ioctl TUNSETIFF failed: %d\n", errno);
122+
close (fd);
123+
return -1;
124+
}
125+
126+
if (ioctl (fd, SIOCGIFHWADDR, &ifr) == -1)
127+
{
128+
cmdwPrint ("netdev_open: ioctl SIOCGIFHWADDR failed: %d\n", errno);
129+
close (fd);
130+
return -1;
131+
}
132+
133+
memcpy (macaddr, (char *) ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
134+
135+
eth = malloc (sizeof *eth);
136+
if (!eth)
137+
{
138+
cmdwPrint ("netdev_open: malloc failed: %d\n", errno);
139+
close (fd);
140+
return -1;
141+
}
142+
143+
/*
144+
* the device is not yet attached
145+
*/
146+
eth->eth_fd = fd;
147+
eth->eth_next = eth_list;
148+
eth->eth_flags = ETH_DETACHED;
149+
eth_list = eth; /* we're at the head of the list now */
150+
151+
return fd;
152+
}
153+
154+
int
155+
netdev_attach (int fd, unsigned int ipaddr)
156+
{
157+
int r;
158+
eth_dev_t *eth = find_eth (fd);
159+
160+
if (eth == NULL)
161+
progExit ("netdev_attach: can't find eth %d\n", fd);
162+
163+
/*
164+
* prepare for SIGIO: set ownership + asynchronous notification
165+
*/
166+
r = fcntl (fd, F_SETOWN, getpid ());
167+
if (r == -1)
168+
progExit ("netdev_attach: f_setown %d\n", errno);
169+
170+
r = fcntl (fd, F_SETFL, fcntl (fd, F_GETFL, 0) | O_ASYNC | O_NONBLOCK);
171+
if (r == -1)
172+
progExit ("netdev_attach: f_setfl %d\n", errno);
173+
174+
eth->eth_flags = ETH_ATTACHED;
175+
176+
return 0;
177+
}
178+
179+
int
180+
netdev_detach (int fd)
181+
{
182+
int r;
183+
eth_dev_t *eth = find_eth (fd);
184+
185+
if (eth == NULL)
186+
progExit ("netdev_detach: can't find eth %d\n", fd);
187+
188+
/*
189+
* don't notify
190+
*
191+
* should also remove ownership but it does not really matter
192+
*/
193+
r = fcntl (fd, F_SETFL, fcntl (fd, F_GETFL, 0) & (~O_ASYNC | O_NONBLOCK));
194+
if (r == -1)
195+
progExit ("netdev_detach: f_setfl %d\n", errno);
196+
197+
eth->eth_flags = ETH_DETACHED;
198+
199+
return 0;
200+
}
201+
202+
/*
203+
* read the next frame from interface
204+
*/
205+
long
206+
netdev_recv (int fd, char *fbuf, int len)
207+
{
208+
int r;
209+
210+
if ((unsigned long) fbuf & 0x3)
211+
progExit ("receive frame not aligned");
212+
213+
r = read (fd, fbuf, len);
214+
if (r == -1 && errno != EAGAIN)
215+
progExit ("netdev_recv: error on read %d\n", errno);
216+
217+
return (long) (r > 0 ? r : 0);
218+
}
219+
220+
/*
221+
* write next frame to interface
222+
*/
223+
long
224+
netdev_send (int fd, char *fbuf, int len)
225+
{
226+
int r;
227+
eth_dev_t *eth = find_eth (fd);
228+
229+
if ((unsigned long) fbuf & 0x3)
230+
progExit ("trasmit frame not aligned");
231+
232+
if (eth == NULL)
233+
progExit ("netdev_send: can't find %d\n", fd);
234+
235+
r = write (fd, fbuf, len);
236+
if (r == -1)
237+
progExit ("netdev_send: error on write %d\n", errno);
238+
239+
return (long) len;
240+
}
241+
242+
static int
243+
netdev_can_read (int fd)
244+
{
245+
struct pollfd pfd;
246+
int r;
247+
248+
pfd.fd = fd;
249+
pfd.events = POLLIN;
250+
pfd.revents = 0;
251+
r = poll (&pfd, 1, 0);
252+
if (r == -1 || r == 0)
253+
return r;
254+
return pfd.revents & POLLIN;
255+
}
256+
257+
# else /* !HAVE_TUN_TAP */
258+
56259
#define MAX_FRAME_SIZE 1536 /* should be more than enough for ethernet */
57260

58261
#define MAX_FD 256
59262

60-
BOOL ski_nonet; /* when true network is disabled, i.e. no interface is found */
61-
62263
/*
63264
* thanks to tcpdump for the program dump
64265
*
@@ -119,38 +320,6 @@ static struct sock_filter insns[] =
119320
BPF_STMT (BPF_RET + BPF_K, 0xffffffff)
120321
};
121322

122-
#define ETH_DETACHED 0x0
123-
#define ETH_ATTACHED 0x1
124-
125-
typedef struct _eth_dev_t
126-
{
127-
struct _eth_dev_t *eth_next; /* linked list of devices */
128-
char eth_name[IFNAMSIZ]; /* real name */
129-
unsigned int eth_ipaddr; /* current IP address */
130-
int eth_fd; /* current field descriptor */
131-
int eth_flags; /* attached|detached */
132-
struct sockaddr_ll eth_sa_ll; /* save extra copies on send */
133-
}
134-
eth_dev_t;
135-
136-
/*
137-
* list of currently detected devices
138-
*/
139-
static eth_dev_t *eth_list;
140-
141-
static inline eth_dev_t *
142-
find_eth (int fd)
143-
{
144-
eth_dev_t *p;
145-
146-
for (p = eth_list; p; p = p->eth_next)
147-
{
148-
if (p->eth_fd == fd)
149-
return p;
150-
}
151-
return NULL;
152-
}
153-
154323
/*
155324
* taken and adapted from
156325
* https://github.com/torvalds/linux/blob/v3.10/Documentation/networking/ifenslave.c
@@ -394,7 +563,6 @@ netdev_detach (int fd)
394563
return 0;
395564
}
396565

397-
398566
/*
399567
* read the next frame from interface
400568
*/
@@ -437,6 +605,20 @@ netdev_send (int fd, char *fbuf, int len)
437605
return (long) len;
438606
}
439607

608+
static int
609+
netdev_can_read (int fd)
610+
{
611+
char c;
612+
613+
/*
614+
* We can't use FIONREAD here because it's only supported
615+
* by TCP sockets.
616+
*/
617+
return recv (fd, &c, 1, MSG_PEEK);
618+
}
619+
620+
# endif /* !HAVE_TUN_TAP */
621+
440622
/*
441623
* check if SIGIO was because of network I/O
442624
* the other possible reason is keyboard input
@@ -449,7 +631,6 @@ int
449631
isnetio (void)
450632
{
451633
int r;
452-
char c;
453634
eth_dev_t *p;
454635

455636
if (eth_list == NULL)
@@ -462,11 +643,7 @@ isnetio (void)
462643
if (p->eth_flags != ETH_ATTACHED)
463644
continue;
464645

465-
/*
466-
* We can't use FIONREAD here because it's only supported
467-
* by TCP sockets.
468-
*/
469-
r = recv (p->eth_fd, &c, 1, MSG_PEEK);
646+
r = netdev_can_read (p->eth_fd);
470647
if (r > 0)
471648
return 1;
472649

0 commit comments

Comments
 (0)