11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) 31da177e4SLinus Torvalds * Licensed under the GPL 41da177e4SLinus Torvalds */ 51da177e4SLinus Torvalds 61da177e4SLinus Torvalds #include <stdio.h> 71da177e4SLinus Torvalds #include <stddef.h> 81da177e4SLinus Torvalds #include <stdlib.h> 91da177e4SLinus Torvalds #include <string.h> 101da177e4SLinus Torvalds #include <errno.h> 111da177e4SLinus Torvalds #include <unistd.h> 121da177e4SLinus Torvalds #include <termios.h> 131da177e4SLinus Torvalds #include <sys/socket.h> 141da177e4SLinus Torvalds #include <sys/un.h> 151da177e4SLinus Torvalds #include <netinet/in.h> 161da177e4SLinus Torvalds #include "kern_util.h" 171da177e4SLinus Torvalds #include "user.h" 181da177e4SLinus Torvalds #include "chan_user.h" 191da177e4SLinus Torvalds #include "port.h" 201da177e4SLinus Torvalds #include "os.h" 21c13e5690SPaolo 'Blaisorblade' Giarrusso #include "um_malloc.h" 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds struct port_chan { 241da177e4SLinus Torvalds int raw; 251da177e4SLinus Torvalds struct termios tt; 261da177e4SLinus Torvalds void *kernel_data; 271da177e4SLinus Torvalds char dev[sizeof("32768\0")]; 281da177e4SLinus Torvalds }; 291da177e4SLinus Torvalds 305e7672ecSJeff Dike static void *port_init(char *str, int device, const struct chan_opts *opts) 311da177e4SLinus Torvalds { 321da177e4SLinus Torvalds struct port_chan *data; 331da177e4SLinus Torvalds void *kern_data; 341da177e4SLinus Torvalds char *end; 351da177e4SLinus Torvalds int port; 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds if(*str != ':'){ 381da177e4SLinus Torvalds printk("port_init : channel type 'port' must specify a " 391da177e4SLinus Torvalds "port number\n"); 4067608e0cSJeff Dike return NULL; 411da177e4SLinus Torvalds } 421da177e4SLinus Torvalds str++; 431da177e4SLinus Torvalds port = strtoul(str, &end, 0); 441da177e4SLinus Torvalds if((*end != '\0') || (end == str)){ 451da177e4SLinus Torvalds printk("port_init : couldn't parse port '%s'\n", str); 4667608e0cSJeff Dike return NULL; 471da177e4SLinus Torvalds } 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds kern_data = port_data(port); 501da177e4SLinus Torvalds if(kern_data == NULL) 5167608e0cSJeff Dike return NULL; 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds data = um_kmalloc(sizeof(*data)); 541da177e4SLinus Torvalds if(data == NULL) 551da177e4SLinus Torvalds goto err; 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds *data = ((struct port_chan) { .raw = opts->raw, 581da177e4SLinus Torvalds .kernel_data = kern_data }); 591da177e4SLinus Torvalds sprintf(data->dev, "%d", port); 601da177e4SLinus Torvalds 6167608e0cSJeff Dike return data; 621da177e4SLinus Torvalds err: 631da177e4SLinus Torvalds port_kern_free(kern_data); 6467608e0cSJeff Dike return NULL; 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds static void port_free(void *d) 681da177e4SLinus Torvalds { 691da177e4SLinus Torvalds struct port_chan *data = d; 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds port_kern_free(data->kernel_data); 721da177e4SLinus Torvalds kfree(data); 731da177e4SLinus Torvalds } 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds static int port_open(int input, int output, int primary, void *d, 761da177e4SLinus Torvalds char **dev_out) 771da177e4SLinus Torvalds { 781da177e4SLinus Torvalds struct port_chan *data = d; 791da177e4SLinus Torvalds int fd, err; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds fd = port_wait(data->kernel_data); 821da177e4SLinus Torvalds if((fd >= 0) && data->raw){ 831da177e4SLinus Torvalds CATCH_EINTR(err = tcgetattr(fd, &data->tt)); 841da177e4SLinus Torvalds if(err) 8567608e0cSJeff Dike return err; 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds err = raw(fd); 881da177e4SLinus Torvalds if(err) 8967608e0cSJeff Dike return err; 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds *dev_out = data->dev; 9267608e0cSJeff Dike return fd; 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds static void port_close(int fd, void *d) 961da177e4SLinus Torvalds { 971da177e4SLinus Torvalds struct port_chan *data = d; 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds port_remove_dev(data->kernel_data); 1001da177e4SLinus Torvalds os_close_file(fd); 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds 1035e7672ecSJeff Dike const struct chan_ops port_ops = { 1041da177e4SLinus Torvalds .type = "port", 1051da177e4SLinus Torvalds .init = port_init, 1061da177e4SLinus Torvalds .open = port_open, 1071da177e4SLinus Torvalds .close = port_close, 1081da177e4SLinus Torvalds .read = generic_read, 1091da177e4SLinus Torvalds .write = generic_write, 110fd9bc53bSPaolo 'Blaisorblade' Giarrusso .console_write = generic_console_write, 1111da177e4SLinus Torvalds .window_size = generic_window_size, 1121da177e4SLinus Torvalds .free = port_free, 1131da177e4SLinus Torvalds .winch = 1, 1141da177e4SLinus Torvalds }; 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds int port_listen_fd(int port) 1171da177e4SLinus Torvalds { 1181da177e4SLinus Torvalds struct sockaddr_in addr; 1191da177e4SLinus Torvalds int fd, err, arg; 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds fd = socket(PF_INET, SOCK_STREAM, 0); 1221da177e4SLinus Torvalds if(fd == -1) 12367608e0cSJeff Dike return -errno; 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds arg = 1; 1261da177e4SLinus Torvalds if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0){ 1271da177e4SLinus Torvalds err = -errno; 1281da177e4SLinus Torvalds goto out; 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds addr.sin_family = AF_INET; 1321da177e4SLinus Torvalds addr.sin_port = htons(port); 1331da177e4SLinus Torvalds addr.sin_addr.s_addr = htonl(INADDR_ANY); 1341da177e4SLinus Torvalds if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0){ 1351da177e4SLinus Torvalds err = -errno; 1361da177e4SLinus Torvalds goto out; 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds if(listen(fd, 1) < 0){ 1401da177e4SLinus Torvalds err = -errno; 1411da177e4SLinus Torvalds goto out; 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds err = os_set_fd_block(fd, 0); 1451da177e4SLinus Torvalds if(err < 0) 1461da177e4SLinus Torvalds goto out; 1471da177e4SLinus Torvalds 14867608e0cSJeff Dike return fd; 1491da177e4SLinus Torvalds out: 1501da177e4SLinus Torvalds os_close_file(fd); 15167608e0cSJeff Dike return err; 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds struct port_pre_exec_data { 1551da177e4SLinus Torvalds int sock_fd; 1561da177e4SLinus Torvalds int pipe_fd; 1571da177e4SLinus Torvalds }; 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds void port_pre_exec(void *arg) 1601da177e4SLinus Torvalds { 1611da177e4SLinus Torvalds struct port_pre_exec_data *data = arg; 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds dup2(data->sock_fd, 0); 1641da177e4SLinus Torvalds dup2(data->sock_fd, 1); 1651da177e4SLinus Torvalds dup2(data->sock_fd, 2); 1661da177e4SLinus Torvalds os_close_file(data->sock_fd); 1671da177e4SLinus Torvalds dup2(data->pipe_fd, 3); 1681da177e4SLinus Torvalds os_shutdown_socket(3, 1, 0); 1691da177e4SLinus Torvalds os_close_file(data->pipe_fd); 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds int port_connection(int fd, int *socket, int *pid_out) 1731da177e4SLinus Torvalds { 1741da177e4SLinus Torvalds int new, err; 1751da177e4SLinus Torvalds char *argv[] = { "/usr/sbin/in.telnetd", "-L", 1761da177e4SLinus Torvalds "/usr/lib/uml/port-helper", NULL }; 1771da177e4SLinus Torvalds struct port_pre_exec_data data; 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds new = os_accept_connection(fd); 1801da177e4SLinus Torvalds if(new < 0) 18167608e0cSJeff Dike return new; 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds err = os_pipe(socket, 0, 0); 1841da177e4SLinus Torvalds if(err < 0) 1851da177e4SLinus Torvalds goto out_close; 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds data = ((struct port_pre_exec_data) 1881da177e4SLinus Torvalds { .sock_fd = new, 1891da177e4SLinus Torvalds .pipe_fd = socket[1] }); 1901da177e4SLinus Torvalds 191*c4399016SJeff Dike err = run_helper(port_pre_exec, &data, argv); 1921da177e4SLinus Torvalds if(err < 0) 1931da177e4SLinus Torvalds goto out_shutdown; 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds *pid_out = err; 19667608e0cSJeff Dike return new; 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds out_shutdown: 1991da177e4SLinus Torvalds os_shutdown_socket(socket[0], 1, 1); 2001da177e4SLinus Torvalds os_close_file(socket[0]); 2011da177e4SLinus Torvalds os_shutdown_socket(socket[1], 1, 1); 2021da177e4SLinus Torvalds os_close_file(socket[1]); 2031da177e4SLinus Torvalds out_close: 2041da177e4SLinus Torvalds os_close_file(new); 20567608e0cSJeff Dike return err; 2061da177e4SLinus Torvalds } 207