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 <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 if (set_up_tty(sfd)) 149 goto out_close2; 150 151 pri->slave = sfd; 152 pri->slip.pos = 0; 153 pri->slip.esc = 0; 154 if (pri->gate_addr != NULL) { 155 sprintf(version_buf, "%d", UML_NET_VERSION); 156 strcpy(gate_buf, pri->gate_addr); 157 158 err = slip_tramp(argv, sfd); 159 160 if (err < 0) { 161 printk(UM_KERN_ERR "slip_tramp failed - err = %d\n", 162 -err); 163 goto out_close2; 164 } 165 err = os_get_ifname(pri->slave, pri->name); 166 if (err < 0) { 167 printk(UM_KERN_ERR "get_ifname failed, err = %d\n", 168 -err); 169 goto out_close2; 170 } 171 iter_addresses(pri->dev, open_addr, pri->name); 172 } 173 else { 174 err = os_set_slip(sfd); 175 if (err < 0) { 176 printk(UM_KERN_ERR "Failed to set slip discipline " 177 "encapsulation - err = %d\n", -err); 178 goto out_close2; 179 } 180 } 181 return mfd; 182 out_close2: 183 close(sfd); 184 out_close: 185 close(mfd); 186 out: 187 return err; 188 } 189 190 static void slip_close(int fd, void *data) 191 { 192 struct slip_data *pri = data; 193 char version_buf[sizeof("nnnnn\0")]; 194 char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name, 195 NULL }; 196 int err; 197 198 if (pri->gate_addr != NULL) 199 iter_addresses(pri->dev, close_addr, pri->name); 200 201 sprintf(version_buf, "%d", UML_NET_VERSION); 202 203 err = slip_tramp(argv, pri->slave); 204 205 if (err != 0) 206 printk(UM_KERN_ERR "slip_tramp failed - errno = %d\n", -err); 207 close(fd); 208 close(pri->slave); 209 pri->slave = -1; 210 } 211 212 int slip_user_read(int fd, void *buf, int len, struct slip_data *pri) 213 { 214 return slip_proto_read(fd, buf, len, &pri->slip); 215 } 216 217 int slip_user_write(int fd, void *buf, int len, struct slip_data *pri) 218 { 219 return slip_proto_write(fd, buf, len, &pri->slip); 220 } 221 222 static void slip_add_addr(unsigned char *addr, unsigned char *netmask, 223 void *data) 224 { 225 struct slip_data *pri = data; 226 227 if (pri->slave < 0) 228 return; 229 open_addr(addr, netmask, pri->name); 230 } 231 232 static void slip_del_addr(unsigned char *addr, unsigned char *netmask, 233 void *data) 234 { 235 struct slip_data *pri = data; 236 237 if (pri->slave < 0) 238 return; 239 close_addr(addr, netmask, pri->name); 240 } 241 242 const struct net_user_info slip_user_info = { 243 .init = slip_user_init, 244 .open = slip_open, 245 .close = slip_close, 246 .remove = NULL, 247 .add_address = slip_add_addr, 248 .delete_address = slip_del_addr, 249 .mtu = BUF_SIZE, 250 .max_packet = BUF_SIZE, 251 }; 252