]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 "helper.h" | |
24 | #include "os.h" | |
25 | ||
26 | #define MAX_PACKET ETH_MAX_PACKET | |
27 | ||
28 | void tuntap_user_init(void *data, void *dev) | |
29 | { | |
30 | struct tuntap_data *pri = data; | |
31 | ||
32 | pri->dev = dev; | |
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) return; | |
42 | open_addr(addr, netmask, pri->dev_name); | |
43 | } | |
44 | ||
45 | static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask, | |
46 | void *data) | |
47 | { | |
48 | struct tuntap_data *pri = data; | |
49 | ||
50 | if((pri->fd == -1) || pri->fixed_config) return; | |
51 | close_addr(addr, netmask, pri->dev_name); | |
52 | } | |
53 | ||
54 | struct tuntap_pre_exec_data { | |
55 | int stdout; | |
56 | int close_me; | |
57 | }; | |
58 | ||
59 | static void tuntap_pre_exec(void *arg) | |
60 | { | |
61 | struct tuntap_pre_exec_data *data = arg; | |
62 | ||
63 | dup2(data->stdout, 1); | |
64 | os_close_file(data->close_me); | |
65 | } | |
66 | ||
67 | static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, | |
68 | char *buffer, int buffer_len, int *used_out) | |
69 | { | |
70 | struct tuntap_pre_exec_data data; | |
71 | char version_buf[sizeof("nnnnn\0")]; | |
72 | char *argv[] = { "uml_net", version_buf, "tuntap", "up", gate, | |
73 | NULL }; | |
74 | char buf[CMSG_SPACE(sizeof(*fd_out))]; | |
75 | struct msghdr msg; | |
76 | struct cmsghdr *cmsg; | |
77 | struct iovec iov; | |
78 | int pid, n; | |
79 | ||
80 | sprintf(version_buf, "%d", UML_NET_VERSION); | |
81 | ||
82 | data.stdout = remote; | |
83 | data.close_me = me; | |
84 | ||
85 | pid = run_helper(tuntap_pre_exec, &data, argv, NULL); | |
86 | ||
87 | if(pid < 0) return(-pid); | |
88 | ||
89 | os_close_file(remote); | |
90 | ||
91 | msg.msg_name = NULL; | |
92 | msg.msg_namelen = 0; | |
93 | if(buffer != NULL){ | |
94 | iov = ((struct iovec) { buffer, buffer_len }); | |
95 | msg.msg_iov = &iov; | |
96 | msg.msg_iovlen = 1; | |
97 | } | |
98 | else { | |
99 | msg.msg_iov = NULL; | |
100 | msg.msg_iovlen = 0; | |
101 | } | |
102 | msg.msg_control = buf; | |
103 | msg.msg_controllen = sizeof(buf); | |
104 | msg.msg_flags = 0; | |
105 | n = recvmsg(me, &msg, 0); | |
106 | *used_out = n; | |
107 | if(n < 0){ | |
108 | printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", | |
109 | errno); | |
110 | return(-errno); | |
111 | } | |
112 | CATCH_EINTR(waitpid(pid, NULL, 0)); | |
113 | ||
114 | cmsg = CMSG_FIRSTHDR(&msg); | |
115 | if(cmsg == NULL){ | |
116 | printk("tuntap_open_tramp : didn't receive a message\n"); | |
117 | return(-EINVAL); | |
118 | } | |
119 | if((cmsg->cmsg_level != SOL_SOCKET) || | |
120 | (cmsg->cmsg_type != SCM_RIGHTS)){ | |
121 | printk("tuntap_open_tramp : didn't receive a descriptor\n"); | |
122 | return(-EINVAL); | |
123 | } | |
124 | *fd_out = ((int *) CMSG_DATA(cmsg))[0]; | |
125 | return(0); | |
126 | } | |
127 | ||
128 | static int tuntap_open(void *data) | |
129 | { | |
130 | struct ifreq ifr; | |
131 | struct tuntap_data *pri = data; | |
132 | char *output, *buffer; | |
133 | int err, fds[2], len, used; | |
134 | ||
135 | err = tap_open_common(pri->dev, pri->gate_addr); | |
136 | if(err < 0) | |
137 | return(err); | |
138 | ||
139 | if(pri->fixed_config){ | |
140 | pri->fd = os_open_file("/dev/net/tun", of_rdwr(OPENFLAGS()), 0); | |
141 | if(pri->fd < 0){ | |
142 | printk("Failed to open /dev/net/tun, err = %d\n", | |
143 | -pri->fd); | |
144 | return(pri->fd); | |
145 | } | |
146 | memset(&ifr, 0, sizeof(ifr)); | |
147 | ifr.ifr_flags = IFF_TAP | IFF_NO_PI; | |
148 | strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name)); | |
149 | if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){ | |
150 | printk("TUNSETIFF failed, errno = %d\n", errno); | |
151 | os_close_file(pri->fd); | |
152 | return(-errno); | |
153 | } | |
154 | } | |
155 | else { | |
156 | err = os_pipe(fds, 0, 0); | |
157 | if(err < 0){ | |
158 | printk("tuntap_open : os_pipe failed - err = %d\n", | |
159 | -err); | |
160 | return(err); | |
161 | } | |
162 | ||
163 | buffer = get_output_buffer(&len); | |
164 | if(buffer != NULL) len--; | |
165 | used = 0; | |
166 | ||
167 | err = tuntap_open_tramp(pri->gate_addr, &pri->fd, fds[0], | |
168 | fds[1], buffer, len, &used); | |
169 | ||
170 | output = buffer; | |
171 | if(err < 0) { | |
172 | printk("%s", output); | |
173 | free_output_buffer(buffer); | |
174 | printk("tuntap_open_tramp failed - err = %d\n", -err); | |
175 | return(err); | |
176 | } | |
177 | ||
178 | pri->dev_name = uml_strdup(buffer); | |
179 | output += IFNAMSIZ; | |
180 | printk("%s", output); | |
181 | free_output_buffer(buffer); | |
182 | ||
183 | os_close_file(fds[0]); | |
184 | iter_addresses(pri->dev, open_addr, pri->dev_name); | |
185 | } | |
186 | ||
187 | return(pri->fd); | |
188 | } | |
189 | ||
190 | static void tuntap_close(int fd, void *data) | |
191 | { | |
192 | struct tuntap_data *pri = data; | |
193 | ||
194 | if(!pri->fixed_config) | |
195 | iter_addresses(pri->dev, close_addr, pri->dev_name); | |
196 | os_close_file(fd); | |
197 | pri->fd = -1; | |
198 | } | |
199 | ||
200 | static int tuntap_set_mtu(int mtu, void *data) | |
201 | { | |
202 | return(mtu); | |
203 | } | |
204 | ||
205 | struct net_user_info tuntap_user_info = { | |
206 | .init = tuntap_user_init, | |
207 | .open = tuntap_open, | |
208 | .close = tuntap_close, | |
209 | .remove = NULL, | |
210 | .set_mtu = tuntap_set_mtu, | |
211 | .add_address = tuntap_add_addr, | |
212 | .delete_address = tuntap_del_addr, | |
213 | .max_packet = MAX_PACKET | |
214 | }; | |
215 | ||
216 | /* | |
217 | * Overrides for Emacs so that we follow Linus's tabbing style. | |
218 | * Emacs will notice this stuff at the end of the file and automatically | |
219 | * adjust the settings for this buffer only. This must remain at the end | |
220 | * of the file. | |
221 | * --------------------------------------------------------------------------- | |
222 | * Local variables: | |
223 | * c-file-style: "linux" | |
224 | * End: | |
225 | */ |