]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/um/os-Linux/drivers/tuntap_user.c
506ef09d83a0f215e6db90ad7663bca954b397b0
[karo-tx-linux.git] / arch / um / os-Linux / drivers / tuntap_user.c
1 /* 
2  * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3  * Licensed under the GPL
4  */
5
6 #include <stdio.h>
7 #include <stddef.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <sys/wait.h>
12 #include <sys/socket.h>
13 #include <sys/un.h>
14 #include <sys/uio.h>
15 #include <sys/ioctl.h>
16 #include <net/if.h>
17 #include <linux/if_tun.h>
18 #include "net_user.h"
19 #include "tuntap.h"
20 #include "kern_util.h"
21 #include "user_util.h"
22 #include "user.h"
23 #include "os.h"
24
25 #define MAX_PACKET ETH_MAX_PACKET
26
27 static int tuntap_user_init(void *data, void *dev)
28 {
29         struct tuntap_data *pri = data;
30
31         pri->dev = dev;
32         return 0;
33 }
34
35 static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask,
36                             void *data)
37 {
38         struct tuntap_data *pri = data;
39
40         tap_check_ips(pri->gate_addr, addr);
41         if((pri->fd == -1) || pri->fixed_config)
42                 return;
43         open_addr(addr, netmask, pri->dev_name);
44 }
45
46 static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask,
47                             void *data)
48 {
49         struct tuntap_data *pri = data;
50
51         if((pri->fd == -1) || pri->fixed_config)
52                 return;
53         close_addr(addr, netmask, pri->dev_name);
54 }
55
56 struct tuntap_pre_exec_data {
57         int stdout;
58         int close_me;
59 };
60
61 static void tuntap_pre_exec(void *arg)
62 {
63         struct tuntap_pre_exec_data *data = arg;
64
65         dup2(data->stdout, 1);
66         os_close_file(data->close_me);
67 }
68
69 static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
70                              char *buffer, int buffer_len, int *used_out)
71 {
72         struct tuntap_pre_exec_data data;
73         char version_buf[sizeof("nnnnn\0")];
74         char *argv[] = { "uml_net", version_buf, "tuntap", "up", gate,
75                          NULL };
76         char buf[CMSG_SPACE(sizeof(*fd_out))];
77         struct msghdr msg;
78         struct cmsghdr *cmsg;
79         struct iovec iov;
80         int pid, n, err;
81
82         sprintf(version_buf, "%d", UML_NET_VERSION);
83
84         data.stdout = remote;
85         data.close_me = me;
86
87         pid = run_helper(tuntap_pre_exec, &data, argv, NULL);
88
89         if(pid < 0)
90                 return -pid;
91
92         os_close_file(remote);
93
94         msg.msg_name = NULL;
95         msg.msg_namelen = 0;
96         if(buffer != NULL){
97                 iov = ((struct iovec) { buffer, buffer_len });
98                 msg.msg_iov = &iov;
99                 msg.msg_iovlen = 1;
100         }
101         else {
102                 msg.msg_iov = NULL;
103                 msg.msg_iovlen = 0;
104         }
105         msg.msg_control = buf;
106         msg.msg_controllen = sizeof(buf);
107         msg.msg_flags = 0;
108         n = recvmsg(me, &msg, 0);
109         *used_out = n;
110         if(n < 0){
111                 err = -errno;
112                 printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", 
113                        errno);
114                 return err;
115         }
116         CATCH_EINTR(waitpid(pid, NULL, 0));
117
118         cmsg = CMSG_FIRSTHDR(&msg);
119         if(cmsg == NULL){
120                 printk("tuntap_open_tramp : didn't receive a message\n");
121                 return -EINVAL;
122         }
123         if((cmsg->cmsg_level != SOL_SOCKET) || 
124            (cmsg->cmsg_type != SCM_RIGHTS)){
125                 printk("tuntap_open_tramp : didn't receive a descriptor\n");
126                 return -EINVAL;
127         }
128         *fd_out = ((int *) CMSG_DATA(cmsg))[0];
129         os_set_exec_close(*fd_out, 1);
130         return 0;
131 }
132
133 static int tuntap_open(void *data)
134 {
135         struct ifreq ifr;
136         struct tuntap_data *pri = data;
137         char *output, *buffer;
138         int err, fds[2], len, used;
139
140         err = tap_open_common(pri->dev, pri->gate_addr);
141         if(err < 0)
142                 return err;
143
144         if(pri->fixed_config){
145                 pri->fd = os_open_file("/dev/net/tun",
146                                        of_cloexec(of_rdwr(OPENFLAGS())), 0);
147                 if(pri->fd < 0){
148                         printk("Failed to open /dev/net/tun, err = %d\n",
149                                -pri->fd);
150                         return pri->fd;
151                 }
152                 memset(&ifr, 0, sizeof(ifr));
153                 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
154                 strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name));
155                 if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){
156                         err = -errno;
157                         printk("TUNSETIFF failed, errno = %d\n", errno);
158                         os_close_file(pri->fd);
159                         return err;
160                 }
161         }
162         else {
163                 err = os_pipe(fds, 0, 0);
164                 if(err < 0){
165                         printk("tuntap_open : os_pipe failed - err = %d\n",
166                                -err);
167                         return err;
168                 }
169
170                 buffer = get_output_buffer(&len);
171                 if(buffer != NULL) len--;
172                 used = 0;
173
174                 err = tuntap_open_tramp(pri->gate_addr, &pri->fd, fds[0],
175                                         fds[1], buffer, len, &used);
176
177                 output = buffer;
178                 if(err < 0) {
179                         printk("%s", output);
180                         free_output_buffer(buffer);
181                         printk("tuntap_open_tramp failed - err = %d\n", -err);
182                         return err;
183                 }
184
185                 pri->dev_name = uml_strdup(buffer);
186                 output += IFNAMSIZ;
187                 printk("%s", output);
188                 free_output_buffer(buffer);
189
190                 os_close_file(fds[0]);
191                 iter_addresses(pri->dev, open_addr, pri->dev_name);
192         }
193
194         return pri->fd;
195 }
196
197 static void tuntap_close(int fd, void *data)
198 {
199         struct tuntap_data *pri = data;
200
201         if(!pri->fixed_config) 
202                 iter_addresses(pri->dev, close_addr, pri->dev_name);
203         os_close_file(fd);
204         pri->fd = -1;
205 }
206
207 static int tuntap_set_mtu(int mtu, void *data)
208 {
209         return mtu;
210 }
211
212 const struct net_user_info tuntap_user_info = {
213         .init           = tuntap_user_init,
214         .open           = tuntap_open,
215         .close          = tuntap_close,
216         .remove         = NULL,
217         .set_mtu        = tuntap_set_mtu,
218         .add_address    = tuntap_add_addr,
219         .delete_address = tuntap_del_addr,
220         .max_packet     = MAX_PACKET
221 };