2 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
3 * Licensed under the GPL
11 #include <netinet/in.h>
12 #include "chan_user.h"
13 #include "kern_constants.h"
16 #include "um_malloc.h"
23 char dev
[sizeof("32768\0")];
26 static void *port_init(char *str
, int device
, const struct chan_opts
*opts
)
28 struct port_chan
*data
;
34 printk(UM_KERN_ERR
"port_init : channel type 'port' must "
35 "specify a port number\n");
39 port
= strtoul(str
, &end
, 0);
40 if ((*end
!= '\0') || (end
== str
)) {
41 printk(UM_KERN_ERR
"port_init : couldn't parse port '%s'\n",
46 kern_data
= port_data(port
);
47 if (kern_data
== NULL
)
50 data
= uml_kmalloc(sizeof(*data
), UM_GFP_KERNEL
);
54 *data
= ((struct port_chan
) { .raw
= opts
->raw
,
55 .kernel_data
= kern_data
});
56 sprintf(data
->dev
, "%d", port
);
60 port_kern_free(kern_data
);
64 static void port_free(void *d
)
66 struct port_chan
*data
= d
;
68 port_kern_free(data
->kernel_data
);
72 static int port_open(int input
, int output
, int primary
, void *d
,
75 struct port_chan
*data
= d
;
78 fd
= port_wait(data
->kernel_data
);
79 if ((fd
>= 0) && data
->raw
) {
80 CATCH_EINTR(err
= tcgetattr(fd
, &data
->tt
));
92 static void port_close(int fd
, void *d
)
94 struct port_chan
*data
= d
;
96 port_remove_dev(data
->kernel_data
);
100 const struct chan_ops port_ops
= {
105 .read
= generic_read
,
106 .write
= generic_write
,
107 .console_write
= generic_console_write
,
108 .window_size
= generic_window_size
,
113 int port_listen_fd(int port
)
115 struct sockaddr_in addr
;
118 fd
= socket(PF_INET
, SOCK_STREAM
, 0);
123 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &arg
, sizeof(arg
)) < 0) {
128 addr
.sin_family
= AF_INET
;
129 addr
.sin_port
= htons(port
);
130 addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
131 if (bind(fd
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
136 if (listen(fd
, 1) < 0) {
141 err
= os_set_fd_block(fd
, 0);
151 struct port_pre_exec_data
{
156 static void port_pre_exec(void *arg
)
158 struct port_pre_exec_data
*data
= arg
;
160 dup2(data
->sock_fd
, 0);
161 dup2(data
->sock_fd
, 1);
162 dup2(data
->sock_fd
, 2);
163 close(data
->sock_fd
);
164 dup2(data
->pipe_fd
, 3);
165 shutdown(3, SHUT_RD
);
166 close(data
->pipe_fd
);
169 int port_connection(int fd
, int *socket
, int *pid_out
)
172 char *argv
[] = { "/usr/sbin/in.telnetd", "-L",
173 "/usr/lib/uml/port-helper", NULL
};
174 struct port_pre_exec_data data
;
176 new = accept(fd
, NULL
, 0);
180 err
= os_pipe(socket
, 0, 0);
184 data
= ((struct port_pre_exec_data
)
186 .pipe_fd
= socket
[1] });
188 err
= run_helper(port_pre_exec
, &data
, argv
);
196 shutdown(socket
[0], SHUT_RDWR
);
198 shutdown(socket
[1], SHUT_RDWR
);