Avoid segmentation fault if no tap name given (thanks to Filippo Giunchedi)
[vde.git] / vde-2 / tuntap.c
bloba5b415cae96d6d8543394601ea5b9cf4808bbe4e
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 <config.h>
8 #include <stdio.h>
9 #include <fcntl.h>
10 #include <errno.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <syslog.h>
14 #include <stdlib.h>
15 #include <libgen.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <sys/ioctl.h>
19 #include <stdarg.h>
20 #define _GNU_SOURCE
21 #include <getopt.h>
22 #include <vde.h>
24 #ifdef VDE_LINUX
25 #include <net/if.h>
26 #include <linux/if_tun.h>
27 #endif
29 #ifdef VDE_DARWIN
30 #define TAP_PREFIX "/dev/"
31 #endif
33 #include <port.h>
34 #include <switch.h>
35 #include <consmgmt.h>
38 #define MAXCMD 128
39 #define MODULENAME "tuntap"
41 static struct swmodule swmi;
42 static struct mod_support modfun;
43 static unsigned int tap_type;
45 struct init_tap {
46 char *tap_dev;
47 struct init_tap *next;
50 struct init_tap *hinit_tap=NULL;
52 static int send_tap(int fd, int ctl_fd, void *packet, int len, void *unused, int port)
54 int n;
56 n = len - write(ctl_fd, packet, len);
57 if(n){
58 int rv=errno;
59 #ifndef VDE_PQ
60 if(errno != EAGAIN) printlog(LOG_WARNING,"send_tap port %d: %s",port,strerror(errno));
61 #endif
62 if (n > len)
63 return -rv;
64 else
65 return n;
67 return 0;
70 static void closeport(int fd, int portno)
72 if (fd>0)
73 remove_fd(fd);
76 static void handle_input(unsigned char type,int fd,int revents,int *arg)
78 struct bipacket packet;
79 int len=read(fd, &(packet.p), sizeof(struct packet));
81 if(len < 0){
82 if(errno != EAGAIN) printlog(LOG_WARNING,"Reading tap data: %s",strerror(errno));
84 else if(len == 0) {
85 if(errno != EAGAIN) printlog(LOG_WARNING,"EOF tap data port: %s",strerror(errno));
86 /* close tap! */
87 } else if (len >= ETH_HEADER_SIZE)
88 handle_in_packet(*arg, &(packet.p), len);
92 static void cleanup(unsigned char type,int fd,int arg)
94 if (fd >= 0)
95 close(fd);
98 static struct option long_options[] = {
99 {"tap", 1, 0, 't'},
101 #define Nlong_options (sizeof(long_options)/sizeof(struct option));
103 static void usage(void)
105 printf(
106 "(opts from tuntap module)\n"
107 " -t, --tap TAP Enable routing through TAP tap interface\n"
108 #ifdef VDE_DARWIN
109 " TAP can be an absolute file name or a relative\n"
110 " one (and will be prefixed with %s). The TAP\n"
111 " device must already exist.\n", TAP_PREFIX
112 #endif
116 static struct init_tap *add_init_tap(struct init_tap *p,char *arg)
118 if (p == NULL) {
119 p=malloc(sizeof(struct init_tap));
120 if (p==NULL)
121 printlog(LOG_WARNING,"Malloc Tap init:%s\n",strerror(errno));
122 else {
123 p->tap_dev=strdup(optarg);
124 p->next=NULL;
126 } else
127 p->next=add_init_tap(p->next,arg);
128 return(p);
131 static struct init_tap *free_init_tap(struct init_tap *p)
133 if (p != NULL) {
134 free_init_tap(p->next);
135 free(p);
137 return NULL;
140 static int parseopt(int c, char *optarg)
142 int outc=0;
143 switch (c) {
144 case 't':
145 hinit_tap=add_init_tap(hinit_tap,optarg);
146 break;
147 default:
148 outc=c;
150 return outc;
153 #ifdef VDE_LINUX
154 int open_tap(char *dev)
156 struct ifreq ifr;
157 int fd;
159 if((fd = open("/dev/net/tun", O_RDWR)) < 0){
160 printlog(LOG_ERR,"Failed to open /dev/net/tun %s",strerror(errno));
161 return(-1);
163 memset(&ifr, 0, sizeof(ifr));
164 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
165 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
166 /*printf("dev=\"%s\", ifr.ifr_name=\"%s\"\n", ifr.ifr_name, dev);*/
167 if(ioctl(fd, TUNSETIFF, (void *) &ifr) < 0){
168 printlog(LOG_ERR,"TUNSETIFF failed %s",strerror(errno));
169 close(fd);
170 return(-1);
172 return(fd);
174 #endif
176 #ifdef VDE_DARWIN
177 int open_tap(char *dev)
179 int fd;
180 int prefixlen = strlen(TAP_PREFIX);
181 char *path = NULL;
182 if (*dev == '/')
183 fd=open(dev, O_RDWR);
184 else
186 path = malloc(strlen(dev) + prefixlen + 1);
187 if (path != NULL)
189 snprintf(path, strlen(dev) + prefixlen + 1, "%s%s", TAP_PREFIX, dev);
190 fd=open(path, O_RDWR);
191 free(path);
193 else
194 fd = -1;
197 if (fd < 0)
199 printlog(LOG_ERR,"Failed to open tap device %s: %s", (*dev == '/') ? dev : path, strerror(errno));
200 return(-1);
202 return fd;
204 #endif
206 static int newport(int fd, int portno)
208 return fd;
211 static int newtap(char *dev)
213 int tap_fd;
214 tap_fd = open_tap(dev);
215 if (tap_fd>0) {
216 int portno=setup_ep(0,tap_fd,NULL,&modfun);
217 if (portno >= 0) {
218 setup_description(portno,tap_fd,dev);
219 add_fd(tap_fd,tap_type,portno);
220 return portno;
221 } else
222 return -1;
223 } else
224 return -1;
227 static void init(void)
229 if(hinit_tap != NULL) {
230 struct init_tap *p;
231 tap_type=add_type(&swmi,1);
232 for(p=hinit_tap;p != NULL;p=p->next) {
233 if (newtap(p->tap_dev) < 0)
234 printlog(LOG_ERR,"ERROR OPENING tap interface: %s",p->tap_dev);
236 hinit_tap=free_init_tap(hinit_tap);
240 static void delep (int fd, void* data, void *descr)
242 if (descr) free(descr);
245 void start_tuntap(void)
247 modfun.modname=swmi.swmname=MODULENAME;
248 swmi.swmnopts=Nlong_options;
249 swmi.swmopts=long_options;
250 swmi.usage=usage;
251 swmi.parseopt=parseopt;
252 swmi.init=init;
253 swmi.handle_input=handle_input;
254 swmi.cleanup=cleanup;
255 modfun.sender=send_tap;
256 modfun.newport=newport;
257 modfun.delep=delep;
258 modfun.delport=closeport;
259 add_swm(&swmi);