tagging vde-2 version 2.3.2
[vde.git] / 2.3.2 / src / vde_switch / tuntap.c
blob9f3c0a2b472c39f8d2bfbc6a92aa9bbbb165b21e
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_ctl, int fd_data, void *packet, int len, int port)
57 int n;
59 n = len - write(fd_ctl, packet, len);
60 if(n > len){
61 int rv=errno;
62 if(rv != EAGAIN && rv != EWOULDBLOCK)
63 printlog(LOG_WARNING,"send_tap port %d: %s",port,strerror(errno));
64 else
65 rv=EWOULDBLOCK;
66 return -rv;
68 return n;
71 static void handle_io(unsigned char type,int fd,int revents,void *private_data)
73 struct endpoint *ep=private_data;
74 #ifdef VDE_PQ2
75 if (revents & POLLOUT)
76 handle_out_packet(ep);
77 #endif
78 if (revents & POLLIN) {
79 struct bipacket packet;
80 int len=read(fd, &(packet.p), sizeof(struct packet));
82 if(len < 0){
83 if(errno != EAGAIN && errno != EWOULDBLOCK)
84 printlog(LOG_WARNING,"Reading tap data: %s",strerror(errno));
86 else if(len == 0) {
87 if(errno != EAGAIN && errno != EWOULDBLOCK)
88 printlog(LOG_WARNING,"EOF tap data port: %s",strerror(errno));
89 /* close tap! */
90 } else if (len >= ETH_HEADER_SIZE)
91 handle_in_packet(ep, &(packet.p), len);
95 static void cleanup(unsigned char type,int fd,void *private_data)
97 if (fd >= 0)
98 close(fd);
101 static struct option long_options[] = {
102 {"tap", 1, 0, 't'},
104 #define Nlong_options (sizeof(long_options)/sizeof(struct option));
106 static void usage(void)
108 printf(
109 "(opts from tuntap module)\n"
110 " -t, --tap TAP Enable routing through TAP tap interface\n"
111 #ifdef VDE_DARWIN
112 " TAP can be an absolute file name or a relative\n"
113 " one (and will be prefixed with %s). The TAP\n"
114 " device must already exist.\n", TAP_PREFIX
115 #endif
119 static struct init_tap *add_init_tap(struct init_tap *p,char *arg)
121 if (p == NULL) {
122 p=malloc(sizeof(struct init_tap));
123 if (p==NULL)
124 printlog(LOG_WARNING,"Malloc Tap init:%s\n",strerror(errno));
125 else {
126 p->tap_dev=strdup(optarg);
127 p->next=NULL;
129 } else
130 p->next=add_init_tap(p->next,arg);
131 return(p);
134 static struct init_tap *free_init_tap(struct init_tap *p)
136 if (p != NULL) {
137 free_init_tap(p->next);
138 free(p);
140 return NULL;
143 static int parseopt(int c, char *optarg)
145 int outc=0;
146 switch (c) {
147 case 't':
148 hinit_tap=add_init_tap(hinit_tap,optarg);
149 break;
150 default:
151 outc=c;
153 return outc;
156 #ifdef VDE_LINUX
157 int open_tap(char *dev)
159 struct ifreq ifr;
160 int fd;
162 if((fd = open("/dev/net/tun", O_RDWR)) < 0){
163 printlog(LOG_ERR,"Failed to open /dev/net/tun %s",strerror(errno));
164 return(-1);
166 memset(&ifr, 0, sizeof(ifr));
167 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
168 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
169 /*printf("dev=\"%s\", ifr.ifr_name=\"%s\"\n", ifr.ifr_name, dev);*/
170 if(ioctl(fd, TUNSETIFF, (void *) &ifr) < 0){
171 printlog(LOG_ERR,"TUNSETIFF failed %s",strerror(errno));
172 close(fd);
173 return(-1);
175 /* tuntap should be "fast", but if there is a packetq we can manage
176 a tuntap which is "not fast enough" */
177 fcntl(fd, F_SETFL, O_NONBLOCK);
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 struct endpoint *newtap(char *dev)
214 int tap_fd;
215 tap_fd = open_tap(dev);
216 if (tap_fd>0) {
217 struct endpoint *ep=setup_ep(0,tap_fd,tap_fd,-1,&modfun);
218 if (ep != NULL) {
219 setup_description(ep,dev);
220 add_fd(tap_fd,tap_type,ep);
222 return ep;
223 } else
224 return NULL;
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) == NULL)
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_ctl, int fd_data, void *descr)
242 if (fd_ctl>=0)
243 remove_fd(fd_ctl);
244 if (descr) free(descr);
247 void start_tuntap(void)
249 modfun.modname=swmi.swmname=MODULENAME;
250 swmi.swmnopts=Nlong_options;
251 swmi.swmopts=long_options;
252 swmi.usage=usage;
253 swmi.parseopt=parseopt;
254 swmi.init=init;
255 swmi.handle_io=handle_io;
256 swmi.cleanup=cleanup;
257 modfun.sender=send_tap;
258 modfun.delep=delep;
259 add_swm(&swmi);
262 #endif