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