bugfixes: wirefilter getopt_long option list, vde_switch EAGAIN/EWOULDBLOCK (tnx...
[vde.git] / vde-2 / src / vde_switch / tuntap.c
blobcad49fe65c4b09e540ebe3b124d3006ab8f172d9
1 /* Copyright 2005 Renzo Davoli - VDE-2
2 * --pidfile/-p and cleanup management by Mattia Belletti (C) 2004.
3 * Licensed under the GPLv2
4 * Modified by Ludovico Gardenghi 2005 (OSX tuntap support)
5 */
7 #include <stdio.h>
8 #include <fcntl.h>
9 #include <errno.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <syslog.h>
13 #include <stdlib.h>
14 #include <libgen.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <sys/ioctl.h>
18 #include <stdarg.h>
19 #define _GNU_SOURCE
20 #include <getopt.h>
22 #include <config.h>
23 #include <vde.h>
24 #include <vdecommon.h>
26 #include "port.h"
27 #include "switch.h"
28 #include "consmgmt.h"
30 #ifdef HAVE_TUNTAP
32 #ifdef VDE_LINUX
33 #include <net/if.h>
34 #include <linux/if_tun.h>
35 #endif
37 #if defined(VDE_DARWIN) || defined(VDE_FREEBSD)
38 #define TAP_PREFIX "/dev/"
39 #endif
41 #define MAXCMD 128
42 #define MODULENAME "tuntap"
44 static struct swmodule swmi;
45 static struct mod_support modfun;
46 static unsigned int tap_type;
48 struct init_tap {
49 char *tap_dev;
50 struct init_tap *next;
53 struct init_tap *hinit_tap=NULL;
55 static int send_tap(int fd, int ctl_fd, void *packet, int len, void *unused, int port)
57 int n;
59 n = len - write(ctl_fd, packet, len);
60 if(n){
61 int rv=errno;
62 #ifndef VDE_PQ
63 if(errno != EAGAIN && errno != EWOULDBLOCK)
64 printlog(LOG_WARNING,"send_tap port %d: %s",port,strerror(errno));
65 #endif
66 if (n > len)
67 return -rv;
68 else
69 return n;
71 return 0;
74 static void closeport(int fd, int portno)
76 if (fd>0)
77 remove_fd(fd);
80 static void handle_input(unsigned char type,int fd,int revents,int *arg)
82 struct bipacket packet;
83 int len=read(fd, &(packet.p), sizeof(struct packet));
85 if(len < 0){
86 if(errno != EAGAIN && errno != EWOULDBLOCK)
87 printlog(LOG_WARNING,"Reading tap data: %s",strerror(errno));
89 else if(len == 0) {
90 if(errno != EAGAIN && errno != EWOULDBLOCK)
91 printlog(LOG_WARNING,"EOF tap data port: %s",strerror(errno));
92 /* close tap! */
93 } else if (len >= ETH_HEADER_SIZE)
94 handle_in_packet(*arg, &(packet.p), len);
98 static void cleanup(unsigned char type,int fd,int arg)
100 if (fd >= 0)
101 close(fd);
104 static struct option long_options[] = {
105 {"tap", 1, 0, 't'},
107 #define Nlong_options (sizeof(long_options)/sizeof(struct option));
109 static void usage(void)
111 printf(
112 "(opts from tuntap module)\n"
113 " -t, --tap TAP Enable routing through TAP tap interface\n"
114 #ifdef VDE_DARWIN
115 " TAP can be an absolute file name or a relative\n"
116 " one (and will be prefixed with %s). The TAP\n"
117 " device must already exist.\n", TAP_PREFIX
118 #endif
122 static struct init_tap *add_init_tap(struct init_tap *p,char *arg)
124 if (p == NULL) {
125 p=malloc(sizeof(struct init_tap));
126 if (p==NULL)
127 printlog(LOG_WARNING,"Malloc Tap init:%s\n",strerror(errno));
128 else {
129 p->tap_dev=strdup(optarg);
130 p->next=NULL;
132 } else
133 p->next=add_init_tap(p->next,arg);
134 return(p);
137 static struct init_tap *free_init_tap(struct init_tap *p)
139 if (p != NULL) {
140 free_init_tap(p->next);
141 free(p);
143 return NULL;
146 static int parseopt(int c, char *optarg)
148 int outc=0;
149 switch (c) {
150 case 't':
151 hinit_tap=add_init_tap(hinit_tap,optarg);
152 break;
153 default:
154 outc=c;
156 return outc;
159 #ifdef VDE_LINUX
160 int open_tap(char *dev)
162 struct ifreq ifr;
163 int fd;
165 if((fd = open("/dev/net/tun", O_RDWR)) < 0){
166 printlog(LOG_ERR,"Failed to open /dev/net/tun %s",strerror(errno));
167 return(-1);
169 memset(&ifr, 0, sizeof(ifr));
170 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
171 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
172 /*printf("dev=\"%s\", ifr.ifr_name=\"%s\"\n", ifr.ifr_name, dev);*/
173 if(ioctl(fd, TUNSETIFF, (void *) &ifr) < 0){
174 printlog(LOG_ERR,"TUNSETIFF failed %s",strerror(errno));
175 close(fd);
176 return(-1);
178 return(fd);
180 #endif
182 #if defined(VDE_DARWIN) || defined(VDE_FREEBSD)
183 int open_tap(char *dev)
185 int fd;
186 int prefixlen = strlen(TAP_PREFIX);
187 char *path = NULL;
188 if (*dev == '/')
189 fd=open(dev, O_RDWR);
190 else
192 path = malloc(strlen(dev) + prefixlen + 1);
193 if (path != NULL)
195 snprintf(path, strlen(dev) + prefixlen + 1, "%s%s", TAP_PREFIX, dev);
196 fd=open(path, O_RDWR);
197 free(path);
199 else
200 fd = -1;
203 if (fd < 0)
205 printlog(LOG_ERR,"Failed to open tap device %s: %s", (*dev == '/') ? dev : path, strerror(errno));
206 return(-1);
208 return fd;
210 #endif
212 static int newport(int fd, int portno, uid_t user)
214 return fd;
217 static int newtap(char *dev)
219 int tap_fd;
220 tap_fd = open_tap(dev);
221 if (tap_fd>0) {
222 int portno=setup_ep(0,tap_fd,NULL,-1,&modfun);
223 if (portno >= 0) {
224 setup_description(portno,tap_fd,dev);
225 add_fd(tap_fd,tap_type,portno);
226 return portno;
227 } else
228 return -1;
229 } else
230 return -1;
233 static void init(void)
235 if(hinit_tap != NULL) {
236 struct init_tap *p;
237 tap_type=add_type(&swmi,1);
238 for(p=hinit_tap;p != NULL;p=p->next) {
239 if (newtap(p->tap_dev) < 0)
240 printlog(LOG_ERR,"ERROR OPENING tap interface: %s",p->tap_dev);
242 hinit_tap=free_init_tap(hinit_tap);
246 static void delep (int fd, void* data, void *descr)
248 if (descr) free(descr);
251 void start_tuntap(void)
253 modfun.modname=swmi.swmname=MODULENAME;
254 swmi.swmnopts=Nlong_options;
255 swmi.swmopts=long_options;
256 swmi.usage=usage;
257 swmi.parseopt=parseopt;
258 swmi.init=init;
259 swmi.handle_input=handle_input;
260 swmi.cleanup=cleanup;
261 modfun.sender=send_tap;
262 modfun.newport=newport;
263 modfun.delep=delep;
264 modfun.delport=closeport;
265 add_swm(&swmi);
268 #endif