1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <stddef.h> 5 #include <sched.h> 6 #include <string.h> 7 #include <errno.h> 8 #include <sys/termios.h> 9 #include <sys/wait.h> 10 #include <sys/signal.h> 11 #include "user_util.h" 12 #include "kern_util.h" 13 #include "user.h" 14 #include "net_user.h" 15 #include "slip.h" 16 #include "slip_proto.h" 17 #include "helper.h" 18 #include "os.h" 19 20 void slip_user_init(void *data, void *dev) 21 { 22 struct slip_data *pri = data; 23 24 pri->dev = dev; 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("could not get initial terminal attributes\n"); 34 return(-1); 35 } 36 37 tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL; 38 tios.c_iflag = IGNBRK | IGNPAR; 39 tios.c_oflag = 0; 40 tios.c_lflag = 0; 41 for (i = 0; i < NCCS; i++) 42 tios.c_cc[i] = 0; 43 tios.c_cc[VMIN] = 1; 44 tios.c_cc[VTIME] = 0; 45 46 cfsetospeed(&tios, B38400); 47 cfsetispeed(&tios, B38400); 48 49 if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { 50 printk("failed to set terminal attributes\n"); 51 return(-1); 52 } 53 return(0); 54 } 55 56 struct slip_pre_exec_data { 57 int stdin; 58 int stdout; 59 int close_me; 60 }; 61 62 static void slip_pre_exec(void *arg) 63 { 64 struct slip_pre_exec_data *data = arg; 65 66 if(data->stdin >= 0) dup2(data->stdin, 0); 67 dup2(data->stdout, 1); 68 if(data->close_me >= 0) os_close_file(data->close_me); 69 } 70 71 static int slip_tramp(char **argv, int fd) 72 { 73 struct slip_pre_exec_data pe_data; 74 char *output; 75 int status, pid, fds[2], err, output_len; 76 77 err = os_pipe(fds, 1, 0); 78 if(err < 0){ 79 printk("slip_tramp : pipe failed, err = %d\n", -err); 80 return(err); 81 } 82 83 err = 0; 84 pe_data.stdin = fd; 85 pe_data.stdout = fds[1]; 86 pe_data.close_me = fds[0]; 87 pid = run_helper(slip_pre_exec, &pe_data, argv, NULL); 88 89 if(pid < 0) err = pid; 90 else { 91 output_len = page_size(); 92 output = um_kmalloc(output_len); 93 if(output == NULL) 94 printk("slip_tramp : failed to allocate output " 95 "buffer\n"); 96 97 os_close_file(fds[1]); 98 read_output(fds[0], output, output_len); 99 if(output != NULL){ 100 printk("%s", output); 101 kfree(output); 102 } 103 CATCH_EINTR(err = waitpid(pid, &status, 0)); 104 if(err < 0) 105 err = errno; 106 else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){ 107 printk("'%s' didn't exit with status 0\n", argv[0]); 108 err = -EINVAL; 109 } 110 } 111 112 os_close_file(fds[0]); 113 114 return(err); 115 } 116 117 static int slip_open(void *data) 118 { 119 struct slip_data *pri = data; 120 char version_buf[sizeof("nnnnn\0")]; 121 char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; 122 char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, 123 NULL }; 124 int sfd, mfd, err; 125 126 mfd = get_pty(); 127 if(mfd < 0){ 128 printk("umn : Failed to open pty, err = %d\n", -mfd); 129 return(mfd); 130 } 131 sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0); 132 if(sfd < 0){ 133 printk("Couldn't open tty for slip line, err = %d\n", -sfd); 134 os_close_file(mfd); 135 return(sfd); 136 } 137 if(set_up_tty(sfd)) return(-1); 138 pri->slave = sfd; 139 pri->pos = 0; 140 pri->esc = 0; 141 if(pri->gate_addr != NULL){ 142 sprintf(version_buf, "%d", UML_NET_VERSION); 143 strcpy(gate_buf, pri->gate_addr); 144 145 err = slip_tramp(argv, sfd); 146 147 if(err < 0){ 148 printk("slip_tramp failed - err = %d\n", -err); 149 return(err); 150 } 151 err = os_get_ifname(pri->slave, pri->name); 152 if(err < 0){ 153 printk("get_ifname failed, err = %d\n", -err); 154 return(err); 155 } 156 iter_addresses(pri->dev, open_addr, pri->name); 157 } 158 else { 159 err = os_set_slip(sfd); 160 if(err < 0){ 161 printk("Failed to set slip discipline encapsulation - " 162 "err = %d\n", -err); 163 return(err); 164 } 165 } 166 return(mfd); 167 } 168 169 static void slip_close(int fd, void *data) 170 { 171 struct slip_data *pri = data; 172 char version_buf[sizeof("nnnnn\0")]; 173 char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name, 174 NULL }; 175 int err; 176 177 if(pri->gate_addr != NULL) 178 iter_addresses(pri->dev, close_addr, pri->name); 179 180 sprintf(version_buf, "%d", UML_NET_VERSION); 181 182 err = slip_tramp(argv, pri->slave); 183 184 if(err != 0) 185 printk("slip_tramp failed - errno = %d\n", -err); 186 os_close_file(fd); 187 os_close_file(pri->slave); 188 pri->slave = -1; 189 } 190 191 int slip_user_read(int fd, void *buf, int len, struct slip_data *pri) 192 { 193 int i, n, size, start; 194 195 if(pri->more>0) { 196 i = 0; 197 while(i < pri->more) { 198 size = slip_unesc(pri->ibuf[i++], 199 pri->ibuf, &pri->pos, &pri->esc); 200 if(size){ 201 memcpy(buf, pri->ibuf, size); 202 memmove(pri->ibuf, &pri->ibuf[i], pri->more-i); 203 pri->more=pri->more-i; 204 return(size); 205 } 206 } 207 pri->more=0; 208 } 209 210 n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos); 211 if(n <= 0) return(n); 212 213 start = pri->pos; 214 for(i = 0; i < n; i++){ 215 size = slip_unesc(pri->ibuf[start + i], 216 pri->ibuf, &pri->pos, &pri->esc); 217 if(size){ 218 memcpy(buf, pri->ibuf, size); 219 memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1)); 220 pri->more=n-(i+1); 221 return(size); 222 } 223 } 224 return(0); 225 } 226 227 int slip_user_write(int fd, void *buf, int len, struct slip_data *pri) 228 { 229 int actual, n; 230 231 actual = slip_esc(buf, pri->obuf, len); 232 n = net_write(fd, pri->obuf, actual); 233 if(n < 0) return(n); 234 else return(len); 235 } 236 237 static int slip_set_mtu(int mtu, void *data) 238 { 239 return(mtu); 240 } 241 242 static void slip_add_addr(unsigned char *addr, unsigned char *netmask, 243 void *data) 244 { 245 struct slip_data *pri = data; 246 247 if(pri->slave < 0) return; 248 open_addr(addr, netmask, pri->name); 249 } 250 251 static void slip_del_addr(unsigned char *addr, unsigned char *netmask, 252 void *data) 253 { 254 struct slip_data *pri = data; 255 256 if(pri->slave < 0) return; 257 close_addr(addr, netmask, pri->name); 258 } 259 260 struct net_user_info slip_user_info = { 261 .init = slip_user_init, 262 .open = slip_open, 263 .close = slip_close, 264 .remove = NULL, 265 .set_mtu = slip_set_mtu, 266 .add_address = slip_add_addr, 267 .delete_address = slip_del_addr, 268 .max_packet = BUF_SIZE 269 }; 270 271 /* 272 * Overrides for Emacs so that we follow Linus's tabbing style. 273 * Emacs will notice this stuff at the end of the file and automatically 274 * adjust the settings for this buffer only. This must remain at the end 275 * of the file. 276 * --------------------------------------------------------------------------- 277 * Local variables: 278 * c-file-style: "linux" 279 * End: 280 */ 281