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/ethertap_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/ethertap_user.c')
-rw-r--r-- | arch/um/os-Linux/drivers/ethertap_user.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c new file mode 100644 index 000000000000..cd4d6544da71 --- /dev/null +++ b/arch/um/os-Linux/drivers/ethertap_user.c | |||
@@ -0,0 +1,240 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and | ||
3 | * James Leu (jleu@mindspring.net). | ||
4 | * Copyright (C) 2001 by various other people who didn't put their name here. | ||
5 | * Licensed under the GPL. | ||
6 | */ | ||
7 | |||
8 | #include <stdio.h> | ||
9 | #include <unistd.h> | ||
10 | #include <stddef.h> | ||
11 | #include <stdlib.h> | ||
12 | #include <sys/errno.h> | ||
13 | #include <sys/socket.h> | ||
14 | #include <sys/wait.h> | ||
15 | #include <sys/un.h> | ||
16 | #include <net/if.h> | ||
17 | #include "user.h" | ||
18 | #include "kern_util.h" | ||
19 | #include "user_util.h" | ||
20 | #include "net_user.h" | ||
21 | #include "etap.h" | ||
22 | #include "helper.h" | ||
23 | #include "os.h" | ||
24 | |||
25 | #define MAX_PACKET ETH_MAX_PACKET | ||
26 | |||
27 | void etap_user_init(void *data, void *dev) | ||
28 | { | ||
29 | struct ethertap_data *pri = data; | ||
30 | |||
31 | pri->dev = dev; | ||
32 | } | ||
33 | |||
34 | struct addr_change { | ||
35 | enum { ADD_ADDR, DEL_ADDR } what; | ||
36 | unsigned char addr[4]; | ||
37 | unsigned char netmask[4]; | ||
38 | }; | ||
39 | |||
40 | static void etap_change(int op, unsigned char *addr, unsigned char *netmask, | ||
41 | int fd) | ||
42 | { | ||
43 | struct addr_change change; | ||
44 | void *output; | ||
45 | int n; | ||
46 | |||
47 | change.what = op; | ||
48 | memcpy(change.addr, addr, sizeof(change.addr)); | ||
49 | memcpy(change.netmask, netmask, sizeof(change.netmask)); | ||
50 | n = os_write_file(fd, &change, sizeof(change)); | ||
51 | if(n != sizeof(change)) | ||
52 | printk("etap_change - request failed, err = %d\n", -n); | ||
53 | output = um_kmalloc(page_size()); | ||
54 | if(output == NULL) | ||
55 | printk("etap_change : Failed to allocate output buffer\n"); | ||
56 | read_output(fd, output, page_size()); | ||
57 | if(output != NULL){ | ||
58 | printk("%s", output); | ||
59 | kfree(output); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | static void etap_open_addr(unsigned char *addr, unsigned char *netmask, | ||
64 | void *arg) | ||
65 | { | ||
66 | etap_change(ADD_ADDR, addr, netmask, *((int *) arg)); | ||
67 | } | ||
68 | |||
69 | static void etap_close_addr(unsigned char *addr, unsigned char *netmask, | ||
70 | void *arg) | ||
71 | { | ||
72 | etap_change(DEL_ADDR, addr, netmask, *((int *) arg)); | ||
73 | } | ||
74 | |||
75 | struct etap_pre_exec_data { | ||
76 | int control_remote; | ||
77 | int control_me; | ||
78 | int data_me; | ||
79 | }; | ||
80 | |||
81 | static void etap_pre_exec(void *arg) | ||
82 | { | ||
83 | struct etap_pre_exec_data *data = arg; | ||
84 | |||
85 | dup2(data->control_remote, 1); | ||
86 | os_close_file(data->data_me); | ||
87 | os_close_file(data->control_me); | ||
88 | } | ||
89 | |||
90 | static int etap_tramp(char *dev, char *gate, int control_me, | ||
91 | int control_remote, int data_me, int data_remote) | ||
92 | { | ||
93 | struct etap_pre_exec_data pe_data; | ||
94 | int pid, status, err, n; | ||
95 | char version_buf[sizeof("nnnnn\0")]; | ||
96 | char data_fd_buf[sizeof("nnnnnn\0")]; | ||
97 | char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; | ||
98 | char *setup_args[] = { "uml_net", version_buf, "ethertap", dev, | ||
99 | data_fd_buf, gate_buf, NULL }; | ||
100 | char *nosetup_args[] = { "uml_net", version_buf, "ethertap", | ||
101 | dev, data_fd_buf, NULL }; | ||
102 | char **args, c; | ||
103 | |||
104 | sprintf(data_fd_buf, "%d", data_remote); | ||
105 | sprintf(version_buf, "%d", UML_NET_VERSION); | ||
106 | if(gate != NULL){ | ||
107 | strcpy(gate_buf, gate); | ||
108 | args = setup_args; | ||
109 | } | ||
110 | else args = nosetup_args; | ||
111 | |||
112 | err = 0; | ||
113 | pe_data.control_remote = control_remote; | ||
114 | pe_data.control_me = control_me; | ||
115 | pe_data.data_me = data_me; | ||
116 | pid = run_helper(etap_pre_exec, &pe_data, args, NULL); | ||
117 | |||
118 | if(pid < 0) err = pid; | ||
119 | os_close_file(data_remote); | ||
120 | os_close_file(control_remote); | ||
121 | n = os_read_file(control_me, &c, sizeof(c)); | ||
122 | if(n != sizeof(c)){ | ||
123 | printk("etap_tramp : read of status failed, err = %d\n", -n); | ||
124 | return(-EINVAL); | ||
125 | } | ||
126 | if(c != 1){ | ||
127 | printk("etap_tramp : uml_net failed\n"); | ||
128 | err = -EINVAL; | ||
129 | CATCH_EINTR(n = waitpid(pid, &status, 0)); | ||
130 | if(n < 0) | ||
131 | err = -errno; | ||
132 | else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)) | ||
133 | printk("uml_net didn't exit with status 1\n"); | ||
134 | } | ||
135 | return(err); | ||
136 | } | ||
137 | |||
138 | static int etap_open(void *data) | ||
139 | { | ||
140 | struct ethertap_data *pri = data; | ||
141 | char *output; | ||
142 | int data_fds[2], control_fds[2], err, output_len; | ||
143 | |||
144 | err = tap_open_common(pri->dev, pri->gate_addr); | ||
145 | if(err) return(err); | ||
146 | |||
147 | err = os_pipe(data_fds, 0, 0); | ||
148 | if(err < 0){ | ||
149 | printk("data os_pipe failed - err = %d\n", -err); | ||
150 | return(err); | ||
151 | } | ||
152 | |||
153 | err = os_pipe(control_fds, 1, 0); | ||
154 | if(err < 0){ | ||
155 | printk("control os_pipe failed - err = %d\n", -err); | ||
156 | return(err); | ||
157 | } | ||
158 | |||
159 | err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0], | ||
160 | control_fds[1], data_fds[0], data_fds[1]); | ||
161 | output_len = page_size(); | ||
162 | output = um_kmalloc(output_len); | ||
163 | read_output(control_fds[0], output, output_len); | ||
164 | |||
165 | if(output == NULL) | ||
166 | printk("etap_open : failed to allocate output buffer\n"); | ||
167 | else { | ||
168 | printk("%s", output); | ||
169 | kfree(output); | ||
170 | } | ||
171 | |||
172 | if(err < 0){ | ||
173 | printk("etap_tramp failed - err = %d\n", -err); | ||
174 | return(err); | ||
175 | } | ||
176 | |||
177 | pri->data_fd = data_fds[0]; | ||
178 | pri->control_fd = control_fds[0]; | ||
179 | iter_addresses(pri->dev, etap_open_addr, &pri->control_fd); | ||
180 | return(data_fds[0]); | ||
181 | } | ||
182 | |||
183 | static void etap_close(int fd, void *data) | ||
184 | { | ||
185 | struct ethertap_data *pri = data; | ||
186 | |||
187 | iter_addresses(pri->dev, etap_close_addr, &pri->control_fd); | ||
188 | os_close_file(fd); | ||
189 | os_shutdown_socket(pri->data_fd, 1, 1); | ||
190 | os_close_file(pri->data_fd); | ||
191 | pri->data_fd = -1; | ||
192 | os_close_file(pri->control_fd); | ||
193 | pri->control_fd = -1; | ||
194 | } | ||
195 | |||
196 | static int etap_set_mtu(int mtu, void *data) | ||
197 | { | ||
198 | return(mtu); | ||
199 | } | ||
200 | |||
201 | static void etap_add_addr(unsigned char *addr, unsigned char *netmask, | ||
202 | void *data) | ||
203 | { | ||
204 | struct ethertap_data *pri = data; | ||
205 | |||
206 | tap_check_ips(pri->gate_addr, addr); | ||
207 | if(pri->control_fd == -1) return; | ||
208 | etap_open_addr(addr, netmask, &pri->control_fd); | ||
209 | } | ||
210 | |||
211 | static void etap_del_addr(unsigned char *addr, unsigned char *netmask, | ||
212 | void *data) | ||
213 | { | ||
214 | struct ethertap_data *pri = data; | ||
215 | |||
216 | if(pri->control_fd == -1) return; | ||
217 | etap_close_addr(addr, netmask, &pri->control_fd); | ||
218 | } | ||
219 | |||
220 | struct net_user_info ethertap_user_info = { | ||
221 | .init = etap_user_init, | ||
222 | .open = etap_open, | ||
223 | .close = etap_close, | ||
224 | .remove = NULL, | ||
225 | .set_mtu = etap_set_mtu, | ||
226 | .add_address = etap_add_addr, | ||
227 | .delete_address = etap_del_addr, | ||
228 | .max_packet = MAX_PACKET - ETH_HEADER_ETHERTAP | ||
229 | }; | ||
230 | |||
231 | /* | ||
232 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
233 | * Emacs will notice this stuff at the end of the file and automatically | ||
234 | * adjust the settings for this buffer only. This must remain at the end | ||
235 | * of the file. | ||
236 | * --------------------------------------------------------------------------- | ||
237 | * Local variables: | ||
238 | * c-file-style: "linux" | ||
239 | * End: | ||
240 | */ | ||