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