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);
116 os_kill_process(pid, 1);
121 DECLARE_MUTEX(ports_sem);
122 struct list_head ports = LIST_HEAD_INIT(ports);
124 void port_work_proc(void *unused)
126 struct port_list *port;
127 struct list_head *ele;
130 local_irq_save(flags);
131 list_for_each(ele, &ports){
132 port = list_entry(ele, struct port_list, list);
133 if(!port->has_connection)
135 reactivate_fd(port->fd, ACCEPT_IRQ);
136 while(port_accept(port)) ;
137 port->has_connection = 0;
139 local_irq_restore(flags);
142 DECLARE_WORK(port_work, port_work_proc, NULL);
144 static irqreturn_t port_interrupt(int irq, void *data, struct pt_regs *regs)
146 struct port_list *port = data;
148 port->has_connection = 1;
149 schedule_work(&port_work);
153 void *port_data(int port_num)
155 struct list_head *ele;
156 struct port_list *port;
157 struct port_dev *dev = NULL;
161 list_for_each(ele, &ports){
162 port = list_entry(ele, struct port_list, list);
163 if(port->port == port_num) goto found;
165 port = kmalloc(sizeof(struct port_list), GFP_KERNEL);
167 printk(KERN_ERR "Allocation of port list failed\n");
171 fd = port_listen_fd(port_num);
173 printk(KERN_ERR "binding to port %d failed, errno = %d\n",
177 if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt,
178 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, "port",
180 printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num);
184 *port = ((struct port_list)
185 { .list = LIST_HEAD_INIT(port->list),
187 .sem = __SEMAPHORE_INITIALIZER(port->sem,
189 .lock = SPIN_LOCK_UNLOCKED,
192 .pending = LIST_HEAD_INIT(port->pending),
193 .connections = LIST_HEAD_INIT(port->connections) });
194 list_add(&port->list, &ports);
197 dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL);
199 printk(KERN_ERR "Allocation of port device entry failed\n");
203 *dev = ((struct port_dev) { .port = port,
205 .telnetd_pid = -1 });
217 int port_wait(void *data)
219 struct port_dev *dev = data;
220 struct connection *conn;
221 struct port_list *port = dev->port;
225 if(down_interruptible(&port->sem))
226 return(-ERESTARTSYS);
228 spin_lock(&port->lock);
230 conn = list_entry(port->connections.next, struct connection,
232 list_del(&conn->list);
233 spin_unlock(&port->lock);
235 os_shutdown_socket(conn->socket[0], 1, 1);
236 os_close_file(conn->socket[0]);
237 os_shutdown_socket(conn->socket[1], 1, 1);
238 os_close_file(conn->socket[1]);
240 /* This is done here because freeing an IRQ can't be done
241 * within the IRQ handler. So, pipe_interrupt always ups
242 * the semaphore regardless of whether it got a successful
243 * connection. Then we loop here throwing out failed
244 * connections until a good one is found.
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"