streams.c revision 43410
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
34
35#include "streams.h"		/* generated file.. defines NSTREAMS */
36#include "opt_devfs.h"
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/unistd.h>
45#include <sys/fcntl.h>
46#include <sys/socket.h>
47#include <sys/protosw.h>
48#include <sys/socketvar.h>
49#include <sys/un.h>
50#include <sys/domain.h>
51#include <net/if.h>
52#include <netinet/in.h>
53#include <sys/proc.h>
54#include <sys/uio.h>
55#ifdef DEVFS
56#include <sys/devfsext.h>	/* DEVFS defintitions */
57#endif /* DEVFS */
58
59#include <sys/sysproto.h>
60
61#include <svr4/svr4_types.h>
62#include <svr4/svr4_util.h>
63#include <svr4/svr4_signal.h>
64#include <svr4/svr4_ioctl.h>
65#include <svr4/svr4_stropts.h>
66#include <svr4/svr4_socket.h>
67
68static int svr4_soo_close __P((struct file *, struct proc *));
69static int svr4_ptm_alloc __P((struct proc *));
70static  d_open_t	streamsopen;
71
72struct svr4_sockcache_entry {
73	struct proc *p;		/* Process for the socket		*/
74	void *cookie;		/* Internal cookie used for matching	*/
75	struct sockaddr_un sock;/* Pathname for the socket		*/
76	dev_t dev;		/* Device where the socket lives on	*/
77	ino_t ino;		/* Inode where the socket lives on	*/
78	TAILQ_ENTRY(svr4_sockcache_entry) entries;
79};
80
81TAILQ_HEAD(svr4_sockcache_head, svr4_sockcache_entry) svr4_head;
82
83/* Initialization flag (set/queried by svr4_mod LKM) */
84int svr4_str_initialized = 0;
85
86/*
87 * Device minor numbers
88 */
89enum {
90	dev_ptm			= 10,
91	dev_arp			= 26,
92	dev_icmp		= 27,
93	dev_ip			= 28,
94	dev_tcp			= 35,
95	dev_udp			= 36,
96	dev_rawip		= 37,
97	dev_unix_dgram		= 38,
98	dev_unix_stream		= 39,
99	dev_unix_ord_stream	= 40
100};
101
102
103
104int soo_read __P((struct file *fp, struct uio *uio,
105		struct ucred *cred));
106int soo_write __P((struct file *fp, struct uio *uio,
107		struct ucred *cred));
108int soo_close __P((struct file *fp, struct proc *p));
109
110static struct fileops svr4_netops = {
111	soo_read, soo_write, soo_ioctl, soo_poll, svr4_soo_close
112};
113
114#define CDEV_MAJOR 103
115static struct cdevsw streams_cdevsw = {
116	streamsopen,
117	NULL,
118	NULL,
119	NULL,
120	NULL,
121	NULL,
122	NULL,
123	NULL,
124	NULL,
125	NULL,
126	NULL,
127	"streams",
128	NULL,
129	-1 };
130
131struct streams_softc {
132	struct isa_device *dev;
133#ifdef DEVFS
134  /*
135   * If this ever becomes an LKM we'll want this crud so we can deallocate
136   * devfs entries when the module is unloaded
137   */
138	void *devfs_ptm;
139        void *devfs_arp;
140        void *devfs_icmp;
141        void *devfs_ip;
142        void *devfs_tcp;
143        void *devfs_udp;
144        void *devfs_rawip;
145        void *devfs_unix_dgram;
146        void *devfs_unix_stream;
147        void *devfs_unix_ord_stream;
148#endif
149} ;
150
151#define UNIT(dev) minor(dev)	/* assume one minor number per unit */
152
153typedef	struct streams_softc *sc_p;
154
155static sc_p sca[NSTREAMS];
156
157/*
158 * We only need open() and close() routines.  open() calls socreate()
159 * to allocate a "real" object behind the stream and mallocs some state
160 * info for use by the svr4 emulator;  close() deallocates the state
161 * information and passes the underlying object to the normal socket close
162 * routine.
163 */
164static  int
165streamsopen(dev_t dev, int oflags, int devtype, struct proc *p)
166{
167	int type, protocol;
168	int fd;
169	struct file *fp;
170	struct socket *so;
171	int error;
172	int family;
173
174	if (p->p_dupfd >= 0)
175	  return ENODEV;
176
177	switch (minor(dev)) {
178	case dev_udp:
179	  family = AF_INET;
180	  type = SOCK_DGRAM;
181	  protocol = IPPROTO_UDP;
182	  break;
183
184	case dev_tcp:
185	  family = AF_INET;
186	  type = SOCK_STREAM;
187	  protocol = IPPROTO_TCP;
188	  break;
189
190	case dev_ip:
191	case dev_rawip:
192	  family = AF_INET;
193	  type = SOCK_RAW;
194	  protocol = IPPROTO_IP;
195	  break;
196
197	case dev_icmp:
198	  family = AF_INET;
199	  type = SOCK_RAW;
200	  protocol = IPPROTO_ICMP;
201	  break;
202
203	case dev_unix_dgram:
204	  family = AF_LOCAL;
205	  type = SOCK_DGRAM;
206	  protocol = 0;
207	  break;
208
209	case dev_unix_stream:
210	case dev_unix_ord_stream:
211	  family = AF_LOCAL;
212	  type = SOCK_STREAM;
213	  protocol = 0;
214	  break;
215
216	case dev_ptm:
217	  return svr4_ptm_alloc(p);
218
219	default:
220	  return EOPNOTSUPP;
221	}
222
223	if ((error = falloc(p, &fp, &fd)) != 0)
224	  return error;
225
226	if ((error = socreate(family, &so, type, protocol, p)) != 0) {
227	  p->p_fd->fd_ofiles[fd] = 0;
228	  ffree(fp);
229	  return error;
230	}
231
232	fp->f_flag = FREAD|FWRITE;
233	fp->f_type = DTYPE_SOCKET;
234	fp->f_ops = &svr4_netops;
235
236	fp->f_data = (caddr_t)so;
237	(void)svr4_stream_get(fp);
238	p->p_dupfd = fd;
239	return ENXIO;
240}
241
242static int
243svr4_ptm_alloc(p)
244	struct proc *p;
245{
246	/*
247	 * XXX this is very, very ugly.  But I can't find a better
248	 * way that won't duplicate a big amount of code from
249	 * sys_open().  Ho hum...
250	 *
251	 * Fortunately for us, Solaris (at least 2.5.1) makes the
252	 * /dev/ptmx open automatically just open a pty, that (after
253	 * STREAMS I_PUSHes), is just a plain pty.  fstat() is used
254	 * to get the minor device number to map to a tty.
255	 *
256	 * Cycle through the names. If sys_open() returns ENOENT (or
257	 * ENXIO), short circuit the cycle and exit.
258	 */
259	static char ptyname[] = "/dev/ptyXX";
260	static char ttyletters[] = "pqrstuwxyzPQRST";
261	static char ttynumbers[] = "0123456789abcdef";
262	caddr_t sg = stackgap_init();
263	char *path = stackgap_alloc(&sg, sizeof(ptyname));
264	struct open_args oa;
265	int l = 0, n = 0;
266	register_t fd = -1;
267	int error;
268
269	SCARG(&oa, path) = path;
270	SCARG(&oa, flags) = O_RDWR;
271	SCARG(&oa, mode) = 0;
272
273	while (fd == -1) {
274		ptyname[8] = ttyletters[l];
275		ptyname[9] = ttynumbers[n];
276
277		if ((error = copyout(ptyname, path, sizeof(ptyname))) != 0)
278			return error;
279
280		switch (error = open(p, &oa)) {
281		case ENOENT:
282		case ENXIO:
283			return error;
284		case 0:
285			p->p_dupfd = p->p_retval[0];
286			return ENXIO;
287		default:
288			if (ttynumbers[++n] == '\0') {
289				if (ttyletters[++l] == '\0')
290					break;
291				n = 0;
292			}
293		}
294	}
295	return ENOENT;
296}
297
298
299struct svr4_strm *
300svr4_stream_get(fp)
301	struct file *fp;
302{
303	struct socket *so;
304	struct svr4_strm *st;
305
306	if (fp == NULL || fp->f_type != DTYPE_SOCKET)
307		return NULL;
308
309	so = (struct socket *) fp->f_data;
310
311       	if (so->so_emuldata)
312		return so->so_emuldata;
313
314	/* Allocate a new one. */
315	fp->f_ops = &svr4_netops;
316	st = malloc(sizeof(struct svr4_strm), M_TEMP, M_WAITOK);
317	st->s_family = so->so_proto->pr_domain->dom_family;
318	st->s_cmd = ~0;
319	st->s_afd = -1;
320	st->s_eventmask = 0;
321	so->so_emuldata = st;
322
323	return st;
324}
325
326void
327svr4_delete_socket(p, fp)
328	struct proc *p;
329	struct file *fp;
330{
331	struct svr4_sockcache_entry *e;
332	void *cookie = ((struct socket *) fp->f_data)->so_emuldata;
333
334	if (!svr4_str_initialized) {
335		TAILQ_INIT(&svr4_head);
336		svr4_str_initialized = 1;
337		return;
338	}
339
340	for (e = svr4_head.tqh_first; e != NULL; e = e->entries.tqe_next)
341		if (e->p == p && e->cookie == cookie) {
342			TAILQ_REMOVE(&svr4_head, e, entries);
343			DPRINTF(("svr4_delete_socket: %s [%p,%d,%d]\n",
344				 e->sock.sun_path, p, e->dev, e->ino));
345			free(e, M_TEMP);
346			return;
347		}
348}
349
350static int
351svr4_soo_close(struct file *fp, struct proc *p)
352{
353        struct socket *so = (struct socket *)fp->f_data;
354
355	/*	CHECKUNIT_DIAG(ENXIO);*/
356
357	svr4_delete_socket(p, fp);
358	free(so->so_emuldata, M_TEMP);
359	return soo_close(fp, p);
360	return (0);
361}
362
363/*
364 * Now  for some driver initialisation.
365 * Occurs ONCE during boot (very early).
366 */
367static void
368streams_drvinit(void *unused)
369{
370        dev_t dev;
371	int	unit;
372	sc_p scp  = sca[unit];
373
374	dev = makedev(CDEV_MAJOR, 0);
375	cdevsw_add(&dev, &streams_cdevsw, NULL);
376	for (unit = 0; unit < NSTREAMS; unit++) {
377		/*
378		 * Allocate storage for this instance .
379		 */
380		scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT);
381		if( scp == NULL) {
382			printf("streams%d failed to allocate strorage\n", unit);
383			return ;
384		}
385		bzero(scp, sizeof(*scp));
386		sca[unit] = scp;
387#if DEVFS
388		/* XXX - This stuff is all completely bogus -- It's supposed
389		 * to show up in /compat/svr4/dev, but devfs will be mounted
390		 * on /dev, won't it?  Sigh.  CHECKALTEXIST() will mean
391		 * device opens will still work (and it will mitigate the
392		 * need to run SVR4_MAKEDEV in /compat/svr4/dev, or will
393		 * replace it with a script which creates symlinks to entities
394		 * in /dev, or something equally 'orrible), but it's
395		 * still a botch to put emulator-specific devices in the
396		 * "global" part of the filesystem tree (especially scumsucking
397		 * devices like these).  Good thing hardly anyone uses
398		 * devfs, right?
399		 */
400    		scp->devfs_ptm = devfs_add_devswf(&streams_cdevsw, dev_ptm, DV_CHR,
401	    		UID_ROOT, GID_KMEM, 0640, "ptmx", unit);
402    		scp->devfs_arp = devfs_add_devswf(&streams_cdevsw, dev_arp, DV_CHR,
403	    		UID_ROOT, GID_KMEM, 0666, "arp", unit);
404    		scp->devfs_icmp = devfs_add_devswf(&streams_cdevsw, dev_icmp, DV_CHR,
405	    		UID_ROOT, GID_KMEM, 0600, "icmp", unit);
406    		scp->devfs_ip = devfs_add_devswf(&streams_cdevsw, dev_ip, DV_CHR,
407	    		UID_ROOT, GID_KMEM, 0600, "ip", unit);
408    		scp->devfs_tcp = devfs_add_devswf(&streams_cdevsw, dev_tcp, DV_CHR,
409	    		UID_ROOT, GID_KMEM, 0666, "tcp", unit);
410    		scp->devfs_udp = devfs_add_devswf(&streams_cdevsw, dev_udp, DV_CHR,
411	    		UID_ROOT, GID_KMEM, 0666, "udp", unit);
412    		scp->devfs_rawip = devfs_add_devswf(&streams_cdevsw, dev_rawip, DV_CHR,
413	    		UID_ROOT, GID_KMEM, 0600, "rawip", unit);
414    		scp->devfs_unix_dgram = devfs_add_devswf(&streams_cdevsw, dev_unix_dgram, DV_CHR,
415	    		UID_ROOT, GID_KMEM, 0666, "ticlts", unit);
416    		scp->devfs_unix_stream = devfs_add_devswf(&streams_cdevsw, dev_unix_stream, DV_CHR,
417	    		UID_ROOT, GID_KMEM, 0666, "ticots", unit);
418    		scp->devfs_unix_ord_stream = devfs_add_devswf(&streams_cdevsw, dev_unix_ord_stream, DV_CHR,
419	    		UID_ROOT, GID_KMEM, 0666, "ticotsord", unit);
420#endif
421	}
422}
423
424SYSINIT(streamsdev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR,
425		streams_drvinit, NULL)
426
427
428