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