1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <stdio.h>
7*4882a593Smuzhiyun #include <stdlib.h>
8*4882a593Smuzhiyun #include <unistd.h>
9*4882a593Smuzhiyun #include <errno.h>
10*4882a593Smuzhiyun #include <fcntl.h>
11*4882a593Smuzhiyun #include <string.h>
12*4882a593Smuzhiyun #include <termios.h>
13*4882a593Smuzhiyun #include <sys/wait.h>
14*4882a593Smuzhiyun #include <net_user.h>
15*4882a593Smuzhiyun #include <os.h>
16*4882a593Smuzhiyun #include "slip.h"
17*4882a593Smuzhiyun #include <um_malloc.h>
18*4882a593Smuzhiyun
slip_user_init(void * data,void * dev)19*4882a593Smuzhiyun static int slip_user_init(void *data, void *dev)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun struct slip_data *pri = data;
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun pri->dev = dev;
24*4882a593Smuzhiyun return 0;
25*4882a593Smuzhiyun }
26*4882a593Smuzhiyun
set_up_tty(int fd)27*4882a593Smuzhiyun static int set_up_tty(int fd)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun int i;
30*4882a593Smuzhiyun struct termios tios;
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun if (tcgetattr(fd, &tios) < 0) {
33*4882a593Smuzhiyun printk(UM_KERN_ERR "could not get initial terminal "
34*4882a593Smuzhiyun "attributes\n");
35*4882a593Smuzhiyun return -1;
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL;
39*4882a593Smuzhiyun tios.c_iflag = IGNBRK | IGNPAR;
40*4882a593Smuzhiyun tios.c_oflag = 0;
41*4882a593Smuzhiyun tios.c_lflag = 0;
42*4882a593Smuzhiyun for (i = 0; i < NCCS; i++)
43*4882a593Smuzhiyun tios.c_cc[i] = 0;
44*4882a593Smuzhiyun tios.c_cc[VMIN] = 1;
45*4882a593Smuzhiyun tios.c_cc[VTIME] = 0;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun cfsetospeed(&tios, B38400);
48*4882a593Smuzhiyun cfsetispeed(&tios, B38400);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
51*4882a593Smuzhiyun printk(UM_KERN_ERR "failed to set terminal attributes\n");
52*4882a593Smuzhiyun return -1;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun return 0;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun struct slip_pre_exec_data {
58*4882a593Smuzhiyun int stdin_fd;
59*4882a593Smuzhiyun int stdout_fd;
60*4882a593Smuzhiyun int close_me;
61*4882a593Smuzhiyun };
62*4882a593Smuzhiyun
slip_pre_exec(void * arg)63*4882a593Smuzhiyun static void slip_pre_exec(void *arg)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun struct slip_pre_exec_data *data = arg;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun if (data->stdin_fd >= 0)
68*4882a593Smuzhiyun dup2(data->stdin_fd, 0);
69*4882a593Smuzhiyun dup2(data->stdout_fd, 1);
70*4882a593Smuzhiyun if (data->close_me >= 0)
71*4882a593Smuzhiyun close(data->close_me);
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
slip_tramp(char ** argv,int fd)74*4882a593Smuzhiyun static int slip_tramp(char **argv, int fd)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun struct slip_pre_exec_data pe_data;
77*4882a593Smuzhiyun char *output;
78*4882a593Smuzhiyun int pid, fds[2], err, output_len;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun err = os_pipe(fds, 1, 0);
81*4882a593Smuzhiyun if (err < 0) {
82*4882a593Smuzhiyun printk(UM_KERN_ERR "slip_tramp : pipe failed, err = %d\n",
83*4882a593Smuzhiyun -err);
84*4882a593Smuzhiyun goto out;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun err = 0;
88*4882a593Smuzhiyun pe_data.stdin_fd = fd;
89*4882a593Smuzhiyun pe_data.stdout_fd = fds[1];
90*4882a593Smuzhiyun pe_data.close_me = fds[0];
91*4882a593Smuzhiyun err = run_helper(slip_pre_exec, &pe_data, argv);
92*4882a593Smuzhiyun if (err < 0)
93*4882a593Smuzhiyun goto out_close;
94*4882a593Smuzhiyun pid = err;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun output_len = UM_KERN_PAGE_SIZE;
97*4882a593Smuzhiyun output = uml_kmalloc(output_len, UM_GFP_KERNEL);
98*4882a593Smuzhiyun if (output == NULL) {
99*4882a593Smuzhiyun printk(UM_KERN_ERR "slip_tramp : failed to allocate output "
100*4882a593Smuzhiyun "buffer\n");
101*4882a593Smuzhiyun os_kill_process(pid, 1);
102*4882a593Smuzhiyun err = -ENOMEM;
103*4882a593Smuzhiyun goto out_close;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun close(fds[1]);
107*4882a593Smuzhiyun read_output(fds[0], output, output_len);
108*4882a593Smuzhiyun printk("%s", output);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun err = helper_wait(pid);
111*4882a593Smuzhiyun close(fds[0]);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun kfree(output);
114*4882a593Smuzhiyun return err;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun out_close:
117*4882a593Smuzhiyun close(fds[0]);
118*4882a593Smuzhiyun close(fds[1]);
119*4882a593Smuzhiyun out:
120*4882a593Smuzhiyun return err;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
slip_open(void * data)123*4882a593Smuzhiyun static int slip_open(void *data)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun struct slip_data *pri = data;
126*4882a593Smuzhiyun char version_buf[sizeof("nnnnn\0")];
127*4882a593Smuzhiyun char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
128*4882a593Smuzhiyun char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf,
129*4882a593Smuzhiyun NULL };
130*4882a593Smuzhiyun int sfd, mfd, err;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun err = get_pty();
133*4882a593Smuzhiyun if (err < 0) {
134*4882a593Smuzhiyun printk(UM_KERN_ERR "slip-open : Failed to open pty, err = %d\n",
135*4882a593Smuzhiyun -err);
136*4882a593Smuzhiyun goto out;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun mfd = err;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun err = open(ptsname(mfd), O_RDWR, 0);
141*4882a593Smuzhiyun if (err < 0) {
142*4882a593Smuzhiyun printk(UM_KERN_ERR "Couldn't open tty for slip line, "
143*4882a593Smuzhiyun "err = %d\n", -err);
144*4882a593Smuzhiyun goto out_close;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun sfd = err;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun err = set_up_tty(sfd);
149*4882a593Smuzhiyun if (err)
150*4882a593Smuzhiyun goto out_close2;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun pri->slave = sfd;
153*4882a593Smuzhiyun pri->slip.pos = 0;
154*4882a593Smuzhiyun pri->slip.esc = 0;
155*4882a593Smuzhiyun if (pri->gate_addr != NULL) {
156*4882a593Smuzhiyun sprintf(version_buf, "%d", UML_NET_VERSION);
157*4882a593Smuzhiyun strcpy(gate_buf, pri->gate_addr);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun err = slip_tramp(argv, sfd);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun if (err < 0) {
162*4882a593Smuzhiyun printk(UM_KERN_ERR "slip_tramp failed - err = %d\n",
163*4882a593Smuzhiyun -err);
164*4882a593Smuzhiyun goto out_close2;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun err = os_get_ifname(pri->slave, pri->name);
167*4882a593Smuzhiyun if (err < 0) {
168*4882a593Smuzhiyun printk(UM_KERN_ERR "get_ifname failed, err = %d\n",
169*4882a593Smuzhiyun -err);
170*4882a593Smuzhiyun goto out_close2;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun iter_addresses(pri->dev, open_addr, pri->name);
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun else {
175*4882a593Smuzhiyun err = os_set_slip(sfd);
176*4882a593Smuzhiyun if (err < 0) {
177*4882a593Smuzhiyun printk(UM_KERN_ERR "Failed to set slip discipline "
178*4882a593Smuzhiyun "encapsulation - err = %d\n", -err);
179*4882a593Smuzhiyun goto out_close2;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun return mfd;
183*4882a593Smuzhiyun out_close2:
184*4882a593Smuzhiyun close(sfd);
185*4882a593Smuzhiyun out_close:
186*4882a593Smuzhiyun close(mfd);
187*4882a593Smuzhiyun out:
188*4882a593Smuzhiyun return err;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
slip_close(int fd,void * data)191*4882a593Smuzhiyun static void slip_close(int fd, void *data)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun struct slip_data *pri = data;
194*4882a593Smuzhiyun char version_buf[sizeof("nnnnn\0")];
195*4882a593Smuzhiyun char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name,
196*4882a593Smuzhiyun NULL };
197*4882a593Smuzhiyun int err;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if (pri->gate_addr != NULL)
200*4882a593Smuzhiyun iter_addresses(pri->dev, close_addr, pri->name);
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun sprintf(version_buf, "%d", UML_NET_VERSION);
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun err = slip_tramp(argv, pri->slave);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun if (err != 0)
207*4882a593Smuzhiyun printk(UM_KERN_ERR "slip_tramp failed - errno = %d\n", -err);
208*4882a593Smuzhiyun close(fd);
209*4882a593Smuzhiyun close(pri->slave);
210*4882a593Smuzhiyun pri->slave = -1;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
slip_user_read(int fd,void * buf,int len,struct slip_data * pri)213*4882a593Smuzhiyun int slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun return slip_proto_read(fd, buf, len, &pri->slip);
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
slip_user_write(int fd,void * buf,int len,struct slip_data * pri)218*4882a593Smuzhiyun int slip_user_write(int fd, void *buf, int len, struct slip_data *pri)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun return slip_proto_write(fd, buf, len, &pri->slip);
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun
slip_add_addr(unsigned char * addr,unsigned char * netmask,void * data)223*4882a593Smuzhiyun static void slip_add_addr(unsigned char *addr, unsigned char *netmask,
224*4882a593Smuzhiyun void *data)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun struct slip_data *pri = data;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun if (pri->slave < 0)
229*4882a593Smuzhiyun return;
230*4882a593Smuzhiyun open_addr(addr, netmask, pri->name);
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
slip_del_addr(unsigned char * addr,unsigned char * netmask,void * data)233*4882a593Smuzhiyun static void slip_del_addr(unsigned char *addr, unsigned char *netmask,
234*4882a593Smuzhiyun void *data)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun struct slip_data *pri = data;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun if (pri->slave < 0)
239*4882a593Smuzhiyun return;
240*4882a593Smuzhiyun close_addr(addr, netmask, pri->name);
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun const struct net_user_info slip_user_info = {
244*4882a593Smuzhiyun .init = slip_user_init,
245*4882a593Smuzhiyun .open = slip_open,
246*4882a593Smuzhiyun .close = slip_close,
247*4882a593Smuzhiyun .remove = NULL,
248*4882a593Smuzhiyun .add_address = slip_add_addr,
249*4882a593Smuzhiyun .delete_address = slip_del_addr,
250*4882a593Smuzhiyun .mtu = BUF_SIZE,
251*4882a593Smuzhiyun .max_packet = BUF_SIZE,
252*4882a593Smuzhiyun };
253