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 <stddef.h> | |
7 | #include <stdarg.h> | |
8 | #include <unistd.h> | |
9 | #include <stdio.h> | |
10 | #include <errno.h> | |
11 | #include <stdlib.h> | |
12 | #include <string.h> | |
13 | #include <sys/socket.h> | |
14 | #include <sys/wait.h> | |
15 | #include "user.h" | |
16 | #include "user_util.h" | |
17 | #include "kern_util.h" | |
18 | #include "net_user.h" | |
1da177e4 LT |
19 | #include "os.h" |
20 | ||
21 | int tap_open_common(void *dev, char *gate_addr) | |
22 | { | |
23 | int tap_addr[4]; | |
24 | ||
25 | if(gate_addr == NULL) return(0); | |
26 | if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], | |
27 | &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){ | |
28 | printk("Invalid tap IP address - '%s'\n", gate_addr); | |
29 | return(-EINVAL); | |
30 | } | |
31 | return(0); | |
32 | } | |
33 | ||
da00d9a5 | 34 | void tap_check_ips(char *gate_addr, unsigned char *eth_addr) |
1da177e4 LT |
35 | { |
36 | int tap_addr[4]; | |
37 | ||
38 | if((gate_addr != NULL) && | |
39 | (sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], | |
40 | &tap_addr[1], &tap_addr[2], &tap_addr[3]) == 4) && | |
41 | (eth_addr[0] == tap_addr[0]) && | |
42 | (eth_addr[1] == tap_addr[1]) && | |
43 | (eth_addr[2] == tap_addr[2]) && | |
44 | (eth_addr[3] == tap_addr[3])){ | |
45 | printk("The tap IP address and the UML eth IP address" | |
46 | " must be different\n"); | |
47 | } | |
48 | } | |
49 | ||
f462e8f9 | 50 | /* Do reliable error handling as this fails frequently enough. */ |
1da177e4 LT |
51 | void read_output(int fd, char *output, int len) |
52 | { | |
f462e8f9 | 53 | int remain, ret, expected; |
1da177e4 | 54 | char c; |
f462e8f9 | 55 | char *str; |
1da177e4 LT |
56 | |
57 | if(output == NULL){ | |
58 | output = &c; | |
59 | len = sizeof(c); | |
60 | } | |
61 | ||
62 | *output = '\0'; | |
f462e8f9 PBG |
63 | ret = os_read_file(fd, &remain, sizeof(remain)); |
64 | ||
65 | if (ret != sizeof(remain)) { | |
66 | expected = sizeof(remain); | |
67 | str = "length"; | |
68 | goto err; | |
1da177e4 LT |
69 | } |
70 | ||
71 | while(remain != 0){ | |
f462e8f9 PBG |
72 | expected = (remain < len) ? remain : len; |
73 | ret = os_read_file(fd, output, expected); | |
74 | if (ret != expected) { | |
75 | str = "data"; | |
76 | goto err; | |
1da177e4 | 77 | } |
f462e8f9 | 78 | remain -= ret; |
1da177e4 | 79 | } |
f462e8f9 | 80 | |
1da177e4 | 81 | return; |
f462e8f9 PBG |
82 | |
83 | err: | |
84 | if (ret < 0) | |
85 | printk("read_output - read of %s failed, errno = %d\n", str, -ret); | |
86 | else | |
87 | printk("read_output - read of %s failed, read only %d of %d bytes\n", str, ret, expected); | |
1da177e4 LT |
88 | } |
89 | ||
90 | int net_read(int fd, void *buf, int len) | |
91 | { | |
92 | int n; | |
93 | ||
94 | n = os_read_file(fd, buf, len); | |
95 | ||
96 | if(n == -EAGAIN) | |
97 | return(0); | |
98 | else if(n == 0) | |
99 | return(-ENOTCONN); | |
100 | return(n); | |
101 | } | |
102 | ||
103 | int net_recvfrom(int fd, void *buf, int len) | |
104 | { | |
105 | int n; | |
106 | ||
107 | while(((n = recvfrom(fd, buf, len, 0, NULL, NULL)) < 0) && | |
108 | (errno == EINTR)) ; | |
109 | ||
110 | if(n < 0){ | |
111 | if(errno == EAGAIN) return(0); | |
112 | return(-errno); | |
113 | } | |
114 | else if(n == 0) return(-ENOTCONN); | |
115 | return(n); | |
116 | } | |
117 | ||
118 | int net_write(int fd, void *buf, int len) | |
119 | { | |
120 | int n; | |
121 | ||
122 | n = os_write_file(fd, buf, len); | |
123 | ||
124 | if(n == -EAGAIN) | |
125 | return(0); | |
126 | else if(n == 0) | |
127 | return(-ENOTCONN); | |
128 | return(n); | |
129 | } | |
130 | ||
131 | int net_send(int fd, void *buf, int len) | |
132 | { | |
133 | int n; | |
134 | ||
135 | while(((n = send(fd, buf, len, 0)) < 0) && (errno == EINTR)) ; | |
136 | if(n < 0){ | |
137 | if(errno == EAGAIN) return(0); | |
138 | return(-errno); | |
139 | } | |
140 | else if(n == 0) return(-ENOTCONN); | |
141 | return(n); | |
142 | } | |
143 | ||
144 | int net_sendto(int fd, void *buf, int len, void *to, int sock_len) | |
145 | { | |
146 | int n; | |
147 | ||
148 | while(((n = sendto(fd, buf, len, 0, (struct sockaddr *) to, | |
149 | sock_len)) < 0) && (errno == EINTR)) ; | |
150 | if(n < 0){ | |
151 | if(errno == EAGAIN) return(0); | |
152 | return(-errno); | |
153 | } | |
154 | else if(n == 0) return(-ENOTCONN); | |
155 | return(n); | |
156 | } | |
157 | ||
158 | struct change_pre_exec_data { | |
159 | int close_me; | |
160 | int stdout; | |
161 | }; | |
162 | ||
163 | static void change_pre_exec(void *arg) | |
164 | { | |
165 | struct change_pre_exec_data *data = arg; | |
166 | ||
167 | os_close_file(data->close_me); | |
168 | dup2(data->stdout, 1); | |
169 | } | |
170 | ||
171 | static int change_tramp(char **argv, char *output, int output_len) | |
172 | { | |
173 | int pid, fds[2], err; | |
174 | struct change_pre_exec_data pe_data; | |
175 | ||
176 | err = os_pipe(fds, 1, 0); | |
177 | if(err < 0){ | |
178 | printk("change_tramp - pipe failed, err = %d\n", -err); | |
179 | return(err); | |
180 | } | |
181 | pe_data.close_me = fds[0]; | |
182 | pe_data.stdout = fds[1]; | |
183 | pid = run_helper(change_pre_exec, &pe_data, argv, NULL); | |
184 | ||
b1c332c9 PBG |
185 | if (pid > 0) /* Avoid hang as we won't get data in failure case. */ |
186 | read_output(fds[0], output, output_len); | |
187 | ||
1da177e4 LT |
188 | os_close_file(fds[0]); |
189 | os_close_file(fds[1]); | |
190 | ||
191 | if (pid > 0) | |
192 | CATCH_EINTR(err = waitpid(pid, NULL, 0)); | |
193 | return(pid); | |
194 | } | |
195 | ||
196 | static void change(char *dev, char *what, unsigned char *addr, | |
197 | unsigned char *netmask) | |
198 | { | |
199 | char addr_buf[sizeof("255.255.255.255\0")]; | |
200 | char netmask_buf[sizeof("255.255.255.255\0")]; | |
201 | char version[sizeof("nnnnn\0")]; | |
202 | char *argv[] = { "uml_net", version, what, dev, addr_buf, | |
203 | netmask_buf, NULL }; | |
204 | char *output; | |
205 | int output_len, pid; | |
206 | ||
207 | sprintf(version, "%d", UML_NET_VERSION); | |
208 | sprintf(addr_buf, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); | |
209 | sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1], | |
210 | netmask[2], netmask[3]); | |
211 | ||
212 | output_len = page_size(); | |
213 | output = um_kmalloc(output_len); | |
214 | if(output == NULL) | |
215 | printk("change : failed to allocate output buffer\n"); | |
216 | ||
217 | pid = change_tramp(argv, output, output_len); | |
218 | if(pid < 0) return; | |
219 | ||
220 | if(output != NULL){ | |
221 | printk("%s", output); | |
222 | kfree(output); | |
223 | } | |
224 | } | |
225 | ||
226 | void open_addr(unsigned char *addr, unsigned char *netmask, void *arg) | |
227 | { | |
228 | change(arg, "add", addr, netmask); | |
229 | } | |
230 | ||
231 | void close_addr(unsigned char *addr, unsigned char *netmask, void *arg) | |
232 | { | |
233 | change(arg, "del", addr, netmask); | |
234 | } | |
235 | ||
236 | char *split_if_spec(char *str, ...) | |
237 | { | |
238 | char **arg, *end; | |
239 | va_list ap; | |
240 | ||
241 | va_start(ap, str); | |
242 | while((arg = va_arg(ap, char **)) != NULL){ | |
243 | if(*str == '\0') | |
244 | return(NULL); | |
245 | end = strchr(str, ','); | |
246 | if(end != str) | |
247 | *arg = str; | |
248 | if(end == NULL) | |
249 | return(NULL); | |
250 | *end++ = '\0'; | |
251 | str = end; | |
252 | } | |
253 | va_end(ap); | |
254 | return(str); | |
255 | } | |
256 | ||
257 | /* | |
258 | * Overrides for Emacs so that we follow Linus's tabbing style. | |
259 | * Emacs will notice this stuff at the end of the file and automatically | |
260 | * adjust the settings for this buffer only. This must remain at the end | |
261 | * of the file. | |
262 | * --------------------------------------------------------------------------- | |
263 | * Local variables: | |
264 | * c-file-style: "linux" | |
265 | * End: | |
266 | */ |