11da177e4SLinus Torvalds /* 2e99525f9SJeff Dike * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) 31da177e4SLinus Torvalds * Licensed under the GPL 41da177e4SLinus Torvalds */ 51da177e4SLinus Torvalds 61da177e4SLinus Torvalds #include <stdio.h> 71da177e4SLinus Torvalds #include <stdlib.h> 81da177e4SLinus Torvalds #include <errno.h> 91da177e4SLinus Torvalds #include <termios.h> 10e99525f9SJeff Dike #include <unistd.h> 111da177e4SLinus Torvalds #include <netinet/in.h> 121da177e4SLinus Torvalds #include "chan_user.h" 13e99525f9SJeff Dike #include "kern_constants.h" 141da177e4SLinus Torvalds #include "os.h" 15e99525f9SJeff Dike #include "port.h" 16c13e5690SPaolo 'Blaisorblade' Giarrusso #include "um_malloc.h" 17e99525f9SJeff Dike #include "user.h" 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds struct port_chan { 201da177e4SLinus Torvalds int raw; 211da177e4SLinus Torvalds struct termios tt; 221da177e4SLinus Torvalds void *kernel_data; 231da177e4SLinus Torvalds char dev[sizeof("32768\0")]; 241da177e4SLinus Torvalds }; 251da177e4SLinus Torvalds 265e7672ecSJeff Dike static void *port_init(char *str, int device, const struct chan_opts *opts) 271da177e4SLinus Torvalds { 281da177e4SLinus Torvalds struct port_chan *data; 291da177e4SLinus Torvalds void *kern_data; 301da177e4SLinus Torvalds char *end; 311da177e4SLinus Torvalds int port; 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds if (*str != ':') { 34e99525f9SJeff Dike printk(UM_KERN_ERR "port_init : channel type 'port' must " 35e99525f9SJeff Dike "specify a port number\n"); 3667608e0cSJeff Dike return NULL; 371da177e4SLinus Torvalds } 381da177e4SLinus Torvalds str++; 391da177e4SLinus Torvalds port = strtoul(str, &end, 0); 401da177e4SLinus Torvalds if ((*end != '\0') || (end == str)) { 41e99525f9SJeff Dike printk(UM_KERN_ERR "port_init : couldn't parse port '%s'\n", 42e99525f9SJeff Dike str); 4367608e0cSJeff Dike return NULL; 441da177e4SLinus Torvalds } 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds kern_data = port_data(port); 471da177e4SLinus Torvalds if (kern_data == NULL) 4867608e0cSJeff Dike return NULL; 491da177e4SLinus Torvalds 50*43f5b308SJeff Dike data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL); 511da177e4SLinus Torvalds if (data == NULL) 521da177e4SLinus Torvalds goto err; 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds *data = ((struct port_chan) { .raw = opts->raw, 551da177e4SLinus Torvalds .kernel_data = kern_data }); 561da177e4SLinus Torvalds sprintf(data->dev, "%d", port); 571da177e4SLinus Torvalds 5867608e0cSJeff Dike return data; 591da177e4SLinus Torvalds err: 601da177e4SLinus Torvalds port_kern_free(kern_data); 6167608e0cSJeff Dike return NULL; 621da177e4SLinus Torvalds } 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds static void port_free(void *d) 651da177e4SLinus Torvalds { 661da177e4SLinus Torvalds struct port_chan *data = d; 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds port_kern_free(data->kernel_data); 691da177e4SLinus Torvalds kfree(data); 701da177e4SLinus Torvalds } 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds static int port_open(int input, int output, int primary, void *d, 731da177e4SLinus Torvalds char **dev_out) 741da177e4SLinus Torvalds { 751da177e4SLinus Torvalds struct port_chan *data = d; 761da177e4SLinus Torvalds int fd, err; 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds fd = port_wait(data->kernel_data); 791da177e4SLinus Torvalds if ((fd >= 0) && data->raw) { 801da177e4SLinus Torvalds CATCH_EINTR(err = tcgetattr(fd, &data->tt)); 811da177e4SLinus Torvalds if (err) 8267608e0cSJeff Dike return err; 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds err = raw(fd); 851da177e4SLinus Torvalds if (err) 8667608e0cSJeff Dike return err; 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds *dev_out = data->dev; 8967608e0cSJeff Dike return fd; 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds static void port_close(int fd, void *d) 931da177e4SLinus Torvalds { 941da177e4SLinus Torvalds struct port_chan *data = d; 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds port_remove_dev(data->kernel_data); 971da177e4SLinus Torvalds os_close_file(fd); 981da177e4SLinus Torvalds } 991da177e4SLinus Torvalds 1005e7672ecSJeff Dike const struct chan_ops port_ops = { 1011da177e4SLinus Torvalds .type = "port", 1021da177e4SLinus Torvalds .init = port_init, 1031da177e4SLinus Torvalds .open = port_open, 1041da177e4SLinus Torvalds .close = port_close, 1051da177e4SLinus Torvalds .read = generic_read, 1061da177e4SLinus Torvalds .write = generic_write, 107fd9bc53bSPaolo 'Blaisorblade' Giarrusso .console_write = generic_console_write, 1081da177e4SLinus Torvalds .window_size = generic_window_size, 1091da177e4SLinus Torvalds .free = port_free, 1101da177e4SLinus Torvalds .winch = 1, 1111da177e4SLinus Torvalds }; 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds int port_listen_fd(int port) 1141da177e4SLinus Torvalds { 1151da177e4SLinus Torvalds struct sockaddr_in addr; 1161da177e4SLinus Torvalds int fd, err, arg; 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds fd = socket(PF_INET, SOCK_STREAM, 0); 1191da177e4SLinus Torvalds if (fd == -1) 12067608e0cSJeff Dike return -errno; 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds arg = 1; 1231da177e4SLinus Torvalds if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0) { 1241da177e4SLinus Torvalds err = -errno; 1251da177e4SLinus Torvalds goto out; 1261da177e4SLinus Torvalds } 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds addr.sin_family = AF_INET; 1291da177e4SLinus Torvalds addr.sin_port = htons(port); 1301da177e4SLinus Torvalds addr.sin_addr.s_addr = htonl(INADDR_ANY); 1311da177e4SLinus Torvalds if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 1321da177e4SLinus Torvalds err = -errno; 1331da177e4SLinus Torvalds goto out; 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds if (listen(fd, 1) < 0) { 1371da177e4SLinus Torvalds err = -errno; 1381da177e4SLinus Torvalds goto out; 1391da177e4SLinus Torvalds } 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds err = os_set_fd_block(fd, 0); 1421da177e4SLinus Torvalds if (err < 0) 1431da177e4SLinus Torvalds goto out; 1441da177e4SLinus Torvalds 14567608e0cSJeff Dike return fd; 1461da177e4SLinus Torvalds out: 147e99525f9SJeff Dike close(fd); 14867608e0cSJeff Dike return err; 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds struct port_pre_exec_data { 1521da177e4SLinus Torvalds int sock_fd; 1531da177e4SLinus Torvalds int pipe_fd; 1541da177e4SLinus Torvalds }; 1551da177e4SLinus Torvalds 1561605ec04SWANG Cong static void port_pre_exec(void *arg) 1571da177e4SLinus Torvalds { 1581da177e4SLinus Torvalds struct port_pre_exec_data *data = arg; 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds dup2(data->sock_fd, 0); 1611da177e4SLinus Torvalds dup2(data->sock_fd, 1); 1621da177e4SLinus Torvalds dup2(data->sock_fd, 2); 163e99525f9SJeff Dike close(data->sock_fd); 1641da177e4SLinus Torvalds dup2(data->pipe_fd, 3); 165e99525f9SJeff Dike shutdown(3, SHUT_RD); 166e99525f9SJeff Dike close(data->pipe_fd); 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds int port_connection(int fd, int *socket, int *pid_out) 1701da177e4SLinus Torvalds { 1711da177e4SLinus Torvalds int new, err; 1721da177e4SLinus Torvalds char *argv[] = { "/usr/sbin/in.telnetd", "-L", 1731da177e4SLinus Torvalds "/usr/lib/uml/port-helper", NULL }; 1741da177e4SLinus Torvalds struct port_pre_exec_data data; 1751da177e4SLinus Torvalds 176e99525f9SJeff Dike new = accept(fd, NULL, 0); 1771da177e4SLinus Torvalds if (new < 0) 178e99525f9SJeff Dike return -errno; 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds err = os_pipe(socket, 0, 0); 1811da177e4SLinus Torvalds if (err < 0) 1821da177e4SLinus Torvalds goto out_close; 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds data = ((struct port_pre_exec_data) 1851da177e4SLinus Torvalds { .sock_fd = new, 1861da177e4SLinus Torvalds .pipe_fd = socket[1] }); 1871da177e4SLinus Torvalds 188c4399016SJeff Dike err = run_helper(port_pre_exec, &data, argv); 1891da177e4SLinus Torvalds if (err < 0) 1901da177e4SLinus Torvalds goto out_shutdown; 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds *pid_out = err; 19367608e0cSJeff Dike return new; 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds out_shutdown: 196e99525f9SJeff Dike shutdown(socket[0], SHUT_RDWR); 197e99525f9SJeff Dike close(socket[0]); 198e99525f9SJeff Dike shutdown(socket[1], SHUT_RDWR); 199e99525f9SJeff Dike close(socket[1]); 2001da177e4SLinus Torvalds out_close: 201e99525f9SJeff Dike close(new); 20267608e0cSJeff Dike return err; 2031da177e4SLinus Torvalds } 204