diff options
Diffstat (limited to 'arch/um/os-Linux/drivers')
-rw-r--r-- | arch/um/os-Linux/drivers/Makefile | 13 | ||||
-rw-r--r-- | arch/um/os-Linux/drivers/etap.h | 27 | ||||
-rw-r--r-- | arch/um/os-Linux/drivers/ethertap_kern.c | 119 | ||||
-rw-r--r-- | arch/um/os-Linux/drivers/ethertap_user.c | 240 | ||||
-rw-r--r-- | arch/um/os-Linux/drivers/tuntap.h | 32 | ||||
-rw-r--r-- | arch/um/os-Linux/drivers/tuntap_kern.c | 104 | ||||
-rw-r--r-- | arch/um/os-Linux/drivers/tuntap_user.c | 225 |
7 files changed, 760 insertions, 0 deletions
diff --git a/arch/um/os-Linux/drivers/Makefile b/arch/um/os-Linux/drivers/Makefile new file mode 100644 index 000000000000..6c546dc9222b --- /dev/null +++ b/arch/um/os-Linux/drivers/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | # | ||
2 | # Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com) | ||
3 | # Licensed under the GPL | ||
4 | # | ||
5 | |||
6 | ethertap-objs := ethertap_kern.o ethertap_user.o | ||
7 | tuntap-objs := tuntap_kern.o tuntap_user.o | ||
8 | |||
9 | obj-y = | ||
10 | obj-$(CONFIG_UML_NET_ETHERTAP) += ethertap.o | ||
11 | obj-$(CONFIG_UML_NET_TUNTAP) += tuntap.o | ||
12 | |||
13 | include arch/um/scripts/Makefile.rules | ||
diff --git a/arch/um/os-Linux/drivers/etap.h b/arch/um/os-Linux/drivers/etap.h new file mode 100644 index 000000000000..b84f6c4740f7 --- /dev/null +++ b/arch/um/os-Linux/drivers/etap.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include "net_user.h" | ||
7 | |||
8 | struct ethertap_data { | ||
9 | char *dev_name; | ||
10 | char *gate_addr; | ||
11 | int data_fd; | ||
12 | int control_fd; | ||
13 | void *dev; | ||
14 | }; | ||
15 | |||
16 | extern struct net_user_info ethertap_user_info; | ||
17 | |||
18 | /* | ||
19 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
20 | * Emacs will notice this stuff at the end of the file and automatically | ||
21 | * adjust the settings for this buffer only. This must remain at the end | ||
22 | * of the file. | ||
23 | * --------------------------------------------------------------------------- | ||
24 | * Local variables: | ||
25 | * c-file-style: "linux" | ||
26 | * End: | ||
27 | */ | ||
diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c new file mode 100644 index 000000000000..6ae4b19d9f50 --- /dev/null +++ b/arch/um/os-Linux/drivers/ethertap_kern.c | |||
@@ -0,0 +1,119 @@ | |||
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 "linux/init.h" | ||
9 | #include "linux/netdevice.h" | ||
10 | #include "linux/etherdevice.h" | ||
11 | #include "net_kern.h" | ||
12 | #include "net_user.h" | ||
13 | #include "etap.h" | ||
14 | |||
15 | struct ethertap_init { | ||
16 | char *dev_name; | ||
17 | char *gate_addr; | ||
18 | }; | ||
19 | |||
20 | static void etap_init(struct net_device *dev, void *data) | ||
21 | { | ||
22 | struct uml_net_private *pri; | ||
23 | struct ethertap_data *epri; | ||
24 | struct ethertap_init *init = data; | ||
25 | |||
26 | pri = dev->priv; | ||
27 | epri = (struct ethertap_data *) pri->user; | ||
28 | epri->dev_name = init->dev_name; | ||
29 | epri->gate_addr = init->gate_addr; | ||
30 | epri->data_fd = -1; | ||
31 | epri->control_fd = -1; | ||
32 | epri->dev = dev; | ||
33 | |||
34 | printk("ethertap backend - %s", epri->dev_name); | ||
35 | if (epri->gate_addr != NULL) | ||
36 | printk(", IP = %s", epri->gate_addr); | ||
37 | printk("\n"); | ||
38 | } | ||
39 | |||
40 | static int etap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp) | ||
41 | { | ||
42 | int len; | ||
43 | |||
44 | *skb = ether_adjust_skb(*skb, ETH_HEADER_ETHERTAP); | ||
45 | if(*skb == NULL) return(-ENOMEM); | ||
46 | len = net_recvfrom(fd, (*skb)->mac.raw, | ||
47 | (*skb)->dev->mtu + 2 * ETH_HEADER_ETHERTAP); | ||
48 | if(len <= 0) return(len); | ||
49 | skb_pull(*skb, 2); | ||
50 | len -= 2; | ||
51 | return(len); | ||
52 | } | ||
53 | |||
54 | static int etap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp) | ||
55 | { | ||
56 | if(skb_headroom(*skb) < 2){ | ||
57 | struct sk_buff *skb2; | ||
58 | |||
59 | skb2 = skb_realloc_headroom(*skb, 2); | ||
60 | dev_kfree_skb(*skb); | ||
61 | if (skb2 == NULL) return(-ENOMEM); | ||
62 | *skb = skb2; | ||
63 | } | ||
64 | skb_push(*skb, 2); | ||
65 | return(net_send(fd, (*skb)->data, (*skb)->len)); | ||
66 | } | ||
67 | |||
68 | struct net_kern_info ethertap_kern_info = { | ||
69 | .init = etap_init, | ||
70 | .protocol = eth_protocol, | ||
71 | .read = etap_read, | ||
72 | .write = etap_write, | ||
73 | }; | ||
74 | |||
75 | int ethertap_setup(char *str, char **mac_out, void *data) | ||
76 | { | ||
77 | struct ethertap_init *init = data; | ||
78 | |||
79 | *init = ((struct ethertap_init) | ||
80 | { .dev_name = NULL, | ||
81 | .gate_addr = NULL }); | ||
82 | if(tap_setup_common(str, "ethertap", &init->dev_name, mac_out, | ||
83 | &init->gate_addr)) | ||
84 | return(0); | ||
85 | if(init->dev_name == NULL){ | ||
86 | printk("ethertap_setup : Missing tap device name\n"); | ||
87 | return(0); | ||
88 | } | ||
89 | |||
90 | return(1); | ||
91 | } | ||
92 | |||
93 | static struct transport ethertap_transport = { | ||
94 | .list = LIST_HEAD_INIT(ethertap_transport.list), | ||
95 | .name = "ethertap", | ||
96 | .setup = ethertap_setup, | ||
97 | .user = ðertap_user_info, | ||
98 | .kern = ðertap_kern_info, | ||
99 | .private_size = sizeof(struct ethertap_data), | ||
100 | }; | ||
101 | |||
102 | static int register_ethertap(void) | ||
103 | { | ||
104 | register_transport(ðertap_transport); | ||
105 | return(1); | ||
106 | } | ||
107 | |||
108 | __initcall(register_ethertap); | ||
109 | |||
110 | /* | ||
111 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
112 | * Emacs will notice this stuff at the end of the file and automatically | ||
113 | * adjust the settings for this buffer only. This must remain at the end | ||
114 | * of the file. | ||
115 | * --------------------------------------------------------------------------- | ||
116 | * Local variables: | ||
117 | * c-file-style: "linux" | ||
118 | * End: | ||
119 | */ | ||
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 | */ | ||
diff --git a/arch/um/os-Linux/drivers/tuntap.h b/arch/um/os-Linux/drivers/tuntap.h new file mode 100644 index 000000000000..25d4a2868814 --- /dev/null +++ b/arch/um/os-Linux/drivers/tuntap.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __UM_TUNTAP_H | ||
7 | #define __UM_TUNTAP_H | ||
8 | |||
9 | #include "net_user.h" | ||
10 | |||
11 | struct tuntap_data { | ||
12 | char *dev_name; | ||
13 | int fixed_config; | ||
14 | char *gate_addr; | ||
15 | int fd; | ||
16 | void *dev; | ||
17 | }; | ||
18 | |||
19 | extern struct net_user_info tuntap_user_info; | ||
20 | |||
21 | #endif | ||
22 | |||
23 | /* | ||
24 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
25 | * Emacs will notice this stuff at the end of the file and automatically | ||
26 | * adjust the settings for this buffer only. This must remain at the end | ||
27 | * of the file. | ||
28 | * --------------------------------------------------------------------------- | ||
29 | * Local variables: | ||
30 | * c-file-style: "linux" | ||
31 | * End: | ||
32 | */ | ||
diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c new file mode 100644 index 000000000000..4202b9ebad4c --- /dev/null +++ b/arch/um/os-Linux/drivers/tuntap_kern.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include "linux/stddef.h" | ||
7 | #include "linux/netdevice.h" | ||
8 | #include "linux/etherdevice.h" | ||
9 | #include "linux/skbuff.h" | ||
10 | #include "linux/init.h" | ||
11 | #include "asm/errno.h" | ||
12 | #include "net_kern.h" | ||
13 | #include "net_user.h" | ||
14 | #include "tuntap.h" | ||
15 | |||
16 | struct tuntap_init { | ||
17 | char *dev_name; | ||
18 | char *gate_addr; | ||
19 | }; | ||
20 | |||
21 | static void tuntap_init(struct net_device *dev, void *data) | ||
22 | { | ||
23 | struct uml_net_private *pri; | ||
24 | struct tuntap_data *tpri; | ||
25 | struct tuntap_init *init = data; | ||
26 | |||
27 | pri = dev->priv; | ||
28 | tpri = (struct tuntap_data *) pri->user; | ||
29 | tpri->dev_name = init->dev_name; | ||
30 | tpri->fixed_config = (init->dev_name != NULL); | ||
31 | tpri->gate_addr = init->gate_addr; | ||
32 | tpri->fd = -1; | ||
33 | tpri->dev = dev; | ||
34 | |||
35 | printk("TUN/TAP backend - "); | ||
36 | if (tpri->gate_addr != NULL) | ||
37 | printk("IP = %s", tpri->gate_addr); | ||
38 | printk("\n"); | ||
39 | } | ||
40 | |||
41 | static int tuntap_read(int fd, struct sk_buff **skb, | ||
42 | struct uml_net_private *lp) | ||
43 | { | ||
44 | *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); | ||
45 | if(*skb == NULL) return(-ENOMEM); | ||
46 | return(net_read(fd, (*skb)->mac.raw, | ||
47 | (*skb)->dev->mtu + ETH_HEADER_OTHER)); | ||
48 | } | ||
49 | |||
50 | static int tuntap_write(int fd, struct sk_buff **skb, | ||
51 | struct uml_net_private *lp) | ||
52 | { | ||
53 | return(net_write(fd, (*skb)->data, (*skb)->len)); | ||
54 | } | ||
55 | |||
56 | struct net_kern_info tuntap_kern_info = { | ||
57 | .init = tuntap_init, | ||
58 | .protocol = eth_protocol, | ||
59 | .read = tuntap_read, | ||
60 | .write = tuntap_write, | ||
61 | }; | ||
62 | |||
63 | int tuntap_setup(char *str, char **mac_out, void *data) | ||
64 | { | ||
65 | struct tuntap_init *init = data; | ||
66 | |||
67 | *init = ((struct tuntap_init) | ||
68 | { .dev_name = NULL, | ||
69 | .gate_addr = NULL }); | ||
70 | if(tap_setup_common(str, "tuntap", &init->dev_name, mac_out, | ||
71 | &init->gate_addr)) | ||
72 | return(0); | ||
73 | |||
74 | return(1); | ||
75 | } | ||
76 | |||
77 | static struct transport tuntap_transport = { | ||
78 | .list = LIST_HEAD_INIT(tuntap_transport.list), | ||
79 | .name = "tuntap", | ||
80 | .setup = tuntap_setup, | ||
81 | .user = &tuntap_user_info, | ||
82 | .kern = &tuntap_kern_info, | ||
83 | .private_size = sizeof(struct tuntap_data), | ||
84 | .setup_size = sizeof(struct tuntap_init), | ||
85 | }; | ||
86 | |||
87 | static int register_tuntap(void) | ||
88 | { | ||
89 | register_transport(&tuntap_transport); | ||
90 | return(1); | ||
91 | } | ||
92 | |||
93 | __initcall(register_tuntap); | ||
94 | |||
95 | /* | ||
96 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
97 | * Emacs will notice this stuff at the end of the file and automatically | ||
98 | * adjust the settings for this buffer only. This must remain at the end | ||
99 | * of the file. | ||
100 | * --------------------------------------------------------------------------- | ||
101 | * Local variables: | ||
102 | * c-file-style: "linux" | ||
103 | * End: | ||
104 | */ | ||
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 | */ | ||