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