Port Access Control.
[vde.git] / vde-2 / src / vde_switch / tuntap.c
blob6918032b4e3807c424866178a2f27148a801daed
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) printlog(LOG_WARNING,"send_tap port %d: %s",port,strerror(errno));
64 #endif
65 if (n > len)
66 return -rv;
67 else
68 return n;
70 return 0;
73 static void closeport(int fd, int portno)
75 if (fd>0)
76 remove_fd(fd);
79 static void handle_input(unsigned char type,int fd,int revents,int *arg)
81 struct bipacket packet;
82 int len=read(fd, &(packet.p), sizeof(struct packet));
84 if(len < 0){
85 if(errno != EAGAIN) printlog(LOG_WARNING,"Reading tap data: %s",strerror(errno));
87 else if(len == 0) {
88 if(errno != EAGAIN) printlog(LOG_WARNING,"EOF tap data port: %s",strerror(errno));
89 /* close tap! */
90 } else if (len >= ETH_HEADER_SIZE)
91 handle_in_packet(*arg, &(packet.p), len);
95 static void cleanup(unsigned char type,int fd,int arg)
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 return(fd);
177 #endif
179 #if defined(VDE_DARWIN) || defined(VDE_FREEBSD)
180 int open_tap(char *dev)
182 int fd;
183 int prefixlen = strlen(TAP_PREFIX);
184 char *path = NULL;
185 if (*dev == '/')
186 fd=open(dev, O_RDWR);
187 else
189 path = malloc(strlen(dev) + prefixlen + 1);
190 if (path != NULL)
192 snprintf(path, strlen(dev) + prefixlen + 1, "%s%s", TAP_PREFIX, dev);
193 fd=open(path, O_RDWR);
194 free(path);
196 else
197 fd = -1;
200 if (fd < 0)
202 printlog(LOG_ERR,"Failed to open tap device %s: %s", (*dev == '/') ? dev : path, strerror(errno));
203 return(-1);
205 return fd;
207 #endif
209 static int newport(int fd, int portno, uid_t user)
211 return fd;
214 static int newtap(char *dev)
216 int tap_fd;
217 tap_fd = open_tap(dev);
218 if (tap_fd>0) {
219 int portno=setup_ep(0,tap_fd,NULL,-1,&modfun);
220 if (portno >= 0) {
221 setup_description(portno,tap_fd,dev);
222 add_fd(tap_fd,tap_type,portno);
223 return portno;
224 } else
225 return -1;
226 } else
227 return -1;
230 static void init(void)
232 if(hinit_tap != NULL) {
233 struct init_tap *p;
234 tap_type=add_type(&swmi,1);
235 for(p=hinit_tap;p != NULL;p=p->next) {
236 if (newtap(p->tap_dev) < 0)
237 printlog(LOG_ERR,"ERROR OPENING tap interface: %s",p->tap_dev);
239 hinit_tap=free_init_tap(hinit_tap);
243 static void delep (int fd, void* data, void *descr)
245 if (descr) free(descr);
248 void start_tuntap(void)
250 modfun.modname=swmi.swmname=MODULENAME;
251 swmi.swmnopts=Nlong_options;
252 swmi.swmopts=long_options;
253 swmi.usage=usage;
254 swmi.parseopt=parseopt;
255 swmi.init=init;
256 swmi.handle_input=handle_input;
257 swmi.cleanup=cleanup;
258 modfun.sender=send_tap;
259 modfun.newport=newport;
260 modfun.delep=delep;
261 modfun.delport=closeport;
262 add_swm(&swmi);
265 #endif