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"
10 #include "linux/spinlock.h"
11 #include "linux/errno.h"
12 #include "asm/semaphore.h"
13 #include "asm/errno.h"
14 #include "kern_util.h"
22 struct list_head list;
28 struct list_head pending;
29 struct list_head connections;
33 struct port_list *port;
39 struct list_head list;
44 struct port_list *port;
47 static void pipe_interrupt(int irq, void *data, struct pt_regs *regs)
49 struct connection *conn = data;
52 fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
57 printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n",
59 os_close_file(conn->fd);
62 list_del(&conn->list);
65 list_add(&conn->list, &conn->port->connections);
70 static int port_accept(struct port_list *port)
72 struct connection *conn;
73 int fd, socket[2], pid, ret = 0;
75 fd = port_connection(port->fd, socket, &pid);
78 printk(KERN_ERR "port_accept : port_connection "
79 "returned %d\n", -fd);
83 conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
85 printk(KERN_ERR "port_accept : failed to allocate "
89 *conn = ((struct connection)
90 { .list = LIST_HEAD_INIT(conn->list),
92 .socket = { socket[0], socket[1] },
96 if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt,
97 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
99 printk(KERN_ERR "port_accept : failed to get IRQ for "
104 list_add(&conn->list, &port->pending);
113 os_kill_process(pid, 1);
118 DECLARE_MUTEX(ports_sem);
119 struct list_head ports = LIST_HEAD_INIT(ports);
121 void port_work_proc(void *unused)
123 struct port_list *port;
124 struct list_head *ele;
127 local_irq_save(flags);
128 list_for_each(ele, &ports){
129 port = list_entry(ele, struct port_list, list);
130 if(!port->has_connection)
132 reactivate_fd(port->fd, ACCEPT_IRQ);
133 while(port_accept(port)) ;
134 port->has_connection = 0;
136 local_irq_restore(flags);
139 DECLARE_WORK(port_work, port_work_proc, NULL);
141 static void port_interrupt(int irq, void *data, struct pt_regs *regs)
143 struct port_list *port = data;
145 port->has_connection = 1;
146 schedule_work(&port_work);
149 void *port_data(int port_num)
151 struct list_head *ele;
152 struct port_list *port;
153 struct port_dev *dev = NULL;
157 list_for_each(ele, &ports){
158 port = list_entry(ele, struct port_list, list);
159 if(port->port == port_num) goto found;
161 port = kmalloc(sizeof(struct port_list), GFP_KERNEL);
163 printk(KERN_ERR "Allocation of port list failed\n");
167 fd = port_listen_fd(port_num);
169 printk(KERN_ERR "binding to port %d failed, errno = %d\n",
173 if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt,
174 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, "port",
176 printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num);
180 *port = ((struct port_list)
181 { .list = LIST_HEAD_INIT(port->list),
183 .sem = __SEMAPHORE_INITIALIZER(port->sem,
185 .lock = SPIN_LOCK_UNLOCKED,
188 .pending = LIST_HEAD_INIT(port->pending),
189 .connections = LIST_HEAD_INIT(port->connections) });
190 list_add(&port->list, &ports);
193 dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL);
195 printk(KERN_ERR "Allocation of port device entry failed\n");
199 *dev = ((struct port_dev) { .port = port,
201 .telnetd_pid = -1 });
213 int port_wait(void *data)
215 struct port_dev *dev = data;
216 struct connection *conn;
217 struct port_list *port = dev->port;
221 if(down_interruptible(&port->sem))
222 return(-ERESTARTSYS);
224 spin_lock(&port->lock);
226 conn = list_entry(port->connections.next, struct connection,
228 list_del(&conn->list);
229 spin_unlock(&port->lock);
231 os_shutdown_socket(conn->socket[0], 1, 1);
232 os_close_file(conn->socket[0]);
233 os_shutdown_socket(conn->socket[1], 1, 1);
234 os_close_file(conn->socket[1]);
236 /* This is done here because freeing an IRQ can't be done
237 * within the IRQ handler. So, pipe_interrupt always ups
238 * the semaphore regardless of whether it got a successful
239 * connection. Then we loop here throwing out failed
240 * connections until a good one is found.
242 free_irq(TELNETD_IRQ, conn);
244 if(conn->fd >= 0) break;
245 os_close_file(conn->fd);
250 dev->helper_pid = conn->helper_pid;
251 dev->telnetd_pid = conn->telnetd_pid;
257 void port_remove_dev(void *d)
259 struct port_dev *dev = d;
261 if(dev->helper_pid != -1)
262 os_kill_process(dev->helper_pid, 0);
263 if(dev->telnetd_pid != -1)
264 os_kill_process(dev->telnetd_pid, 1);
265 dev->helper_pid = -1;
266 dev->telnetd_pid = -1;
269 void port_kern_free(void *d)
271 struct port_dev *dev = d;
273 port_remove_dev(dev);
277 static void free_port(void)
279 struct list_head *ele;
280 struct port_list *port;
282 list_for_each(ele, &ports){
283 port = list_entry(ele, struct port_list, list);
284 free_irq_by_fd(port->fd);
285 os_close_file(port->fd);
289 __uml_exitcall(free_port);
292 * Overrides for Emacs so that we follow Linus's tabbing style.
293 * Emacs will notice this stuff at the end of the file and automatically
294 * adjust the settings for this buffer only. This must remain at the end
296 * ---------------------------------------------------------------------------
298 * c-file-style: "linux"