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 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 = uml_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_close; 106 } 107 108 close(fds[1]); 109 read_output(fds[0], output, output_len); 110 printk("%s", output); 111 112 err = helper_wait(pid); 113 close(fds[0]); 114 115 kfree(output); 116 return err; 117 118 out_close: 119 close(fds[0]); 120 close(fds[1]); 121 out: 122 return err; 123 } 124 125 static int slip_open(void *data) 126 { 127 struct slip_data *pri = data; 128 char version_buf[sizeof("nnnnn\0")]; 129 char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; 130 char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, 131 NULL }; 132 int sfd, mfd, err; 133 134 err = get_pty(); 135 if (err < 0) { 136 printk(UM_KERN_ERR "slip-open : Failed to open pty, err = %d\n", 137 -err); 138 goto out; 139 } 140 mfd = err; 141 142 err = open(ptsname(mfd), O_RDWR, 0); 143 if (err < 0) { 144 printk(UM_KERN_ERR "Couldn't open tty for slip line, " 145 "err = %d\n", -err); 146 goto out_close; 147 } 148 sfd = err; 149 150 if (set_up_tty(sfd)) 151 goto out_close2; 152 153 pri->slave = sfd; 154 pri->slip.pos = 0; 155 pri->slip.esc = 0; 156 if (pri->gate_addr != NULL) { 157 sprintf(version_buf, "%d", UML_NET_VERSION); 158 strcpy(gate_buf, pri->gate_addr); 159 160 err = slip_tramp(argv, sfd); 161 162 if (err < 0) { 163 printk(UM_KERN_ERR "slip_tramp failed - err = %d\n", 164 -err); 165 goto out_close2; 166 } 167 err = os_get_ifname(pri->slave, pri->name); 168 if (err < 0) { 169 printk(UM_KERN_ERR "get_ifname failed, err = %d\n", 170 -err); 171 goto out_close2; 172 } 173 iter_addresses(pri->dev, open_addr, pri->name); 174 } 175 else { 176 err = os_set_slip(sfd); 177 if (err < 0) { 178 printk(UM_KERN_ERR "Failed to set slip discipline " 179 "encapsulation - err = %d\n", -err); 180 goto out_close2; 181 } 182 } 183 return mfd; 184 out_close2: 185 close(sfd); 186 out_close: 187 close(mfd); 188 out: 189 return err; 190 } 191 192 static void slip_close(int fd, void *data) 193 { 194 struct slip_data *pri = data; 195 char version_buf[sizeof("nnnnn\0")]; 196 char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name, 197 NULL }; 198 int err; 199 200 if (pri->gate_addr != NULL) 201 iter_addresses(pri->dev, close_addr, pri->name); 202 203 sprintf(version_buf, "%d", UML_NET_VERSION); 204 205 err = slip_tramp(argv, pri->slave); 206 207 if (err != 0) 208 printk(UM_KERN_ERR "slip_tramp failed - errno = %d\n", -err); 209 close(fd); 210 close(pri->slave); 211 pri->slave = -1; 212 } 213 214 int slip_user_read(int fd, void *buf, int len, struct slip_data *pri) 215 { 216 return slip_proto_read(fd, buf, len, &pri->slip); 217 } 218 219 int slip_user_write(int fd, void *buf, int len, struct slip_data *pri) 220 { 221 return slip_proto_write(fd, buf, len, &pri->slip); 222 } 223 224 static void slip_add_addr(unsigned char *addr, unsigned char *netmask, 225 void *data) 226 { 227 struct slip_data *pri = data; 228 229 if (pri->slave < 0) 230 return; 231 open_addr(addr, netmask, pri->name); 232 } 233 234 static void slip_del_addr(unsigned char *addr, unsigned char *netmask, 235 void *data) 236 { 237 struct slip_data *pri = data; 238 239 if (pri->slave < 0) 240 return; 241 close_addr(addr, netmask, pri->name); 242 } 243 244 const struct net_user_info slip_user_info = { 245 .init = slip_user_init, 246 .open = slip_open, 247 .close = slip_close, 248 .remove = NULL, 249 .add_address = slip_add_addr, 250 .delete_address = slip_del_addr, 251 .mtu = BUF_SIZE, 252 .max_packet = BUF_SIZE, 253 }; 254