VDE 2.1.6, 2006-12-21
[vde.git] / vde-2 / vdetaplib / libvdetap.c
blob89ab258a0dc7e4c5bd2dcb4516657a4daa6334d7
1 /* Copyright 2004 Renzo Davoli
2 * Reseased under the GPLv2 */
4 #define _GNU_SOURCE
5 #include <config.h>
6 #include <dlfcn.h>
7 #include <stdio.h>
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <sys/syscall.h>
11 #include <sys/stat.h>
12 #include <stdarg.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include <fcntl.h>
17 #include <errno.h>
18 #include <stdio.h>
19 #include <signal.h>
20 #include <linux/ioctl.h>
21 #include <linux/if.h>
22 #include <linux/if_tun.h>
24 #define TUNTAPPATH "/dev/net/tun"
25 #define VDETAPEXEC LIBEXECDIR "/vdetap"
26 #define VDEALLTAP "VDEALLTAP"
27 #define MAX 10
29 #define nativesym(function, name) \
30 { \
31 char *msg; \
32 if (native_##function == NULL) { \
33 *(void **)(&native_##function) = dlsym(RTLD_NEXT, name); \
34 if ((msg = dlerror()) != NULL) { \
35 fprintf (stderr, "%s: dlsym(%s): %s\n", PACKAGE, name, msg); \
36 } \
37 } \
40 static int (*native_ioctl) (int d, int request, ...) = NULL;
41 static int (*native_open) (const char *pathname, int flags, ...) = NULL;
42 static int (*native_open64) (const char *pathname, int flags, ...) = NULL;
44 int tapfd[2] = {-1,-1};
45 static int tapcount=0;
46 static int tuncount=0;
48 static struct pidlist {
49 pid_t pid;
50 struct pidlist *next;
51 } *plh = NULL, *flh=NULL, pidpool[MAX];
53 static struct pidlist *plmalloc(void) {
54 struct pidlist *rv;
55 rv=flh;
56 if (rv != NULL)
57 flh=flh->next;
58 return rv;
61 static void plfree (struct pidlist *el) {
62 el->next=flh;
63 flh=el;
66 static int addpid(int pid) {
67 struct pidlist *plp;
68 if ((plp=plmalloc ()) != NULL) {
69 plp->next=plh;
70 plh=plp;
71 plp->pid=pid;
72 return pid;
73 } else {
74 kill(pid,SIGTERM);
75 return -1;
79 void libvdetap_init (void) __attribute((constructor));
80 void libvdetap_init(void)
82 register int i;
83 nativesym(ioctl, "ioctl");
84 nativesym(open, "open");
85 nativesym(open64, "open64");
86 for (i=1;i<MAX;i++)
87 pidpool[i-1].next= &(pidpool[i]);
88 flh=pidpool;
91 void libvdetap_fini(void)
93 struct pidlist *plp=plh;
94 while (plp != NULL) {
95 kill(plp->pid,SIGTERM);
96 plp = plp->next;
100 int open(const char *path, int flags, ...)
102 static char buf[PATH_MAX];
103 va_list ap;
104 mode_t data;
106 va_start(ap, flags);
107 data = va_arg(ap, mode_t);
108 va_end(ap);
110 if (strcmp(path,TUNTAPPATH)==0 && tapfd[0] == -1) {
111 if (socketpair(PF_UNIX, SOCK_DGRAM, 0,tapfd) == 0) {
112 return tapfd[0];
114 else
115 return -1;
117 } else
118 return native_open(path, flags, data);
121 int open64(const char *path, int flags, ...)
123 static char buf[PATH_MAX];
124 va_list ap;
125 mode_t data;
127 va_start(ap, flags);
128 data = va_arg(ap, mode_t);
129 va_end(ap);
131 if (strcmp(path,TUNTAPPATH)==0 && tapfd[0] == -1) {
132 if (socketpair(PF_UNIX, SOCK_DGRAM, 0,tapfd) == 0) {
133 return tapfd[0];
135 else
136 return -1;
138 } else
139 return native_open64(path, flags | O_LARGEFILE, data);
142 int ioctl(int fd, unsigned long int command, ...)
144 va_list ap;
145 char *data;
146 char *vdesock;
147 int pid;
149 va_start(ap, command);
150 data = va_arg(ap, char *);
151 va_end(ap);
153 if (fd == tapfd[0]) {
154 if (command == TUNSETIFF) {
155 struct ifreq *ifr = (struct ifreq *) data;
156 char num[5];
157 char name[10];
159 ifr->ifr_name[IFNAMSIZ-1] = '\0';
160 if (ifr->ifr_name[0] == 0) {
161 if (ifr->ifr_flags & IFF_TAP)
162 sprintf(name,"tap%d",tapcount++);
163 else
164 sprintf(name,"tun%d",tuncount++);
165 strncpy(ifr->ifr_name,name,IFNAMSIZ);
167 else if (strchr(ifr->ifr_name, '%') != NULL) {
168 sprintf(name,ifr->ifr_name,tapcount++);
169 strncpy(ifr->ifr_name,name,IFNAMSIZ);
171 if (ifr->ifr_flags & IFF_TAP &&
172 ((vdesock=getenv(ifr->ifr_name)) != NULL)
173 ||(vdesock=getenv(VDEALLTAP)) != NULL){
174 if ((pid=fork()) < 0) {
175 close(tapfd[1]);
176 errno=EINVAL;
177 return -1;
178 } else if (pid > 0) { /*father*/
179 if(pid=addpid(pid) < 0) {
180 close(tapfd[0]);
181 close(tapfd[1]);
182 return -1;
183 } else {
184 close(tapfd[1]);
185 return 0;
187 } else { /*son*/
188 plh=NULL;
189 close(tapfd[0]);
190 sprintf(num,"%d",tapfd[1]);
191 execlp(VDETAPEXEC,"-",num,vdesock,name,(char *) 0);
194 else /*roll back to the native tuntap*/
196 int newfd;
197 int saverrno;
198 int resultioctl;
199 close(tapfd[1]);
200 if ((newfd=native_open(TUNTAPPATH, O_RDWR, 0)) < 0) {
201 saverrno=errno;
202 close(tapfd[0]);
203 errno=saverrno;
204 return -1;
205 } else
207 resultioctl=native_ioctl(fd, command, data);
208 if (resultioctl < 0) {
209 saverrno=errno;
210 close(tapfd[0]);
211 errno=saverrno;
212 return -1;
213 } else {
214 dup2(newfd,tapfd[0]);
215 return resultioctl;
219 } else
220 return 0;
221 } else
222 return (native_ioctl(fd, command, data));