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