1 /* 2 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) 3 * Licensed under the GPL 4 */ 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <errno.h> 9 #include <termios.h> 10 #include <unistd.h> 11 #include <netinet/in.h> 12 #include "chan_user.h" 13 #include "kern_constants.h" 14 #include "os.h" 15 #include "port.h" 16 #include "um_malloc.h" 17 #include "user.h" 18 19 struct port_chan { 20 int raw; 21 struct termios tt; 22 void *kernel_data; 23 char dev[sizeof("32768\0")]; 24 }; 25 26 static void *port_init(char *str, int device, const struct chan_opts *opts) 27 { 28 struct port_chan *data; 29 void *kern_data; 30 char *end; 31 int port; 32 33 if (*str != ':') { 34 printk(UM_KERN_ERR "port_init : channel type 'port' must " 35 "specify a port number\n"); 36 return NULL; 37 } 38 str++; 39 port = strtoul(str, &end, 0); 40 if ((*end != '\0') || (end == str)) { 41 printk(UM_KERN_ERR "port_init : couldn't parse port '%s'\n", 42 str); 43 return NULL; 44 } 45 46 kern_data = port_data(port); 47 if (kern_data == NULL) 48 return NULL; 49 50 data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL); 51 if (data == NULL) 52 goto err; 53 54 *data = ((struct port_chan) { .raw = opts->raw, 55 .kernel_data = kern_data }); 56 sprintf(data->dev, "%d", port); 57 58 return data; 59 err: 60 port_kern_free(kern_data); 61 return NULL; 62 } 63 64 static void port_free(void *d) 65 { 66 struct port_chan *data = d; 67 68 port_kern_free(data->kernel_data); 69 kfree(data); 70 } 71 72 static int port_open(int input, int output, int primary, void *d, 73 char **dev_out) 74 { 75 struct port_chan *data = d; 76 int fd, err; 77 78 fd = port_wait(data->kernel_data); 79 if ((fd >= 0) && data->raw) { 80 CATCH_EINTR(err = tcgetattr(fd, &data->tt)); 81 if (err) 82 return err; 83 84 err = raw(fd); 85 if (err) 86 return err; 87 } 88 *dev_out = data->dev; 89 return fd; 90 } 91 92 static void port_close(int fd, void *d) 93 { 94 struct port_chan *data = d; 95 96 port_remove_dev(data->kernel_data); 97 os_close_file(fd); 98 } 99 100 const struct chan_ops port_ops = { 101 .type = "port", 102 .init = port_init, 103 .open = port_open, 104 .close = port_close, 105 .read = generic_read, 106 .write = generic_write, 107 .console_write = generic_console_write, 108 .window_size = generic_window_size, 109 .free = port_free, 110 .winch = 1, 111 }; 112 113 int port_listen_fd(int port) 114 { 115 struct sockaddr_in addr; 116 int fd, err, arg; 117 118 fd = socket(PF_INET, SOCK_STREAM, 0); 119 if (fd == -1) 120 return -errno; 121 122 arg = 1; 123 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0) { 124 err = -errno; 125 goto out; 126 } 127 128 addr.sin_family = AF_INET; 129 addr.sin_port = htons(port); 130 addr.sin_addr.s_addr = htonl(INADDR_ANY); 131 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 132 err = -errno; 133 goto out; 134 } 135 136 if (listen(fd, 1) < 0) { 137 err = -errno; 138 goto out; 139 } 140 141 err = os_set_fd_block(fd, 0); 142 if (err < 0) 143 goto out; 144 145 return fd; 146 out: 147 close(fd); 148 return err; 149 } 150 151 struct port_pre_exec_data { 152 int sock_fd; 153 int pipe_fd; 154 }; 155 156 static void port_pre_exec(void *arg) 157 { 158 struct port_pre_exec_data *data = arg; 159 160 dup2(data->sock_fd, 0); 161 dup2(data->sock_fd, 1); 162 dup2(data->sock_fd, 2); 163 close(data->sock_fd); 164 dup2(data->pipe_fd, 3); 165 shutdown(3, SHUT_RD); 166 close(data->pipe_fd); 167 } 168 169 int port_connection(int fd, int *socket, int *pid_out) 170 { 171 int new, err; 172 char *argv[] = { "/usr/sbin/in.telnetd", "-L", 173 "/usr/lib/uml/port-helper", NULL }; 174 struct port_pre_exec_data data; 175 176 new = accept(fd, NULL, 0); 177 if (new < 0) 178 return -errno; 179 180 err = os_pipe(socket, 0, 0); 181 if (err < 0) 182 goto out_close; 183 184 data = ((struct port_pre_exec_data) 185 { .sock_fd = new, 186 .pipe_fd = socket[1] }); 187 188 err = run_helper(port_pre_exec, &data, argv); 189 if (err < 0) 190 goto out_shutdown; 191 192 *pid_out = err; 193 return new; 194 195 out_shutdown: 196 shutdown(socket[0], SHUT_RDWR); 197 close(socket[0]); 198 shutdown(socket[1], SHUT_RDWR); 199 close(socket[1]); 200 out_close: 201 close(new); 202 return err; 203 } 204