vde_autolink: Add missing null entry in getopt_long array.
[vde.git] / vde-2 / src / vdetaplib / libvdetap.c
blob9da3344f20ae67ecd7a82545c2e89d28e19c61d3
1 /* Copyright 2004 Renzo Davoli
2 * Reseased under the GPLv2 */
4 #define _GNU_SOURCE
5 #include <dlfcn.h>
6 #include <stdio.h>
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <sys/syscall.h>
10 #include <sys/stat.h>
11 #include <stdarg.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <fcntl.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <signal.h>
19 #include <linux/ioctl.h>
20 #include <linux/if.h>
21 #include <linux/if_tun.h>
23 #include <config.h>
24 #include <vde.h>
25 #include <vdecommon.h>
27 #define TUNTAPPATH "/dev/net/tun"
28 #define VDETAPEXEC LIBEXECDIR "/vdetap"
29 #define VDEALLTAP "VDEALLTAP"
30 #define MAX 10
32 #define nativesym(function, name) \
33 { \
34 const char *msg; \
35 if (native_##function == NULL) { \
36 *(void **)(&native_##function) = dlsym(RTLD_NEXT, name); \
37 if ((msg = dlerror()) != NULL) { \
38 fprintf (stderr, "%s: dlsym(%s): %s\n", PACKAGE, name, msg); \
39 } \
40 } \
43 static int (*native_ioctl) (int d, int request, ...) = NULL;
44 static int (*native_open) (const char *pathname, int flags, ...) = NULL;
45 static int (*native_open64) (const char *pathname, int flags, ...) = NULL;
47 int tapfd[2] = {-1,-1};
48 static int tapcount=0;
49 static int tuncount=0;
51 static struct pidlist {
52 pid_t pid;
53 struct pidlist *next;
54 } *plh = NULL, *flh=NULL, pidpool[MAX];
56 static struct pidlist *plmalloc(void) {
57 struct pidlist *rv;
58 rv=flh;
59 if (rv != NULL)
60 flh=flh->next;
61 return rv;
64 /* not used?
65 static void plfree (struct pidlist *el) {
66 el->next=flh;
67 flh=el;
71 static int addpid(int pid) {
72 struct pidlist *plp;
73 if ((plp=plmalloc ()) != NULL) {
74 plp->next=plh;
75 plh=plp;
76 plp->pid=pid;
77 return pid;
78 } else {
79 kill(pid,SIGTERM);
80 return -1;
84 void libvdetap_init (void) __attribute((constructor));
85 void libvdetap_init(void)
87 int i;
88 nativesym(ioctl, "ioctl");
89 nativesym(open, "open");
90 nativesym(open64, "open64");
91 for (i=1;i<MAX;i++)
92 pidpool[i-1].next= &(pidpool[i]);
93 flh=pidpool;
96 void libvdetap_fini(void)
98 struct pidlist *plp=plh;
99 while (plp != NULL) {
100 kill(plp->pid,SIGTERM);
101 plp = plp->next;
105 int open(const char *path, int flags, ...)
107 va_list ap;
108 int data;
110 va_start(ap, flags);
111 data = va_arg(ap, int);
112 va_end(ap);
114 if (strcmp(path,TUNTAPPATH)==0 && tapfd[0] == -1) {
115 if (socketpair(PF_UNIX, SOCK_DGRAM, 0,tapfd) == 0)
116 return tapfd[0];
117 else
118 return -1;
120 } else
121 return native_open(path, flags, data);
124 int open64(const char *path, int flags, ...)
126 va_list ap;
127 int data;
129 va_start(ap, flags);
130 data = va_arg(ap, int);
131 va_end(ap);
133 if (strcmp(path,TUNTAPPATH)==0 && tapfd[0] == -1) {
134 if (socketpair(PF_UNIX, SOCK_DGRAM, 0,tapfd) == 0)
135 return tapfd[0];
136 else
137 return -1;
139 } else
140 return native_open64(path, flags | O_LARGEFILE, data);
143 static char *getvdeopt(struct ifreq *ifr,char *suffix)
145 static char buf[16];
146 char *rv;
147 snprintf(buf,16,"%s_%s",ifr->ifr_name,suffix);
148 if ((rv=getenv(buf)) != NULL)
149 return rv;
150 snprintf(buf,16,"VDEALLTAP_%s",suffix);
151 if ((rv=getenv(buf)) != NULL)
152 return rv;
153 else
154 return "";
157 #ifdef VDE_BIONIC
158 int ioctl(int fd, int command, ...)
159 #else
160 int ioctl(int fd, unsigned long int command, ...)
161 #endif
163 va_list ap;
164 char *data;
165 char *vdesock;
166 int pid;
167 int callerpid=getpid();
169 va_start(ap, command);
170 data = va_arg(ap, char *);
171 va_end(ap);
173 if (fd == tapfd[0]) {
174 if (command == TUNSETIFF) {
175 struct ifreq *ifr = (struct ifreq *) data;
176 char num[5];
177 char name[10];
178 char scallerpid[6];
180 ifr->ifr_name[IFNAMSIZ-1] = '\0';
181 if (ifr->ifr_name[0] == 0) {
182 if (ifr->ifr_flags & IFF_TAP)
183 sprintf(name,"tap%d",tapcount++);
184 else
185 sprintf(name,"tun%d",tuncount++);
186 strncpy(ifr->ifr_name,name,IFNAMSIZ);
188 else if (strchr(ifr->ifr_name, '%') != NULL) {
189 sprintf(name,ifr->ifr_name,tapcount++);
190 strncpy(ifr->ifr_name,name,IFNAMSIZ);
192 if ((ifr->ifr_flags & IFF_TAP) && (
193 /* from env: single interface or VDEALLTAP */
194 ((vdesock=getenv(ifr->ifr_name)) != NULL) ||
195 (vdesock=getenv(VDEALLTAP)) != NULL)
197 if ((pid=fork()) < 0) {
198 close(tapfd[1]);
199 errno=EINVAL;
200 return -1;
201 } else if (pid > 0) { /*father*/
202 if((pid=addpid(pid)) < 0) {
203 close(tapfd[0]);
204 close(tapfd[1]);
205 return -1;
206 } else {
207 close(tapfd[1]);
208 return 0;
210 } else { /*son*/
211 plh=NULL;
212 close(tapfd[0]);
213 sprintf(num,"%d",tapfd[1]);
214 sprintf(scallerpid,"%d",callerpid);
215 return execlp(VDETAPEXEC,"-",num,vdesock,ifr->ifr_name,
216 scallerpid,
217 getvdeopt(ifr,"port"),
218 getvdeopt(ifr,"group"),
219 getvdeopt(ifr,"mode"),
220 (char *) 0);
223 else /*roll back to the native tuntap*/
225 int newfd;
226 int saverrno;
227 int resultioctl;
228 close(tapfd[1]);
229 if ((newfd=native_open(TUNTAPPATH, O_RDWR, 0)) < 0) {
230 saverrno=errno;
231 close(tapfd[0]);
232 errno=saverrno;
233 return -1;
234 } else
236 resultioctl=native_ioctl(fd, command, data);
237 if (resultioctl < 0) {
238 saverrno=errno;
239 close(tapfd[0]);
240 errno=saverrno;
241 return -1;
242 } else {
243 dup2(newfd,tapfd[0]);
244 return resultioctl;
248 } else
249 return 0;
250 } else
251 return (native_ioctl(fd, command, data));