1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/list.h"
7#include "linux/sched.h"
8#include "linux/slab.h"
9#include "linux/interrupt.h"
10#include "linux/spinlock.h"
11#include "linux/errno.h"
12#include "asm/atomic.h"
13#include "asm/semaphore.h"
14#include "asm/errno.h"
15#include "kern_util.h"
16#include "kern.h"
17#include "irq_user.h"
18#include "irq_kern.h"
19#include "port.h"
20#include "init.h"
21#include "os.h"
22
23struct port_list {
24	struct list_head list;
25	atomic_t wait_count;
26	int has_connection;
27	struct completion done;
28	int port;
29	int fd;
30	spinlock_t lock;
31	struct list_head pending;
32	struct list_head connections;
33};
34
35struct port_dev {
36	struct port_list *port;
37	int helper_pid;
38	int telnetd_pid;
39};
40
41struct connection {
42	struct list_head list;
43	int fd;
44	int helper_pid;
45	int socket[2];
46	int telnetd_pid;
47	struct port_list *port;
48};
49
50static irqreturn_t pipe_interrupt(int irq, void *data)
51{
52	struct connection *conn = data;
53	int fd;
54
55	fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
56	if(fd < 0){
57		if(fd == -EAGAIN)
58			return IRQ_NONE;
59
60		printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n",
61		       -fd);
62		os_close_file(conn->fd);
63	}
64
65	list_del(&conn->list);
66
67	conn->fd = fd;
68	list_add(&conn->list, &conn->port->connections);
69
70	complete(&conn->port->done);
71	return IRQ_HANDLED;
72}
73
74#define NO_WAITER_MSG \
75    "****\n" \
76    "There are currently no UML consoles waiting for port connections.\n" \
77    "Either disconnect from one to make it available or activate some more\n" \
78    "by enabling more consoles in the UML /etc/inittab.\n" \
79    "****\n"
80
81static int port_accept(struct port_list *port)
82{
83	struct connection *conn;
84	int fd, socket[2], pid, ret = 0;
85
86	fd = port_connection(port->fd, socket, &pid);
87	if(fd < 0){
88		if(fd != -EAGAIN)
89			printk(KERN_ERR "port_accept : port_connection "
90			       "returned %d\n", -fd);
91		goto out;
92	}
93
94	conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
95	if(conn == NULL){
96		printk(KERN_ERR "port_accept : failed to allocate "
97		       "connection\n");
98		goto out_close;
99	}
100	*conn = ((struct connection)
101		{ .list 	= LIST_HEAD_INIT(conn->list),
102		  .fd 		= fd,
103		  .socket  	= { socket[0], socket[1] },
104		  .telnetd_pid 	= pid,
105		  .port 	= port });
106
107	if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt,
108			  IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
109			  "telnetd", conn)){
110		printk(KERN_ERR "port_accept : failed to get IRQ for "
111		       "telnetd\n");
112		goto out_free;
113	}
114
115	if(atomic_read(&port->wait_count) == 0){
116		os_write_file(fd, NO_WAITER_MSG, sizeof(NO_WAITER_MSG));
117		printk("No one waiting for port\n");
118	}
119	list_add(&conn->list, &port->pending);
120	return 1;
121
122 out_free:
123	kfree(conn);
124 out_close:
125	os_close_file(fd);
126	if(pid != -1)
127		os_kill_process(pid, 1);
128 out:
129	return ret;
130}
131
132static DECLARE_MUTEX(ports_sem);
133static LIST_HEAD(ports);
134
135void port_work_proc(struct work_struct *unused)
136{
137	struct port_list *port;
138	struct list_head *ele;
139	unsigned long flags;
140
141	local_irq_save(flags);
142	list_for_each(ele, &ports){
143		port = list_entry(ele, struct port_list, list);
144		if(!port->has_connection)
145			continue;
146		reactivate_fd(port->fd, ACCEPT_IRQ);
147		while(port_accept(port)) ;
148		port->has_connection = 0;
149	}
150	local_irq_restore(flags);
151}
152
153DECLARE_WORK(port_work, port_work_proc);
154
155static irqreturn_t port_interrupt(int irq, void *data)
156{
157	struct port_list *port = data;
158
159	port->has_connection = 1;
160	schedule_work(&port_work);
161	return IRQ_HANDLED;
162}
163
164void *port_data(int port_num)
165{
166	struct list_head *ele;
167	struct port_list *port;
168	struct port_dev *dev = NULL;
169	int fd;
170
171	down(&ports_sem);
172	list_for_each(ele, &ports){
173		port = list_entry(ele, struct port_list, list);
174		if(port->port == port_num) goto found;
175	}
176	port = kmalloc(sizeof(struct port_list), GFP_KERNEL);
177	if(port == NULL){
178		printk(KERN_ERR "Allocation of port list failed\n");
179		goto out;
180	}
181
182	fd = port_listen_fd(port_num);
183	if(fd < 0){
184		printk(KERN_ERR "binding to port %d failed, errno = %d\n",
185		       port_num, -fd);
186		goto out_free;
187	}
188	if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt,
189			  IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
190			  "port", port)){
191		printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num);
192		goto out_close;
193	}
194
195	*port = ((struct port_list)
196		{ .list 	 	= LIST_HEAD_INIT(port->list),
197		  .wait_count		= ATOMIC_INIT(0),
198		  .has_connection 	= 0,
199		  .port 	 	= port_num,
200		  .fd  			= fd,
201		  .pending 		= LIST_HEAD_INIT(port->pending),
202		  .connections 		= LIST_HEAD_INIT(port->connections) });
203	spin_lock_init(&port->lock);
204	init_completion(&port->done);
205	list_add(&port->list, &ports);
206
207 found:
208	dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL);
209	if(dev == NULL){
210		printk(KERN_ERR "Allocation of port device entry failed\n");
211		goto out;
212	}
213
214	*dev = ((struct port_dev) { .port  		= port,
215				    .helper_pid  	= -1,
216				    .telnetd_pid  	= -1 });
217	goto out;
218
219 out_free:
220	kfree(port);
221 out_close:
222	os_close_file(fd);
223 out:
224	up(&ports_sem);
225	return dev;
226}
227
228int port_wait(void *data)
229{
230	struct port_dev *dev = data;
231	struct connection *conn;
232	struct port_list *port = dev->port;
233	int fd;
234
235	atomic_inc(&port->wait_count);
236	while(1){
237		fd = -ERESTARTSYS;
238		if(wait_for_completion_interruptible(&port->done))
239			goto out;
240
241		spin_lock(&port->lock);
242
243		conn = list_entry(port->connections.next, struct connection,
244				  list);
245		list_del(&conn->list);
246		spin_unlock(&port->lock);
247
248		os_shutdown_socket(conn->socket[0], 1, 1);
249		os_close_file(conn->socket[0]);
250		os_shutdown_socket(conn->socket[1], 1, 1);
251		os_close_file(conn->socket[1]);
252
253		/* This is done here because freeing an IRQ can't be done
254		 * within the IRQ handler.  So, pipe_interrupt always ups
255		 * the semaphore regardless of whether it got a successful
256		 * connection.  Then we loop here throwing out failed
257		 * connections until a good one is found.
258		 */
259		free_irq(TELNETD_IRQ, conn);
260
261		if(conn->fd >= 0) break;
262		os_close_file(conn->fd);
263		kfree(conn);
264	}
265
266	fd = conn->fd;
267	dev->helper_pid = conn->helper_pid;
268	dev->telnetd_pid = conn->telnetd_pid;
269	kfree(conn);
270 out:
271	atomic_dec(&port->wait_count);
272	return fd;
273}
274
275void port_remove_dev(void *d)
276{
277	struct port_dev *dev = d;
278
279	if(dev->helper_pid != -1)
280		os_kill_process(dev->helper_pid, 0);
281	if(dev->telnetd_pid != -1)
282		os_kill_process(dev->telnetd_pid, 1);
283	dev->helper_pid = -1;
284	dev->telnetd_pid = -1;
285}
286
287void port_kern_free(void *d)
288{
289	struct port_dev *dev = d;
290
291	port_remove_dev(dev);
292	kfree(dev);
293}
294
295static void free_port(void)
296{
297	struct list_head *ele;
298	struct port_list *port;
299
300	list_for_each(ele, &ports){
301		port = list_entry(ele, struct port_list, list);
302		free_irq_by_fd(port->fd);
303		os_close_file(port->fd);
304	}
305}
306
307__uml_exitcall(free_port);
308