Merge from vendor branch BINUTILS:
[dragonfly.git] / sys / dev / misc / streams / streams.c
1 /*
2  * Copyright (c) 1998 Mark Newton
3  * Copyright (c) 1994 Christos Zoulas
4  * Copyright (c) 1997 Todd Vierling
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The names of the authors may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * Stolen from NetBSD /sys/compat/svr4/svr4_net.c.  Pseudo-device driver
30  * skeleton produced from /usr/share/examples/drivers/make_pseudo_driver.sh
31  * in 3.0-980524-SNAP then hacked a bit (but probably not enough :-).
32  *
33  * $FreeBSD: src/sys/dev/streams/streams.c,v 1.16.2.1 2001/02/26 04:23:07 jlemon Exp $
34  * $DragonFly: src/sys/dev/misc/streams/Attic/streams.c,v 1.19 2005/07/13 01:38:54 dillon Exp $
35  */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>         /* SYSINIT stuff */
40 #include <sys/conf.h>           /* cdevsw stuff */
41 #include <sys/malloc.h>         /* malloc region definitions */
42 #include <sys/file.h>
43 #include <sys/filedesc.h>
44 #include <sys/kern_syscall.h>
45 #include <sys/nlookup.h>
46 #include <sys/unistd.h>
47 #include <sys/fcntl.h>
48 #include <sys/socket.h>
49 #include <sys/protosw.h>
50 #include <sys/socketvar.h>
51 #include <sys/un.h>
52 #include <sys/domain.h>
53 #include <net/if.h>
54 #include <netinet/in.h>
55 #include <sys/proc.h>
56 #include <sys/uio.h>
57
58 #include <sys/sysproto.h>
59
60 #include <emulation/svr4/svr4_types.h>
61 #include <emulation/svr4/svr4_util.h>
62 #include <emulation/svr4/svr4_signal.h>
63 #include <emulation/svr4/svr4_ioctl.h>
64 #include <emulation/svr4/svr4_stropts.h>
65 #include <emulation/svr4/svr4_socket.h>
66
67 static int svr4_soo_close (struct file *, struct thread *);
68 static int svr4_ptm_alloc (struct thread *);
69 static  d_open_t        streamsopen;
70
71 struct svr4_sockcache_entry {
72         struct thread *td;      /* Thread for the socket                */
73         void *cookie;           /* Internal cookie used for matching    */
74         struct sockaddr_un sock;/* Pathname for the socket              */
75         dev_t dev;              /* Device where the socket lives on     */
76         ino_t ino;              /* Inode where the socket lives on      */
77         TAILQ_ENTRY(svr4_sockcache_entry) entries;
78 };
79
80 TAILQ_HEAD(svr4_sockcache_head, svr4_sockcache_entry) svr4_head;
81
82 /* Initialization flag (set/queried by svr4_mod LKM) */
83 int svr4_str_initialized = 0;
84
85 /*
86  * Device minor numbers
87  */
88 enum {
89         dev_ptm                 = 10,
90         dev_arp                 = 26,
91         dev_icmp                = 27,
92         dev_ip                  = 28,
93         dev_tcp                 = 35,
94         dev_udp                 = 36,
95         dev_rawip               = 37,
96         dev_unix_dgram          = 38,
97         dev_unix_stream         = 39,
98         dev_unix_ord_stream     = 40
99 };
100
101 static struct fileops svr4_netops = {
102         NULL,   /* port */
103         NULL,   /* clone */
104         soo_read, soo_write, soo_ioctl, soo_poll, sokqfilter,
105         soo_stat, svr4_soo_close, soo_shutdown
106 };
107  
108 #define CDEV_MAJOR 103
109 static struct cdevsw streams_cdevsw = {
110         /* name */      "streams",
111         /* maj */       CDEV_MAJOR,
112         /* flags */     0,
113         /* port */      NULL,
114         /* clone */     NULL,
115
116         /* open */      streamsopen,
117         /* close */     noclose,
118         /* read */      noread,
119         /* write */     nowrite,
120         /* ioctl */     noioctl,
121         /* poll */      nopoll,
122         /* mmap */      nommap,
123         /* strategy */  nostrategy,
124         /* dump */      nodump,
125         /* psize */     nopsize
126 };
127  
128 struct streams_softc {
129         struct isa_device *dev;
130 } ;
131
132 #define UNIT(dev) minor(dev)    /* assume one minor number per unit */
133
134 typedef struct streams_softc *sc_p;
135
136 static  int
137 streams_modevent(module_t mod, int type, void *unused)
138 {
139         switch (type) {
140         case MOD_LOAD:
141                 /* XXX should make sure it isn't already loaded first */
142                 cdevsw_add(&streams_cdevsw, 0, 0);
143                 make_dev(&streams_cdevsw, dev_ptm, 0, 0, 0666, "ptm");
144                 make_dev(&streams_cdevsw, dev_arp, 0, 0, 0666, "arp");
145                 make_dev(&streams_cdevsw, dev_icmp, 0, 0, 0666, "icmp");
146                 make_dev(&streams_cdevsw, dev_ip, 0, 0, 0666, "ip");
147                 make_dev(&streams_cdevsw, dev_tcp, 0, 0, 0666, "tcp");
148                 make_dev(&streams_cdevsw, dev_udp, 0, 0, 0666, "udp");
149                 make_dev(&streams_cdevsw, dev_rawip, 0, 0, 0666, "rawip");
150                 make_dev(&streams_cdevsw, dev_unix_dgram, 0, 0, 0666, "ticlts");
151                 make_dev(&streams_cdevsw, dev_unix_stream, 
152                         0, 0, 0666, "ticots");
153                 make_dev(&streams_cdevsw, dev_unix_ord_stream, 
154                         0, 0, 0666, "ticotsord");
155                 return 0;
156         case MOD_UNLOAD:
157                 /* XXX should check to see if it's busy first */
158                 cdevsw_remove(&streams_cdevsw, 0, 0);
159
160                 return 0;
161         default:
162                 break;
163         }
164         return 0;
165 }
166
167 static moduledata_t streams_mod = {
168         "streams",
169         streams_modevent,
170         0
171 };
172 DECLARE_MODULE(streams, streams_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
173
174 /*
175  * We only need open() and close() routines.  open() calls socreate()
176  * to allocate a "real" object behind the stream and mallocs some state
177  * info for use by the svr4 emulator;  close() deallocates the state
178  * information and passes the underlying object to the normal socket close
179  * routine.
180  */
181 static  int
182 streamsopen(dev_t dev, int oflags, int devtype, d_thread_t *td)
183 {
184         struct proc *p = td->td_proc;
185         int type, protocol;
186         int fd;
187         struct file *fp;
188         struct socket *so;
189         int error;
190         int family;
191
192         KKASSERT(p != NULL);
193         
194         if (p->p_dupfd >= 0)
195           return ENODEV;
196
197         switch (minor(dev)) {
198         case dev_udp:
199           family = AF_INET;
200           type = SOCK_DGRAM;
201           protocol = IPPROTO_UDP;
202           break;
203
204         case dev_tcp:
205           family = AF_INET;
206           type = SOCK_STREAM;
207           protocol = IPPROTO_TCP;
208           break;
209
210         case dev_ip:
211         case dev_rawip:
212           family = AF_INET;
213           type = SOCK_RAW;
214           protocol = IPPROTO_IP;
215           break;
216
217         case dev_icmp:
218           family = AF_INET;
219           type = SOCK_RAW;
220           protocol = IPPROTO_ICMP;
221           break;
222
223         case dev_unix_dgram:
224           family = AF_LOCAL;
225           type = SOCK_DGRAM;
226           protocol = 0;
227           break;
228
229         case dev_unix_stream:
230         case dev_unix_ord_stream:
231           family = AF_LOCAL;
232           type = SOCK_STREAM;
233           protocol = 0;
234           break;
235
236         case dev_ptm:
237           return svr4_ptm_alloc(td);
238
239         default:
240           return EOPNOTSUPP;
241         }
242
243         if ((error = falloc(p, &fp, &fd)) != 0)
244           return error;
245
246         if ((error = socreate(family, &so, type, protocol, td)) != 0) {
247           if (p->p_fd->fd_files[fd].fp == fp) {
248               funsetfd(p->p_fd, fd);
249               fdrop(fp, td);
250           }
251           fdrop(fp, td);
252           return error;
253         }
254
255         fp->f_data = (caddr_t)so;
256         fp->f_flag = FREAD|FWRITE;
257         fp->f_ops = &svr4_netops;
258         fp->f_type = DTYPE_SOCKET;
259         (void)svr4_stream_get(fp);
260         fdrop(fp, td);
261         p->p_dupfd = fd;
262         return ENXIO;
263 }
264
265 static int
266 svr4_ptm_alloc(struct thread *td)
267 {
268         /*
269          * XXX this is very, very ugly.  But I can't find a better
270          * way that won't duplicate a big amount of code from
271          * sys_open().  Ho hum...
272          *
273          * Fortunately for us, Solaris (at least 2.5.1) makes the
274          * /dev/ptmx open automatically just open a pty, that (after
275          * STREAMS I_PUSHes), is just a plain pty.  fstat() is used
276          * to get the minor device number to map to a tty.
277          * 
278          * Cycle through the names. If sys_open() returns ENOENT (or
279          * ENXIO), short circuit the cycle and exit.
280          */
281         static char ptyname[] = "/dev/ptyXX";
282         static char ttyletters[] = "pqrstuwxyzPQRST";
283         static char ttynumbers[] = "0123456789abcdef";
284         struct proc *p = td->td_proc;
285         struct nlookupdata nd;
286         int error, fd, l = 0, n = 0;
287
288         KKASSERT(p);
289
290         for (;;) {
291                 ptyname[8] = ttyletters[l];
292                 ptyname[9] = ttynumbers[n];
293
294                 error = nlookup_init(&nd, ptyname, UIO_SYSSPACE, NLC_FOLLOW);
295                 if (error == 0)
296                         error = kern_open(&nd, O_RDWR, 0, &fd);
297                 nlookup_done(&nd);
298
299                 switch (error) {
300                 case ENOENT:
301                 case ENXIO:
302                         return error;
303                 case 0:
304                         p->p_dupfd = fd;
305                         return ENXIO;
306                 default:
307                         if (ttynumbers[++n] == '\0') {
308                                 if (ttyletters[++l] == '\0')
309                                         return(ENOENT);
310                                 n = 0;
311                         }
312                 }
313         }
314 }
315
316
317 struct svr4_strm *
318 svr4_stream_get(fp)
319         struct file *fp;
320 {
321         struct socket *so;
322         struct svr4_strm *st;
323
324         if (fp == NULL || fp->f_type != DTYPE_SOCKET)
325                 return NULL;
326
327         so = (struct socket *) fp->f_data;
328
329         if (so->so_emuldata)
330                 return so->so_emuldata;
331
332         /* Allocate a new one. */
333         st = malloc(sizeof(struct svr4_strm), M_TEMP, M_WAITOK);
334         st->s_family = so->so_proto->pr_domain->dom_family;
335         st->s_cmd = ~0;
336         st->s_afd = -1;
337         st->s_eventmask = 0;
338         so->so_emuldata = st;
339         fp->f_ops = &svr4_netops;
340
341         return st;
342 }
343
344 void
345 svr4_delete_socket(struct thread *td, struct file *fp)
346 {
347         struct svr4_sockcache_entry *e;
348         void *cookie = ((struct socket *) fp->f_data)->so_emuldata;
349
350         if (!svr4_str_initialized) {
351                 TAILQ_INIT(&svr4_head);
352                 svr4_str_initialized = 1;
353                 return;
354         }
355
356         TAILQ_FOREACH(e, &svr4_head, entries) {
357                 if (e->td == td && e->cookie == cookie) {
358                         TAILQ_REMOVE(&svr4_head, e, entries);
359                         DPRINTF(("svr4_delete_socket: %s [%p,%d,%d]\n",
360                                  e->sock.sun_path, td, (int)e->dev,
361                                  (int)e->ino));
362                         free(e, M_TEMP);
363                         return;
364                 }
365         }
366 }
367
368 static int
369 svr4_soo_close(struct file *fp, struct thread *td)
370 {
371         struct socket *so = (struct socket *)fp->f_data;
372         
373         /*      CHECKUNIT_DIAG(ENXIO);*/
374
375         svr4_delete_socket(td, fp);
376         free(so->so_emuldata, M_TEMP);
377         return soo_close(fp, td);
378         return (0);
379 }