Merge git://oss.sgi.com:8090/xfs/xfs-2.6
[linux-2.6-block.git] / arch / um / drivers / net_user.c
CommitLineData
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
22int 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 36void 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
53void 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
85err:
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
92int 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
105int 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
120int 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
133int 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
148int 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
164struct change_pre_exec_data {
165 int close_me;
166 int stdout;
167};
168
169static 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
177static 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
202static 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
232void open_addr(unsigned char *addr, unsigned char *netmask, void *arg)
233{
234 change(arg, "add", addr, netmask);
235}
236
237void close_addr(unsigned char *addr, unsigned char *netmask, void *arg)
238{
239 change(arg, "del", addr, netmask);
240}
241
242char *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}