diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/um/os-Linux/drivers/tuntap_user.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/um/os-Linux/drivers/tuntap_user.c')
-rw-r--r-- | arch/um/os-Linux/drivers/tuntap_user.c | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c new file mode 100644 index 000000000000..4b83c6c3f48d --- /dev/null +++ b/arch/um/os-Linux/drivers/tuntap_user.c | |||
@@ -0,0 +1,225 @@ | |||
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 | */ | ||