1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
11 #include <netinet/in.h>
12 #include "chan_user.h"
15 #include <um_malloc.h>
21 char dev
[sizeof("32768\0")];
24 static void *port_init(char *str
, int device
, const struct chan_opts
*opts
)
26 struct port_chan
*data
;
32 printk(UM_KERN_ERR
"port_init : channel type 'port' must "
33 "specify a port number\n");
37 port
= strtoul(str
, &end
, 0);
38 if ((*end
!= '\0') || (end
== str
)) {
39 printk(UM_KERN_ERR
"port_init : couldn't parse port '%s'\n",
44 kern_data
= port_data(port
);
45 if (kern_data
== NULL
)
48 data
= uml_kmalloc(sizeof(*data
), UM_GFP_KERNEL
);
52 *data
= ((struct port_chan
) { .raw
= opts
->raw
,
53 .kernel_data
= kern_data
});
54 sprintf(data
->dev
, "%d", port
);
58 port_kern_free(kern_data
);
62 static void port_free(void *d
)
64 struct port_chan
*data
= d
;
66 port_kern_free(data
->kernel_data
);
70 static int port_open(int input
, int output
, int primary
, void *d
,
73 struct port_chan
*data
= d
;
76 fd
= port_wait(data
->kernel_data
);
77 if ((fd
>= 0) && data
->raw
) {
78 CATCH_EINTR(err
= tcgetattr(fd
, &data
->tt
));
90 static void port_close(int fd
, void *d
)
92 struct port_chan
*data
= d
;
94 port_remove_dev(data
->kernel_data
);
98 const struct chan_ops port_ops
= {
103 .read
= generic_read
,
104 .write
= generic_write
,
105 .console_write
= generic_console_write
,
106 .window_size
= generic_window_size
,
111 int port_listen_fd(int port
)
113 struct sockaddr_in addr
;
116 fd
= socket(PF_INET
, SOCK_STREAM
, 0);
121 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &arg
, sizeof(arg
)) < 0) {
126 addr
.sin_family
= AF_INET
;
127 addr
.sin_port
= htons(port
);
128 addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
129 if (bind(fd
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
134 if (listen(fd
, 1) < 0) {
139 err
= os_set_fd_block(fd
, 0);
149 struct port_pre_exec_data
{
154 static void port_pre_exec(void *arg
)
156 struct port_pre_exec_data
*data
= arg
;
158 dup2(data
->sock_fd
, 0);
159 dup2(data
->sock_fd
, 1);
160 dup2(data
->sock_fd
, 2);
161 close(data
->sock_fd
);
162 dup2(data
->pipe_fd
, 3);
163 shutdown(3, SHUT_RD
);
164 close(data
->pipe_fd
);
167 int port_connection(int fd
, int *socket
, int *pid_out
)
170 char *argv
[] = { "/usr/sbin/in.telnetd", "-L",
171 OS_LIB_PATH
"/uml/port-helper", NULL
};
172 struct port_pre_exec_data data
;
174 new = accept(fd
, NULL
, 0);
178 err
= os_pipe(socket
, 0, 0);
182 data
= ((struct port_pre_exec_data
)
184 .pipe_fd
= socket
[1] });
186 err
= run_helper(port_pre_exec
, &data
, argv
);
194 shutdown(socket
[0], SHUT_RDWR
);
196 shutdown(socket
[1], SHUT_RDWR
);