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