xref: /OK3568_Linux_fs/kernel/arch/um/drivers/port_user.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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