Consolidate the file descriptor destruction code used when a newly created
[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.25 2006/05/19 05:15:33 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 *);
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         struct lwp *lp = td->td_lwp;
186         int type, protocol;
187         int fd;
188         struct file *fp;
189         struct socket *so;
190         int error;
191         int family;
192
193         KKASSERT(p != NULL);
194         
195         if (lp->lwp_dupfd >= 0)
196           return ENODEV;
197
198         switch (minor(dev)) {
199         case dev_udp:
200           family = AF_INET;
201           type = SOCK_DGRAM;
202           protocol = IPPROTO_UDP;
203           break;
204
205         case dev_tcp:
206           family = AF_INET;
207           type = SOCK_STREAM;
208           protocol = IPPROTO_TCP;
209           break;
210
211         case dev_ip:
212         case dev_rawip:
213           family = AF_INET;
214           type = SOCK_RAW;
215           protocol = IPPROTO_IP;
216           break;
217
218         case dev_icmp:
219           family = AF_INET;
220           type = SOCK_RAW;
221           protocol = IPPROTO_ICMP;
222           break;
223
224         case dev_unix_dgram:
225           family = AF_LOCAL;
226           type = SOCK_DGRAM;
227           protocol = 0;
228           break;
229
230         case dev_unix_stream:
231         case dev_unix_ord_stream:
232           family = AF_LOCAL;
233           type = SOCK_STREAM;
234           protocol = 0;
235           break;
236
237         case dev_ptm:
238           return svr4_ptm_alloc(td);
239
240         default:
241           return EOPNOTSUPP;
242         }
243
244         if ((error = falloc(p, &fp, &fd)) != 0)
245           return error;
246
247         if ((error = socreate(family, &so, type, protocol, td)) != 0) {
248           fdealloc(p, fp, fd);
249           fdrop(fp);
250           return error;
251         }
252
253         fp->f_type = DTYPE_SOCKET;
254         fp->f_flag = FREAD|FWRITE;
255         fp->f_ops = &svr4_netops;
256         fp->f_data = so;
257         (void)svr4_stream_get(fp);
258         fdrop(fp);
259         lp->lwp_dupfd = fd;
260         return ENXIO;
261 }
262
263 static int
264 svr4_ptm_alloc(struct thread *td)
265 {
266         /*
267          * XXX this is very, very ugly.  But I can't find a better
268          * way that won't duplicate a big amount of code from
269          * sys_open().  Ho hum...
270          *
271          * Fortunately for us, Solaris (at least 2.5.1) makes the
272          * /dev/ptmx open automatically just open a pty, that (after
273          * STREAMS I_PUSHes), is just a plain pty.  fstat() is used
274          * to get the minor device number to map to a tty.
275          * 
276          * Cycle through the names. If sys_open() returns ENOENT (or
277          * ENXIO), short circuit the cycle and exit.
278          */
279         static char ptyname[] = "/dev/ptyXX";
280         static char ttyletters[] = "pqrstuwxyzPQRST";
281         static char ttynumbers[] = "0123456789abcdef";
282         struct lwp *lp = td->td_lwp;
283         struct nlookupdata nd;
284         int error, fd, l = 0, n = 0;
285
286         KKASSERT(lp);
287
288         for (;;) {
289                 ptyname[8] = ttyletters[l];
290                 ptyname[9] = ttynumbers[n];
291
292                 error = nlookup_init(&nd, ptyname, UIO_SYSSPACE, NLC_FOLLOW);
293                 if (error == 0)
294                         error = kern_open(&nd, O_RDWR, 0, &fd);
295                 nlookup_done(&nd);
296
297                 switch (error) {
298                 case ENOENT:
299                 case ENXIO:
300                         return error;
301                 case 0:
302                         lp->lwp_dupfd = fd;
303                         return ENXIO;
304                 default:
305                         if (ttynumbers[++n] == '\0') {
306                                 if (ttyletters[++l] == '\0')
307                                         return(ENOENT);
308                                 n = 0;
309                         }
310                 }
311         }
312 }
313
314
315 struct svr4_strm *
316 svr4_stream_get(struct file *fp)
317 {
318         struct socket *so;
319         struct svr4_strm *st;
320
321         if (fp == NULL || fp->f_type != DTYPE_SOCKET)
322                 return NULL;
323
324         so = (struct socket *) fp->f_data;
325
326         if (so->so_emuldata)
327                 return so->so_emuldata;
328
329         /* Allocate a new one. */
330         st = malloc(sizeof(struct svr4_strm), M_TEMP, M_WAITOK);
331         st->s_family = so->so_proto->pr_domain->dom_family;
332         st->s_cmd = ~0;
333         st->s_afd = -1;
334         st->s_eventmask = 0;
335         so->so_emuldata = st;
336         fp->f_ops = &svr4_netops;
337
338         return st;
339 }
340
341 void
342 svr4_delete_socket(struct thread *td, struct file *fp)
343 {
344         struct svr4_sockcache_entry *e;
345         void *cookie = ((struct socket *) fp->f_data)->so_emuldata;
346
347         if (!svr4_str_initialized) {
348                 TAILQ_INIT(&svr4_head);
349                 svr4_str_initialized = 1;
350                 return;
351         }
352
353         TAILQ_FOREACH(e, &svr4_head, entries) {
354                 if (e->td == td && e->cookie == cookie) {
355                         TAILQ_REMOVE(&svr4_head, e, entries);
356                         DPRINTF(("svr4_delete_socket: %s [%p,%d,%d]\n",
357                                  e->sock.sun_path, td, (int)e->dev,
358                                  (int)e->ino));
359                         free(e, M_TEMP);
360                         return;
361                 }
362         }
363 }
364
365 static int
366 svr4_soo_close(struct file *fp)
367 {
368         struct socket *so = (struct socket *)fp->f_data;
369         
370         /*      CHECKUNIT_DIAG(ENXIO);*/
371
372         svr4_delete_socket(curthread, fp);      /* XXX curthread */
373         free(so->so_emuldata, M_TEMP);
374         return (soo_close(fp));
375 }