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