streams.c revision 115550
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 * $FreeBSD: head/sys/dev/streams/streams.c 115550 2003-05-31 20:33:18Z phk $
34105760Srwatson */
35105760Srwatson
36105760Srwatson#include <sys/param.h>
37105760Srwatson#include <sys/systm.h>
38105760Srwatson#include <sys/kernel.h>		/* SYSINIT stuff */
39105760Srwatson#include <sys/conf.h>		/* cdevsw stuff */
40105760Srwatson#include <sys/malloc.h>		/* malloc region definitions */
41105760Srwatson#include <sys/file.h>
42105760Srwatson#include <sys/filedesc.h>
43105760Srwatson#include <sys/unistd.h>
44105760Srwatson#include <sys/fcntl.h>
45105760Srwatson#include <sys/socket.h>
46105760Srwatson#include <sys/protosw.h>
47105760Srwatson#include <sys/socketvar.h>
48105760Srwatson#include <sys/un.h>
49105760Srwatson#include <sys/domain.h>
50105760Srwatson#include <net/if.h>
51105760Srwatson#include <netinet/in.h>
52105760Srwatson#include <sys/proc.h>
53105825Srwatson#include <sys/uio.h>
54105760Srwatson
55105760Srwatson#include <sys/sysproto.h>
56105760Srwatson
57105760Srwatson#include <compat/svr4/svr4_types.h>
58105760Srwatson#include <compat/svr4/svr4_util.h>
59105760Srwatson#include <compat/svr4/svr4_signal.h>
60105760Srwatson#include <compat/svr4/svr4_ioctl.h>
61105760Srwatson#include <compat/svr4/svr4_stropts.h>
62105760Srwatson#include <compat/svr4/svr4_socket.h>
63105760Srwatson
64105760Srwatsonstatic int svr4_soo_close(struct file *, struct thread *);
65105760Srwatsonstatic int svr4_ptm_alloc(struct thread *);
66105760Srwatsonstatic  d_open_t	streamsopen;
67105760Srwatson
68105760Srwatsonstruct svr4_sockcache_head svr4_head;
69105760Srwatson
70105760Srwatson/* Initialization flag (set/queried by svr4_mod LKM) */
71105760Srwatsonint svr4_str_initialized = 0;
72105760Srwatson
73105825Srwatson/*
74105760Srwatson * Device minor numbers
75105760Srwatson */
76105760Srwatsonenum {
77105760Srwatson	dev_ptm			= 10,
78105760Srwatson	dev_arp			= 26,
79105760Srwatson	dev_icmp		= 27,
80105760Srwatson	dev_ip			= 28,
81105825Srwatson	dev_tcp			= 35,
82105760Srwatson	dev_udp			= 36,
83105760Srwatson	dev_rawip		= 37,
84105760Srwatson	dev_unix_dgram		= 38,
85105760Srwatson	dev_unix_stream		= 39,
86105760Srwatson	dev_unix_ord_stream	= 40
87105760Srwatson};
88105760Srwatson
89105760Srwatsonstatic dev_t dt_ptm, dt_arp, dt_icmp, dt_ip, dt_tcp, dt_udp, dt_rawip,
90105760Srwatson	dt_unix_dgram, dt_unix_stream, dt_unix_ord_stream;
91105760Srwatson
92105760Srwatsonstatic struct fileops svr4_netops = {
93105760Srwatson	soo_read, soo_write, soo_ioctl, soo_poll, soo_kqfilter,
94105760Srwatson	soo_stat, svr4_soo_close
95105760Srwatson};
96105760Srwatson
97105760Srwatson#define CDEV_MAJOR 103
98105760Srwatsonstatic struct cdevsw streams_cdevsw = {
99105760Srwatson	.d_open =	streamsopen,
100105760Srwatson	.d_name =	"streams",
101	.d_maj =	CDEV_MAJOR,
102};
103
104struct streams_softc {
105	struct isa_device *dev;
106} ;
107
108#define UNIT(dev) minor(dev)	/* assume one minor number per unit */
109
110typedef	struct streams_softc *sc_p;
111
112static	int
113streams_modevent(module_t mod, int type, void *unused)
114{
115	switch (type) {
116	case MOD_LOAD:
117		/* XXX should make sure it isn't already loaded first */
118		dt_ptm = make_dev(&streams_cdevsw, dev_ptm, 0, 0, 0666,
119			"ptm");
120		dt_arp = make_dev(&streams_cdevsw, dev_arp, 0, 0, 0666,
121			"arp");
122		dt_icmp = make_dev(&streams_cdevsw, dev_icmp, 0, 0, 0666,
123			"icmp");
124		dt_ip = make_dev(&streams_cdevsw, dev_ip, 0, 0, 0666,
125			"ip");
126		dt_tcp = make_dev(&streams_cdevsw, dev_tcp, 0, 0, 0666,
127			"tcp");
128		dt_udp = make_dev(&streams_cdevsw, dev_udp, 0, 0, 0666,
129			"udp");
130		dt_rawip = make_dev(&streams_cdevsw, dev_rawip, 0, 0, 0666,
131			"rawip");
132		dt_unix_dgram = make_dev(&streams_cdevsw, dev_unix_dgram,
133			0, 0, 0666, "ticlts");
134		dt_unix_stream = make_dev(&streams_cdevsw, dev_unix_stream,
135			0, 0, 0666, "ticots");
136		dt_unix_ord_stream = make_dev(&streams_cdevsw,
137			dev_unix_ord_stream, 0, 0, 0666, "ticotsord");
138
139		if (! (dt_ptm && dt_arp && dt_icmp && dt_ip && dt_tcp &&
140				dt_udp && dt_rawip && dt_unix_dgram &&
141				dt_unix_stream && dt_unix_ord_stream)) {
142			printf("WARNING: device config for STREAMS failed\n");
143			printf("Suggest unloading streams KLD\n");
144		}
145		return 0;
146	case MOD_UNLOAD:
147	  	/* XXX should check to see if it's busy first */
148		destroy_dev(dt_ptm);
149		destroy_dev(dt_arp);
150		destroy_dev(dt_icmp);
151		destroy_dev(dt_ip);
152		destroy_dev(dt_tcp);
153		destroy_dev(dt_udp);
154		destroy_dev(dt_rawip);
155		destroy_dev(dt_unix_dgram);
156		destroy_dev(dt_unix_stream);
157		destroy_dev(dt_unix_ord_stream);
158
159		return 0;
160	default:
161		break;
162	}
163	return 0;
164}
165
166static moduledata_t streams_mod = {
167	"streams",
168	streams_modevent,
169	0
170};
171DECLARE_MODULE(streams, streams_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
172MODULE_VERSION(streams, 1);
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 */
181static  int
182streamsopen(dev_t dev, int oflags, int devtype, struct thread *td)
183{
184	int type, protocol;
185	int fd;
186	struct file *fp;
187	struct socket *so;
188	int error;
189	int family;
190	struct proc *p = td->td_proc;
191
192	PROC_LOCK(p);
193	if (td->td_dupfd >= 0) {
194	  PROC_UNLOCK(p);
195	  return ENODEV;
196	}
197	PROC_UNLOCK(p);
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(td);
240
241	default:
242	  return EOPNOTSUPP;
243	}
244
245	if ((error = falloc(td, &fp, &fd)) != 0)
246	  return error;
247
248	if ((error = socreate(family, &so, type, protocol,
249	    td->td_ucred, td)) != 0) {
250	  FILEDESC_LOCK(p->p_fd);
251	  p->p_fd->fd_ofiles[fd] = 0;
252	  FILEDESC_UNLOCK(p->p_fd);
253	  ffree(fp);
254	  return error;
255	}
256
257	FILEDESC_LOCK(p->p_fd);
258	fp->f_data = so;
259	fp->f_flag = FREAD|FWRITE;
260	fp->f_ops = &svr4_netops;
261	fp->f_type = DTYPE_SOCKET;
262	FILEDESC_UNLOCK(p->p_fd);
263
264	(void)svr4_stream_get(fp);
265	PROC_LOCK(p);
266	td->td_dupfd = fd;
267	PROC_UNLOCK(p);
268	return ENXIO;
269}
270
271static int
272svr4_ptm_alloc(td)
273	struct thread *td;
274{
275	struct proc *p = td->td_proc;
276	/*
277	 * XXX this is very, very ugly.  But I can't find a better
278	 * way that won't duplicate a big amount of code from
279	 * sys_open().  Ho hum...
280	 *
281	 * Fortunately for us, Solaris (at least 2.5.1) makes the
282	 * /dev/ptmx open automatically just open a pty, that (after
283	 * STREAMS I_PUSHes), is just a plain pty.  fstat() is used
284	 * to get the minor device number to map to a tty.
285	 *
286	 * Cycle through the names. If sys_open() returns ENOENT (or
287	 * ENXIO), short circuit the cycle and exit.
288	 */
289	static char ptyname[] = "/dev/ptyXX";
290	static char ttyletters[] = "pqrstuwxyzPQRST";
291	static char ttynumbers[] = "0123456789abcdef";
292	caddr_t sg = stackgap_init();
293	char *path = stackgap_alloc(&sg, sizeof(ptyname));
294	struct open_args oa;
295	int l = 0, n = 0;
296	register_t fd = -1;
297	int error;
298
299	oa.path = path;
300	oa.flags = O_RDWR;
301	oa.mode = 0;
302
303	while (fd == -1) {
304		ptyname[8] = ttyletters[l];
305		ptyname[9] = ttynumbers[n];
306
307		if ((error = copyout(ptyname, path, sizeof(ptyname))) != 0)
308			return error;
309
310		switch (error = open(td, &oa)) {
311		case ENOENT:
312		case ENXIO:
313			return error;
314		case 0:
315			PROC_LOCK(p);
316			td->td_dupfd = td->td_retval[0];
317			PROC_UNLOCK(p);
318			return ENXIO;
319		default:
320			if (ttynumbers[++n] == '\0') {
321				if (ttyletters[++l] == '\0')
322					break;
323				n = 0;
324			}
325		}
326	}
327	return ENOENT;
328}
329
330
331struct svr4_strm *
332svr4_stream_get(fp)
333	struct file *fp;
334{
335	struct socket *so;
336	struct svr4_strm *st;
337
338	if (fp == NULL || fp->f_type != DTYPE_SOCKET)
339		return NULL;
340
341	so = fp->f_data;
342
343	/*
344	 * mpfixme: lock socketbuffer here
345	 */
346	if (so->so_emuldata) {
347		return so->so_emuldata;
348	}
349
350	/* Allocate a new one. */
351	st = malloc(sizeof(struct svr4_strm), M_TEMP, M_WAITOK);
352	st->s_family = so->so_proto->pr_domain->dom_family;
353	st->s_cmd = ~0;
354	st->s_afd = -1;
355	st->s_eventmask = 0;
356	/*
357	 * avoid a race where we loose due to concurrancy issues
358	 * of two threads trying to allocate the so_emuldata.
359	 */
360	if (so->so_emuldata) {
361		/* lost the race, use the existing emuldata */
362		FREE(st, M_TEMP);
363		st = so->so_emuldata;
364	} else {
365		/* we won, or there was no race, use our copy */
366		so->so_emuldata = st;
367		fp->f_ops = &svr4_netops;
368	}
369
370	return st;
371}
372
373void
374svr4_delete_socket(p, fp)
375	struct proc *p;
376	struct file *fp;
377{
378	struct svr4_sockcache_entry *e;
379	void *cookie = ((struct socket *)fp->f_data)->so_emuldata;
380
381	while (svr4_str_initialized != 2) {
382		if (atomic_cmpset_acq_int(&svr4_str_initialized, 0, 1)) {
383			TAILQ_INIT(&svr4_head);
384			atomic_store_rel_int(&svr4_str_initialized, 2);
385		}
386		return;
387	}
388
389	TAILQ_FOREACH(e, &svr4_head, entries)
390		if (e->p == p && e->cookie == cookie) {
391			TAILQ_REMOVE(&svr4_head, e, entries);
392			DPRINTF(("svr4_delete_socket: %s [%p,%d,%d]\n",
393				 e->sock.sun_path, p, (int)e->dev, e->ino));
394			free(e, M_TEMP);
395			return;
396		}
397}
398
399static int
400svr4_soo_close(struct file *fp, struct thread *td)
401{
402        struct socket *so = fp->f_data;
403
404	/*	CHECKUNIT_DIAG(ENXIO);*/
405
406	svr4_delete_socket(td->td_proc, fp);
407	free(so->so_emuldata, M_TEMP);
408	return soo_close(fp, td);
409}
410