streams.c revision 49413
1105760Srwatson/*
2105760Srwatson * Copyright (c) 1998 Mark Newton
3105760Srwatson * Copyright (c) 1994 Christos Zoulas
4105760Srwatson * Copyright (c) 1997 Todd Vierling
5105760Srwatson * All rights reserved.
6105760Srwatson *
7105760Srwatson * Redistribution and use in source and binary forms, with or without
8105760Srwatson * modification, are permitted provided that the following conditions
9105760Srwatson * are met:
10105760Srwatson * 1. Redistributions of source code must retain the above copyright
11105760Srwatson *    notice, this list of conditions and the following disclaimer.
12105760Srwatson * 2. Redistributions in binary form must reproduce the above copyright
13105760Srwatson *    notice, this list of conditions and the following disclaimer in the
14105760Srwatson *    documentation and/or other materials provided with the distribution.
15105760Srwatson * 3. The names of the authors may not be used to endorse or promote products
16105760Srwatson *    derived from this software without specific prior written permission
17105760Srwatson *
18105760Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19105760Srwatson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20105760Srwatson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21105760Srwatson * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22105760Srwatson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23105760Srwatson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24105760Srwatson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25105760Srwatson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26105760Srwatson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27105760Srwatson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28105760Srwatson *
29105760Srwatson * Stolen from NetBSD /sys/compat/svr4/svr4_net.c.  Pseudo-device driver
30105760Srwatson * skeleton produced from /usr/share/examples/drivers/make_pseudo_driver.sh
31105760Srwatson * in 3.0-980524-SNAP then hacked a bit (but probably not enough :-).
32105760Srwatson *
33105760Srwatson * $Id: streams.c,v 1.8 1999/08/01 12:51:06 newton Exp $
34105760Srwatson */
35105760Srwatson
36105760Srwatson#include "streams.h"		/* generated file.. defines NSTREAMS */
37105760Srwatson#include "opt_devfs.h"
38105760Srwatson#include <sys/param.h>
39105760Srwatson#include <sys/systm.h>
40105760Srwatson#include <sys/kernel.h>		/* SYSINIT stuff */
41105760Srwatson#include <sys/conf.h>		/* cdevsw stuff */
42105760Srwatson#include <sys/malloc.h>		/* malloc region definitions */
43105760Srwatson#include <sys/file.h>
44105760Srwatson#include <sys/filedesc.h>
45105760Srwatson#include <sys/unistd.h>
46105760Srwatson#include <sys/fcntl.h>
47105760Srwatson#include <sys/socket.h>
48105760Srwatson#include <sys/protosw.h>
49105760Srwatson#include <sys/socketvar.h>
50105760Srwatson#include <sys/un.h>
51105760Srwatson#include <sys/domain.h>
52105760Srwatson#include <net/if.h>
53105760Srwatson#include <netinet/in.h>
54105760Srwatson#include <sys/proc.h>
55105760Srwatson#include <sys/uio.h>
56105760Srwatson#ifdef DEVFS
57105760Srwatson#include <sys/devfsext.h>	/* DEVFS defintitions */
58105760Srwatson#endif /* DEVFS */
59105760Srwatson
60105760Srwatson#include <sys/sysproto.h>
61105760Srwatson
62105760Srwatson#include <svr4/svr4_types.h>
63105760Srwatson#include <svr4/svr4_util.h>
64105760Srwatson#include <svr4/svr4_signal.h>
65105760Srwatson#include <svr4/svr4_ioctl.h>
66105760Srwatson#include <svr4/svr4_stropts.h>
67105760Srwatson#include <svr4/svr4_socket.h>
68105760Srwatson
69105760Srwatsonstatic int svr4_soo_close __P((struct file *, struct proc *));
70105760Srwatsonstatic int svr4_ptm_alloc __P((struct proc *));
71105760Srwatsonstatic  d_open_t	streamsopen;
72105760Srwatson
73105760Srwatsonstruct svr4_sockcache_entry {
74105760Srwatson	struct proc *p;		/* Process for the socket		*/
75105760Srwatson	void *cookie;		/* Internal cookie used for matching	*/
76105760Srwatson	struct sockaddr_un sock;/* Pathname for the socket		*/
77105760Srwatson	dev_t dev;		/* Device where the socket lives on	*/
78105760Srwatson	ino_t ino;		/* Inode where the socket lives on	*/
79105760Srwatson	TAILQ_ENTRY(svr4_sockcache_entry) entries;
80105760Srwatson};
81105760Srwatson
82105760SrwatsonTAILQ_HEAD(svr4_sockcache_head, svr4_sockcache_entry) svr4_head;
83105760Srwatson
84105760Srwatson/* Initialization flag (set/queried by svr4_mod LKM) */
85105760Srwatsonint svr4_str_initialized = 0;
86105760Srwatson
87105760Srwatson/*
88105760Srwatson * Device minor numbers
89105760Srwatson */
90105760Srwatsonenum {
91105760Srwatson	dev_ptm			= 10,
92105760Srwatson	dev_arp			= 26,
93105760Srwatson	dev_icmp		= 27,
94105760Srwatson	dev_ip			= 28,
95105760Srwatson	dev_tcp			= 35,
96105760Srwatson	dev_udp			= 36,
97105760Srwatson	dev_rawip		= 37,
98105760Srwatson	dev_unix_dgram		= 38,
99105760Srwatson	dev_unix_stream		= 39,
100105760Srwatson	dev_unix_ord_stream	= 40
101};
102
103static struct fileops svr4_netops = {
104	soo_read, soo_write, soo_ioctl, soo_poll, svr4_soo_close
105};
106
107#define CDEV_MAJOR 103
108static struct cdevsw streams_cdevsw = {
109	/* open */	streamsopen,
110	/* close */	noclose,
111	/* read */	noread,
112	/* write */	nowrite,
113	/* ioctl */	noioctl,
114	/* stop */	nostop,
115	/* reset */	noreset,
116	/* devtotty */	nodevtotty,
117	/* poll */	nopoll,
118	/* mmap */	nommap,
119	/* strategy */	nostrategy,
120	/* name */	"streams",
121	/* parms */	noparms,
122	/* maj */	CDEV_MAJOR,
123	/* dump */	nodump,
124	/* psize */	nopsize,
125	/* flags */	0,
126	/* maxio */	0,
127	/* bmaj */	-1
128};
129
130struct streams_softc {
131	struct isa_device *dev;
132#ifdef DEVFS
133  /*
134   * If this ever becomes an LKM we'll want this crud so we can deallocate
135   * devfs entries when the module is unloaded
136   */
137	void *devfs_ptm;
138        void *devfs_arp;
139        void *devfs_icmp;
140        void *devfs_ip;
141        void *devfs_tcp;
142        void *devfs_udp;
143        void *devfs_rawip;
144        void *devfs_unix_dgram;
145        void *devfs_unix_stream;
146        void *devfs_unix_ord_stream;
147#endif
148} ;
149
150#define UNIT(dev) minor(dev)	/* assume one minor number per unit */
151
152typedef	struct streams_softc *sc_p;
153
154static	int
155streams_modevent(module_t mod, int type, void *unused)
156{
157	switch (type) {
158	case MOD_LOAD:
159		/* XXX should make sure it isn't already loaded first */
160		cdevsw_add(&streams_cdevsw);
161		return 0;
162	case MOD_UNLOAD:
163	  	/* XXX should check to see if it's busy first */
164		cdevsw_remove(&streams_cdevsw);
165		return 0;
166	default:
167		break;
168	}
169	return 0;
170}
171
172static moduledata_t streams_mod = {
173	"streams",
174	streams_modevent,
175	0
176};
177DECLARE_MODULE(streams, streams_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
178
179/*
180 * We only need open() and close() routines.  open() calls socreate()
181 * to allocate a "real" object behind the stream and mallocs some state
182 * info for use by the svr4 emulator;  close() deallocates the state
183 * information and passes the underlying object to the normal socket close
184 * routine.
185 */
186static  int
187streamsopen(dev_t dev, int oflags, int devtype, struct proc *p)
188{
189	int type, protocol;
190	int fd;
191	struct file *fp;
192	struct socket *so;
193	int error;
194	int family;
195
196	if (p->p_dupfd >= 0)
197	  return ENODEV;
198
199	switch (minor(dev)) {
200	case dev_udp:
201	  family = AF_INET;
202	  type = SOCK_DGRAM;
203	  protocol = IPPROTO_UDP;
204	  break;
205
206	case dev_tcp:
207	  family = AF_INET;
208	  type = SOCK_STREAM;
209	  protocol = IPPROTO_TCP;
210	  break;
211
212	case dev_ip:
213	case dev_rawip:
214	  family = AF_INET;
215	  type = SOCK_RAW;
216	  protocol = IPPROTO_IP;
217	  break;
218
219	case dev_icmp:
220	  family = AF_INET;
221	  type = SOCK_RAW;
222	  protocol = IPPROTO_ICMP;
223	  break;
224
225	case dev_unix_dgram:
226	  family = AF_LOCAL;
227	  type = SOCK_DGRAM;
228	  protocol = 0;
229	  break;
230
231	case dev_unix_stream:
232	case dev_unix_ord_stream:
233	  family = AF_LOCAL;
234	  type = SOCK_STREAM;
235	  protocol = 0;
236	  break;
237
238	case dev_ptm:
239	  return svr4_ptm_alloc(p);
240
241	default:
242	  return EOPNOTSUPP;
243	}
244
245	if ((error = falloc(p, &fp, &fd)) != 0)
246	  return error;
247
248	if ((error = socreate(family, &so, type, protocol, p)) != 0) {
249	  p->p_fd->fd_ofiles[fd] = 0;
250	  ffree(fp);
251	  return error;
252	}
253
254	fp->f_data = (caddr_t)so;
255	fp->f_flag = FREAD|FWRITE;
256	fp->f_ops = &svr4_netops;
257	fp->f_type = DTYPE_SOCKET;
258
259	(void)svr4_stream_get(fp);
260	p->p_dupfd = fd;
261	return ENXIO;
262}
263
264static int
265svr4_ptm_alloc(p)
266	struct proc *p;
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	caddr_t sg = stackgap_init();
285	char *path = stackgap_alloc(&sg, sizeof(ptyname));
286	struct open_args oa;
287	int l = 0, n = 0;
288	register_t fd = -1;
289	int error;
290
291	SCARG(&oa, path) = path;
292	SCARG(&oa, flags) = O_RDWR;
293	SCARG(&oa, mode) = 0;
294
295	while (fd == -1) {
296		ptyname[8] = ttyletters[l];
297		ptyname[9] = ttynumbers[n];
298
299		if ((error = copyout(ptyname, path, sizeof(ptyname))) != 0)
300			return error;
301
302		switch (error = open(p, &oa)) {
303		case ENOENT:
304		case ENXIO:
305			return error;
306		case 0:
307			p->p_dupfd = p->p_retval[0];
308			return ENXIO;
309		default:
310			if (ttynumbers[++n] == '\0') {
311				if (ttyletters[++l] == '\0')
312					break;
313				n = 0;
314			}
315		}
316	}
317	return ENOENT;
318}
319
320
321struct svr4_strm *
322svr4_stream_get(fp)
323	struct file *fp;
324{
325	struct socket *so;
326	struct svr4_strm *st;
327
328	if (fp == NULL || fp->f_type != DTYPE_SOCKET)
329		return NULL;
330
331	so = (struct socket *) fp->f_data;
332
333       	if (so->so_emuldata)
334		return so->so_emuldata;
335
336	/* Allocate a new one. */
337	st = malloc(sizeof(struct svr4_strm), M_TEMP, M_WAITOK);
338	st->s_family = so->so_proto->pr_domain->dom_family;
339	st->s_cmd = ~0;
340	st->s_afd = -1;
341	st->s_eventmask = 0;
342	so->so_emuldata = st;
343	fp->f_ops = &svr4_netops;
344
345	return st;
346}
347
348void
349svr4_delete_socket(p, fp)
350	struct proc *p;
351	struct file *fp;
352{
353	struct svr4_sockcache_entry *e;
354	void *cookie = ((struct socket *) fp->f_data)->so_emuldata;
355
356	if (!svr4_str_initialized) {
357		TAILQ_INIT(&svr4_head);
358		svr4_str_initialized = 1;
359		return;
360	}
361
362	for (e = svr4_head.tqh_first; e != NULL; e = e->entries.tqe_next)
363		if (e->p == p && e->cookie == cookie) {
364			TAILQ_REMOVE(&svr4_head, e, entries);
365			DPRINTF(("svr4_delete_socket: %s [%p,%d,%d]\n",
366				 e->sock.sun_path, p, e->dev, e->ino));
367			free(e, M_TEMP);
368			return;
369		}
370}
371
372static int
373svr4_soo_close(struct file *fp, struct proc *p)
374{
375        struct socket *so = (struct socket *)fp->f_data;
376
377	/*	CHECKUNIT_DIAG(ENXIO);*/
378
379	svr4_delete_socket(p, fp);
380	free(so->so_emuldata, M_TEMP);
381	return soo_close(fp, p);
382	return (0);
383}
384