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