streams.c revision 130585
143410Snewton/*
243410Snewton * Copyright (c) 1998 Mark Newton
343410Snewton * Copyright (c) 1994 Christos Zoulas
443410Snewton * Copyright (c) 1997 Todd Vierling
543410Snewton * All rights reserved.
643410Snewton *
743410Snewton * Redistribution and use in source and binary forms, with or without
843410Snewton * modification, are permitted provided that the following conditions
943410Snewton * are met:
1043410Snewton * 1. Redistributions of source code must retain the above copyright
1143410Snewton *    notice, this list of conditions and the following disclaimer.
1243410Snewton * 2. Redistributions in binary form must reproduce the above copyright
1343410Snewton *    notice, this list of conditions and the following disclaimer in the
1443410Snewton *    documentation and/or other materials provided with the distribution.
1543410Snewton * 3. The names of the authors may not be used to endorse or promote products
1643410Snewton *    derived from this software without specific prior written permission
1743410Snewton *
1843410Snewton * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1943410Snewton * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2043410Snewton * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2143410Snewton * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2243410Snewton * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2343410Snewton * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2443410Snewton * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2543410Snewton * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2643410Snewton * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2743410Snewton * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2843410Snewton *
2943410Snewton * Stolen from NetBSD /sys/compat/svr4/svr4_net.c.  Pseudo-device driver
3043410Snewton * skeleton produced from /usr/share/examples/drivers/make_pseudo_driver.sh
3143410Snewton * in 3.0-980524-SNAP then hacked a bit (but probably not enough :-).
3249263Snewton *
3343410Snewton */
3443410Snewton
35119420Sobrien#include <sys/cdefs.h>
36119420Sobrien__FBSDID("$FreeBSD: head/sys/dev/streams/streams.c 130585 2004-06-16 09:47:26Z phk $");
37119420Sobrien
3843410Snewton#include <sys/param.h>
3943410Snewton#include <sys/systm.h>
4043410Snewton#include <sys/kernel.h>		/* SYSINIT stuff */
4143410Snewton#include <sys/conf.h>		/* cdevsw stuff */
4243410Snewton#include <sys/malloc.h>		/* malloc region definitions */
4343410Snewton#include <sys/file.h>
4443410Snewton#include <sys/filedesc.h>
4543410Snewton#include <sys/unistd.h>
4643410Snewton#include <sys/fcntl.h>
4743410Snewton#include <sys/socket.h>
4843410Snewton#include <sys/protosw.h>
4943410Snewton#include <sys/socketvar.h>
5043410Snewton#include <sys/un.h>
5143410Snewton#include <sys/domain.h>
5243410Snewton#include <net/if.h>
5343410Snewton#include <netinet/in.h>
5443410Snewton#include <sys/proc.h>
5543410Snewton#include <sys/uio.h>
5643410Snewton
5743410Snewton#include <sys/sysproto.h>
5843410Snewton
5965314Sobrien#include <compat/svr4/svr4_types.h>
6065314Sobrien#include <compat/svr4/svr4_util.h>
6165314Sobrien#include <compat/svr4/svr4_signal.h>
6265314Sobrien#include <compat/svr4/svr4_ioctl.h>
6365314Sobrien#include <compat/svr4/svr4_stropts.h>
6465314Sobrien#include <compat/svr4/svr4_socket.h>
6543410Snewton
6692739Salfredstatic int svr4_soo_close(struct file *, struct thread *);
6792739Salfredstatic int svr4_ptm_alloc(struct thread *);
6843410Snewtonstatic  d_open_t	streamsopen;
6943410Snewton
70115550Sphkstruct svr4_sockcache_head svr4_head;
7143410Snewton
7243410Snewton/* Initialization flag (set/queried by svr4_mod LKM) */
7343410Snewtonint svr4_str_initialized = 0;
7443410Snewton
7543410Snewton/*
7643410Snewton * Device minor numbers
7743410Snewton */
7843410Snewtonenum {
7943410Snewton	dev_ptm			= 10,
8043410Snewton	dev_arp			= 26,
8143410Snewton	dev_icmp		= 27,
8243410Snewton	dev_ip			= 28,
8343410Snewton	dev_tcp			= 35,
8443410Snewton	dev_udp			= 36,
8543410Snewton	dev_rawip		= 37,
8643410Snewton	dev_unix_dgram		= 38,
8743410Snewton	dev_unix_stream		= 39,
8843410Snewton	dev_unix_ord_stream	= 40
8943410Snewton};
9043410Snewton
91130585Sphkstatic struct cdev *dt_ptm, *dt_arp, *dt_icmp, *dt_ip, *dt_tcp, *dt_udp, *dt_rawip,
92130585Sphk	*dt_unix_dgram, *dt_unix_stream, *dt_unix_ord_stream;
9352114Snewton
9443410Snewtonstatic struct fileops svr4_netops = {
95116546Sphk	.fo_read = soo_read,
96116546Sphk	.fo_write = soo_write,
97116546Sphk	.fo_ioctl = soo_ioctl,
98116546Sphk	.fo_poll = soo_poll,
99116546Sphk	.fo_kqfilter = soo_kqfilter,
100116546Sphk	.fo_stat = soo_stat,
101116546Sphk	.fo_close =  svr4_soo_close
10243410Snewton};
10343410Snewton
10443410Snewtonstatic struct cdevsw streams_cdevsw = {
105126080Sphk	.d_version =	D_VERSION,
106126080Sphk	.d_flags =	D_NEEDGIANT,
107111815Sphk	.d_open =	streamsopen,
108111815Sphk	.d_name =	"streams",
10947625Sphk};
11043410Snewton
11143410Snewtonstruct streams_softc {
11243410Snewton	struct isa_device *dev;
11343410Snewton} ;
11443410Snewton
11543410Snewton#define UNIT(dev) minor(dev)	/* assume one minor number per unit */
11643410Snewton
11743410Snewtontypedef	struct streams_softc *sc_p;
11843410Snewton
11944208Snewtonstatic	int
12044208Snewtonstreams_modevent(module_t mod, int type, void *unused)
12144208Snewton{
12244208Snewton	switch (type) {
12344208Snewton	case MOD_LOAD:
12449344Snewton		/* XXX should make sure it isn't already loaded first */
12552114Snewton		dt_ptm = make_dev(&streams_cdevsw, dev_ptm, 0, 0, 0666,
12652114Snewton			"ptm");
12752114Snewton		dt_arp = make_dev(&streams_cdevsw, dev_arp, 0, 0, 0666,
12852114Snewton			"arp");
12952114Snewton		dt_icmp = make_dev(&streams_cdevsw, dev_icmp, 0, 0, 0666,
13052114Snewton			"icmp");
13152114Snewton		dt_ip = make_dev(&streams_cdevsw, dev_ip, 0, 0, 0666,
13252114Snewton			"ip");
13352114Snewton		dt_tcp = make_dev(&streams_cdevsw, dev_tcp, 0, 0, 0666,
13452114Snewton			"tcp");
13552114Snewton		dt_udp = make_dev(&streams_cdevsw, dev_udp, 0, 0, 0666,
13652114Snewton			"udp");
13752114Snewton		dt_rawip = make_dev(&streams_cdevsw, dev_rawip, 0, 0, 0666,
13852114Snewton			"rawip");
13952114Snewton		dt_unix_dgram = make_dev(&streams_cdevsw, dev_unix_dgram,
14052114Snewton			0, 0, 0666, "ticlts");
14152114Snewton		dt_unix_stream = make_dev(&streams_cdevsw, dev_unix_stream,
14252114Snewton			0, 0, 0666, "ticots");
14352114Snewton		dt_unix_ord_stream = make_dev(&streams_cdevsw,
14452114Snewton			dev_unix_ord_stream, 0, 0, 0666, "ticotsord");
14552114Snewton
14652114Snewton		if (! (dt_ptm && dt_arp && dt_icmp && dt_ip && dt_tcp &&
14752114Snewton				dt_udp && dt_rawip && dt_unix_dgram &&
14852114Snewton				dt_unix_stream && dt_unix_ord_stream)) {
14952114Snewton			printf("WARNING: device config for STREAMS failed\n");
15052114Snewton			printf("Suggest unloading streams KLD\n");
15152114Snewton		}
15244208Snewton		return 0;
15344208Snewton	case MOD_UNLOAD:
15449344Snewton	  	/* XXX should check to see if it's busy first */
15553000Sphk		destroy_dev(dt_ptm);
15653000Sphk		destroy_dev(dt_arp);
15753000Sphk		destroy_dev(dt_icmp);
15853000Sphk		destroy_dev(dt_ip);
15953000Sphk		destroy_dev(dt_tcp);
16053000Sphk		destroy_dev(dt_udp);
16153000Sphk		destroy_dev(dt_rawip);
16253000Sphk		destroy_dev(dt_unix_dgram);
16353000Sphk		destroy_dev(dt_unix_stream);
16453000Sphk		destroy_dev(dt_unix_ord_stream);
16552114Snewton
16644208Snewton		return 0;
16744208Snewton	default:
16844208Snewton		break;
16944208Snewton	}
17044208Snewton	return 0;
17144208Snewton}
17244208Snewton
17344208Snewtonstatic moduledata_t streams_mod = {
17444208Snewton	"streams",
17544208Snewton	streams_modevent,
17644208Snewton	0
17744208Snewton};
17844208SnewtonDECLARE_MODULE(streams, streams_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
17960060SgreenMODULE_VERSION(streams, 1);
18044208Snewton
18143410Snewton/*
18243410Snewton * We only need open() and close() routines.  open() calls socreate()
18343410Snewton * to allocate a "real" object behind the stream and mallocs some state
18443410Snewton * info for use by the svr4 emulator;  close() deallocates the state
18543410Snewton * information and passes the underlying object to the normal socket close
18643410Snewton * routine.
18743410Snewton */
18843410Snewtonstatic  int
189130585Sphkstreamsopen(struct cdev *dev, int oflags, int devtype, struct thread *td)
19043410Snewton{
19143410Snewton	int type, protocol;
192121256Sdwmalone	int fd, extraref;
19343410Snewton	struct file *fp;
19443410Snewton	struct socket *so;
19543410Snewton	int error;
19643410Snewton	int family;
19783366Sjulian	struct proc *p = td->td_proc;
19843410Snewton
19971448Sjhb	PROC_LOCK(p);
20083366Sjulian	if (td->td_dupfd >= 0) {
20171448Sjhb	  PROC_UNLOCK(p);
20243410Snewton	  return ENODEV;
20371448Sjhb	}
20471448Sjhb	PROC_UNLOCK(p);
20543410Snewton
20643410Snewton	switch (minor(dev)) {
20743410Snewton	case dev_udp:
20843410Snewton	  family = AF_INET;
20943410Snewton	  type = SOCK_DGRAM;
21043410Snewton	  protocol = IPPROTO_UDP;
21143410Snewton	  break;
21243410Snewton
21343410Snewton	case dev_tcp:
21443410Snewton	  family = AF_INET;
21543410Snewton	  type = SOCK_STREAM;
21643410Snewton	  protocol = IPPROTO_TCP;
21743410Snewton	  break;
21843410Snewton
21943410Snewton	case dev_ip:
22043410Snewton	case dev_rawip:
22143410Snewton	  family = AF_INET;
22243410Snewton	  type = SOCK_RAW;
22343410Snewton	  protocol = IPPROTO_IP;
22443410Snewton	  break;
22543410Snewton
22643410Snewton	case dev_icmp:
22743410Snewton	  family = AF_INET;
22843410Snewton	  type = SOCK_RAW;
22943410Snewton	  protocol = IPPROTO_ICMP;
23043410Snewton	  break;
23143410Snewton
23243410Snewton	case dev_unix_dgram:
23343410Snewton	  family = AF_LOCAL;
23443410Snewton	  type = SOCK_DGRAM;
23543410Snewton	  protocol = 0;
23643410Snewton	  break;
23743410Snewton
23843410Snewton	case dev_unix_stream:
23943410Snewton	case dev_unix_ord_stream:
24043410Snewton	  family = AF_LOCAL;
24143410Snewton	  type = SOCK_STREAM;
24243410Snewton	  protocol = 0;
24343410Snewton	  break;
24443410Snewton
24543410Snewton	case dev_ptm:
24683366Sjulian	  return svr4_ptm_alloc(td);
24743410Snewton
24843410Snewton	default:
24943410Snewton	  return EOPNOTSUPP;
25043410Snewton	}
25143410Snewton
25283366Sjulian	if ((error = falloc(td, &fp, &fd)) != 0)
25343410Snewton	  return error;
254121256Sdwmalone	/* An extra reference on `fp' has been held for us by falloc(). */
25543410Snewton
25688739Srwatson	if ((error = socreate(family, &so, type, protocol,
25791406Sjhb	    td->td_ucred, td)) != 0) {
25889306Salfred	  FILEDESC_LOCK(p->p_fd);
259121256Sdwmalone	  /* Check the fd table entry hasn't changed since we made it. */
260121256Sdwmalone	  extraref = 0;
261121256Sdwmalone	  if (p->p_fd->fd_ofiles[fd] == fp) {
262121256Sdwmalone	    p->p_fd->fd_ofiles[fd] = NULL;
263121256Sdwmalone	    extraref = 1;
264121256Sdwmalone	  }
26589306Salfred	  FILEDESC_UNLOCK(p->p_fd);
266121256Sdwmalone	  if (extraref)
267121256Sdwmalone	    fdrop(fp, td);
268121256Sdwmalone	  fdrop(fp, td);
26943410Snewton	  return error;
27043410Snewton	}
27143410Snewton
27289306Salfred	FILEDESC_LOCK(p->p_fd);
273109153Sdillon	fp->f_data = so;
27443410Snewton	fp->f_flag = FREAD|FWRITE;
27549413Sgreen	fp->f_ops = &svr4_netops;
27643410Snewton	fp->f_type = DTYPE_SOCKET;
27789306Salfred	FILEDESC_UNLOCK(p->p_fd);
27843410Snewton
27943410Snewton	(void)svr4_stream_get(fp);
280121256Sdwmalone	fdrop(fp, td);
28171448Sjhb	PROC_LOCK(p);
28283366Sjulian	td->td_dupfd = fd;
28371448Sjhb	PROC_UNLOCK(p);
28443410Snewton	return ENXIO;
28543410Snewton}
28643410Snewton
28743410Snewtonstatic int
28883366Sjuliansvr4_ptm_alloc(td)
28983366Sjulian	struct thread *td;
29043410Snewton{
29183366Sjulian	struct proc *p = td->td_proc;
29243410Snewton	/*
29343410Snewton	 * XXX this is very, very ugly.  But I can't find a better
29443410Snewton	 * way that won't duplicate a big amount of code from
29543410Snewton	 * sys_open().  Ho hum...
29643410Snewton	 *
29743410Snewton	 * Fortunately for us, Solaris (at least 2.5.1) makes the
29843410Snewton	 * /dev/ptmx open automatically just open a pty, that (after
29943410Snewton	 * STREAMS I_PUSHes), is just a plain pty.  fstat() is used
30043410Snewton	 * to get the minor device number to map to a tty.
30143410Snewton	 *
30243410Snewton	 * Cycle through the names. If sys_open() returns ENOENT (or
30343410Snewton	 * ENXIO), short circuit the cycle and exit.
30443410Snewton	 */
30543410Snewton	static char ptyname[] = "/dev/ptyXX";
30643410Snewton	static char ttyletters[] = "pqrstuwxyzPQRST";
30743410Snewton	static char ttynumbers[] = "0123456789abcdef";
30843410Snewton	caddr_t sg = stackgap_init();
30943410Snewton	char *path = stackgap_alloc(&sg, sizeof(ptyname));
31043410Snewton	struct open_args oa;
31143410Snewton	int l = 0, n = 0;
31243410Snewton	register_t fd = -1;
31343410Snewton	int error;
31443410Snewton
315107849Salfred	oa.path = path;
316107849Salfred	oa.flags = O_RDWR;
317107849Salfred	oa.mode = 0;
31843410Snewton
31943410Snewton	while (fd == -1) {
32043410Snewton		ptyname[8] = ttyletters[l];
32143410Snewton		ptyname[9] = ttynumbers[n];
32243410Snewton
32343410Snewton		if ((error = copyout(ptyname, path, sizeof(ptyname))) != 0)
32443410Snewton			return error;
32543410Snewton
32683366Sjulian		switch (error = open(td, &oa)) {
32743410Snewton		case ENOENT:
32843410Snewton		case ENXIO:
32943410Snewton			return error;
33043410Snewton		case 0:
33171448Sjhb			PROC_LOCK(p);
33283366Sjulian			td->td_dupfd = td->td_retval[0];
33371448Sjhb			PROC_UNLOCK(p);
33443410Snewton			return ENXIO;
33543410Snewton		default:
33643410Snewton			if (ttynumbers[++n] == '\0') {
33743410Snewton				if (ttyletters[++l] == '\0')
33843410Snewton					break;
33943410Snewton				n = 0;
34043410Snewton			}
34143410Snewton		}
34243410Snewton	}
34343410Snewton	return ENOENT;
34443410Snewton}
34543410Snewton
34643410Snewton
34743410Snewtonstruct svr4_strm *
34843410Snewtonsvr4_stream_get(fp)
34943410Snewton	struct file *fp;
35043410Snewton{
35143410Snewton	struct socket *so;
35243410Snewton	struct svr4_strm *st;
35343410Snewton
35443410Snewton	if (fp == NULL || fp->f_type != DTYPE_SOCKET)
35543410Snewton		return NULL;
35643410Snewton
357109153Sdillon	so = fp->f_data;
35843410Snewton
35989306Salfred	/*
36089306Salfred	 * mpfixme: lock socketbuffer here
36189306Salfred	 */
36289306Salfred	if (so->so_emuldata) {
36343410Snewton		return so->so_emuldata;
36489306Salfred	}
36543410Snewton
36643410Snewton	/* Allocate a new one. */
367111119Simp	st = malloc(sizeof(struct svr4_strm), M_TEMP, M_WAITOK);
36843410Snewton	st->s_family = so->so_proto->pr_domain->dom_family;
36943410Snewton	st->s_cmd = ~0;
37043410Snewton	st->s_afd = -1;
37143410Snewton	st->s_eventmask = 0;
37289306Salfred	/*
37389306Salfred	 * avoid a race where we loose due to concurrancy issues
37489306Salfred	 * of two threads trying to allocate the so_emuldata.
37589306Salfred	 */
37689306Salfred	if (so->so_emuldata) {
37789306Salfred		/* lost the race, use the existing emuldata */
37889306Salfred		FREE(st, M_TEMP);
37989306Salfred		st = so->so_emuldata;
38089306Salfred	} else {
38189306Salfred		/* we won, or there was no race, use our copy */
38289306Salfred		so->so_emuldata = st;
38389306Salfred		fp->f_ops = &svr4_netops;
38489306Salfred	}
38543410Snewton
38643410Snewton	return st;
38743410Snewton}
38843410Snewton
38943410Snewtonvoid
39043410Snewtonsvr4_delete_socket(p, fp)
39143410Snewton	struct proc *p;
39243410Snewton	struct file *fp;
39343410Snewton{
39443410Snewton	struct svr4_sockcache_entry *e;
395109153Sdillon	void *cookie = ((struct socket *)fp->f_data)->so_emuldata;
39643410Snewton
39771448Sjhb	while (svr4_str_initialized != 2) {
39871448Sjhb		if (atomic_cmpset_acq_int(&svr4_str_initialized, 0, 1)) {
39971448Sjhb			TAILQ_INIT(&svr4_head);
40071448Sjhb			atomic_store_rel_int(&svr4_str_initialized, 2);
40171448Sjhb		}
40243410Snewton		return;
40343410Snewton	}
40443410Snewton
40571448Sjhb	TAILQ_FOREACH(e, &svr4_head, entries)
40643410Snewton		if (e->p == p && e->cookie == cookie) {
40743410Snewton			TAILQ_REMOVE(&svr4_head, e, entries);
40843410Snewton			DPRINTF(("svr4_delete_socket: %s [%p,%d,%d]\n",
40985653Sdillon				 e->sock.sun_path, p, (int)e->dev, e->ino));
41043410Snewton			free(e, M_TEMP);
41143410Snewton			return;
41243410Snewton		}
41343410Snewton}
41443410Snewton
41543410Snewtonstatic int
41683366Sjuliansvr4_soo_close(struct file *fp, struct thread *td)
41743410Snewton{
418109153Sdillon        struct socket *so = fp->f_data;
41943410Snewton
42043410Snewton	/*	CHECKUNIT_DIAG(ENXIO);*/
42143410Snewton
42283366Sjulian	svr4_delete_socket(td->td_proc, fp);
42343410Snewton	free(so->so_emuldata, M_TEMP);
42483366Sjulian	return soo_close(fp, td);
42543410Snewton}
426