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