2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
6 #include "linux/list.h"
7 #include "linux/sched.h"
8 #include "linux/slab.h"
9 #include "linux/interrupt.h"
10 #include "linux/irq.h"
11 #include "linux/spinlock.h"
12 #include "linux/errno.h"
13 #include "asm/semaphore.h"
14 #include "asm/errno.h"
15 #include "kern_util.h"
24 struct list_head list;
30 struct list_head pending;
31 struct list_head connections;
35 struct port_list *port;
41 struct list_head list;
46 struct port_list *port;
49 static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs)
51 struct connection *conn = data;
54 fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
59 printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n",
61 os_close_file(conn->fd);
64 list_del(&conn->list);
67 list_add(&conn->list, &conn->port->connections);
73 static int port_accept(struct port_list *port)
75 struct connection *conn;
76 int fd, socket[2], pid, ret = 0;
78 fd = port_connection(port->fd, socket, &pid);
81 printk(KERN_ERR "port_accept : port_connection "
82 "returned %d\n", -fd);
86 conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
88 printk(KERN_ERR "port_accept : failed to allocate "
92 *conn = ((struct connection)
93 { .list = LIST_HEAD_INIT(conn->list),
95 .socket = { socket[0], socket[1] },
99 if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt,
100 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
102 printk(KERN_ERR "port_accept : failed to get IRQ for "
107 list_add(&conn->list, &port->pending);
115 os_kill_process(pid, 1);
120 DECLARE_MUTEX(ports_sem);
121 struct list_head ports = LIST_HEAD_INIT(ports);
123 void port_work_proc(void *unused)
125 struct port_list *port;
126 struct list_head *ele;
129 local_irq_save(flags);
130 list_for_each(ele, &ports){
131 port = list_entry(ele, struct port_list, list);
132 if(!port->has_connection)
134 reactivate_fd(port->fd, ACCEPT_IRQ);
135 while(port_accept(port)) ;
136 port->has_connection = 0;
138 local_irq_restore(flags);
141 DECLARE_WORK(port_work, port_work_proc, NULL);
143 static irqreturn_t port_interrupt(int irq, void *data, struct pt_regs *regs)
145 struct port_list *port = data;
147 port->has_connection = 1;
148 schedule_work(&port_work);
152 void *port_data(int port_num)
154 struct list_head *ele;
155 struct port_list *port;
156 struct port_dev *dev = NULL;
160 list_for_each(ele, &ports){
161 port = list_entry(ele, struct port_list, list);
162 if(port->port == port_num) goto found;
164 port = kmalloc(sizeof(struct port_list), GFP_KERNEL);
166 printk(KERN_ERR "Allocation of port list failed\n");
170 fd = port_listen_fd(port_num);
172 printk(KERN_ERR "binding to port %d failed, errno = %d\n",
176 if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt,
177 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, "port",
179 printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num);
183 *port = ((struct port_list)
184 { .list = LIST_HEAD_INIT(port->list),
186 .sem = __SEMAPHORE_INITIALIZER(port->sem,
188 .lock = SPIN_LOCK_UNLOCKED,
191 .pending = LIST_HEAD_INIT(port->pending),
192 .connections = LIST_HEAD_INIT(port->connections) });
193 list_add(&port->list, &ports);
196 dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL);
198 printk(KERN_ERR "Allocation of port device entry failed\n");
202 *dev = ((struct port_dev) { .port = port,
204 .telnetd_pid = -1 });
216 int port_wait(void *data)
218 struct port_dev *dev = data;
219 struct connection *conn;
220 struct port_list *port = dev->port;
224 if(down_interruptible(&port->sem))
225 return(-ERESTARTSYS);
227 spin_lock(&port->lock);
229 conn = list_entry(port->connections.next, struct connection,
231 list_del(&conn->list);
232 spin_unlock(&port->lock);
234 os_shutdown_socket(conn->socket[0], 1, 1);
235 os_close_file(conn->socket[0]);
236 os_shutdown_socket(conn->socket[1], 1, 1);
237 os_close_file(conn->socket[1]);
239 /* This is done here because freeing an IRQ can't be done
240 * within the IRQ handler. So, pipe_interrupt always ups
241 * the semaphore regardless of whether it got a successful
242 * connection. Then we loop here throwing out failed
243 * connections until a good one is found.
245 free_irq_by_irq_and_dev(TELNETD_IRQ, conn);
246 free_irq(TELNETD_IRQ, conn);
248 if(conn->fd >= 0) break;
249 os_close_file(conn->fd);
254 dev->helper_pid = conn->helper_pid;
255 dev->telnetd_pid = conn->telnetd_pid;
261 void port_remove_dev(void *d)
263 struct port_dev *dev = d;
265 if(dev->helper_pid != -1)
266 os_kill_process(dev->helper_pid, 0);
267 if(dev->telnetd_pid != -1)
268 os_kill_process(dev->telnetd_pid, 1);
269 dev->helper_pid = -1;
270 dev->telnetd_pid = -1;
273 void port_kern_free(void *d)
275 struct port_dev *dev = d;
277 port_remove_dev(dev);
281 static void free_port(void)
283 struct list_head *ele;
284 struct port_list *port;
286 list_for_each(ele, &ports){
287 port = list_entry(ele, struct port_list, list);
288 free_irq_by_fd(port->fd);
289 os_close_file(port->fd);
293 __uml_exitcall(free_port);
296 * Overrides for Emacs so that we follow Linus's tabbing style.
297 * Emacs will notice this stuff at the end of the file and automatically
298 * adjust the settings for this buffer only. This must remain at the end
300 * ---------------------------------------------------------------------------
302 * c-file-style: "linux"