streams.c revision 91406
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 *
3350477Speter * $FreeBSD: head/sys/dev/streams/streams.c 91406 2002-02-27 18:32:23Z jhb $
3443410Snewton */
3543410Snewton
3643410Snewton#include <sys/param.h>
3743410Snewton#include <sys/systm.h>
3843410Snewton#include <sys/kernel.h>		/* SYSINIT stuff */
3943410Snewton#include <sys/conf.h>		/* cdevsw stuff */
4043410Snewton#include <sys/malloc.h>		/* malloc region definitions */
4143410Snewton#include <sys/file.h>
4243410Snewton#include <sys/filedesc.h>
4343410Snewton#include <sys/unistd.h>
4443410Snewton#include <sys/fcntl.h>
4543410Snewton#include <sys/socket.h>
4643410Snewton#include <sys/protosw.h>
4743410Snewton#include <sys/socketvar.h>
4843410Snewton#include <sys/un.h>
4943410Snewton#include <sys/domain.h>
5043410Snewton#include <net/if.h>
5143410Snewton#include <netinet/in.h>
5243410Snewton#include <sys/proc.h>
5343410Snewton#include <sys/uio.h>
5443410Snewton
5543410Snewton#include <sys/sysproto.h>
5643410Snewton
5765314Sobrien#include <compat/svr4/svr4_types.h>
5865314Sobrien#include <compat/svr4/svr4_util.h>
5965314Sobrien#include <compat/svr4/svr4_signal.h>
6065314Sobrien#include <compat/svr4/svr4_ioctl.h>
6165314Sobrien#include <compat/svr4/svr4_stropts.h>
6265314Sobrien#include <compat/svr4/svr4_socket.h>
6343410Snewton
6483366Sjulianstatic int svr4_soo_close __P((struct file *, struct thread *));
6583366Sjulianstatic int svr4_ptm_alloc __P((struct thread *));
6643410Snewtonstatic  d_open_t	streamsopen;
6743410Snewton
6843410Snewtonstruct svr4_sockcache_entry {
6943410Snewton	struct proc *p;		/* Process for the socket		*/
7043410Snewton	void *cookie;		/* Internal cookie used for matching	*/
7143410Snewton	struct sockaddr_un sock;/* Pathname for the socket		*/
7243410Snewton	dev_t dev;		/* Device where the socket lives on	*/
7343410Snewton	ino_t ino;		/* Inode where the socket lives on	*/
7460938Sjake	TAILQ_ENTRY(svr4_sockcache_entry) entries;
7543410Snewton};
7643410Snewton
7760938SjakeTAILQ_HEAD(svr4_sockcache_head, svr4_sockcache_entry) svr4_head;
7843410Snewton
7943410Snewton/* Initialization flag (set/queried by svr4_mod LKM) */
8043410Snewtonint svr4_str_initialized = 0;
8143410Snewton
8243410Snewton/*
8343410Snewton * Device minor numbers
8443410Snewton */
8543410Snewtonenum {
8643410Snewton	dev_ptm			= 10,
8743410Snewton	dev_arp			= 26,
8843410Snewton	dev_icmp		= 27,
8943410Snewton	dev_ip			= 28,
9043410Snewton	dev_tcp			= 35,
9143410Snewton	dev_udp			= 36,
9243410Snewton	dev_rawip		= 37,
9343410Snewton	dev_unix_dgram		= 38,
9443410Snewton	dev_unix_stream		= 39,
9543410Snewton	dev_unix_ord_stream	= 40
9643410Snewton};
9743410Snewton
9889059Smsmithstatic dev_t dt_ptm, dt_arp, dt_icmp, dt_ip, dt_tcp, dt_udp, dt_rawip,
9952114Snewton	dt_unix_dgram, dt_unix_stream, dt_unix_ord_stream;
10052114Snewton
10143410Snewtonstatic struct fileops svr4_netops = {
10272521Sjlemon	soo_read, soo_write, soo_ioctl, soo_poll, sokqfilter,
10372521Sjlemon	soo_stat, svr4_soo_close
10443410Snewton};
10543410Snewton
10643410Snewton#define CDEV_MAJOR 103
10743410Snewtonstatic struct cdevsw streams_cdevsw = {
10847625Sphk	/* open */	streamsopen,
10947625Sphk	/* close */	noclose,
11047625Sphk	/* read */	noread,
11147625Sphk	/* write */	nowrite,
11247625Sphk	/* ioctl */	noioctl,
11347625Sphk	/* poll */	nopoll,
11447625Sphk	/* mmap */	nommap,
11547625Sphk	/* strategy */	nostrategy,
11647625Sphk	/* name */	"streams",
11747625Sphk	/* maj */	CDEV_MAJOR,
11847625Sphk	/* dump */	nodump,
11947625Sphk	/* psize */	nopsize,
12047625Sphk	/* flags */	0,
12147625Sphk};
12243410Snewton
12343410Snewtonstruct streams_softc {
12443410Snewton	struct isa_device *dev;
12543410Snewton} ;
12643410Snewton
12743410Snewton#define UNIT(dev) minor(dev)	/* assume one minor number per unit */
12843410Snewton
12943410Snewtontypedef	struct streams_softc *sc_p;
13043410Snewton
13144208Snewtonstatic	int
13244208Snewtonstreams_modevent(module_t mod, int type, void *unused)
13344208Snewton{
13444208Snewton	switch (type) {
13544208Snewton	case MOD_LOAD:
13649344Snewton		/* XXX should make sure it isn't already loaded first */
13752114Snewton		dt_ptm = make_dev(&streams_cdevsw, dev_ptm, 0, 0, 0666,
13852114Snewton			"ptm");
13952114Snewton		dt_arp = make_dev(&streams_cdevsw, dev_arp, 0, 0, 0666,
14052114Snewton			"arp");
14152114Snewton		dt_icmp = make_dev(&streams_cdevsw, dev_icmp, 0, 0, 0666,
14252114Snewton			"icmp");
14352114Snewton		dt_ip = make_dev(&streams_cdevsw, dev_ip, 0, 0, 0666,
14452114Snewton			"ip");
14552114Snewton		dt_tcp = make_dev(&streams_cdevsw, dev_tcp, 0, 0, 0666,
14652114Snewton			"tcp");
14752114Snewton		dt_udp = make_dev(&streams_cdevsw, dev_udp, 0, 0, 0666,
14852114Snewton			"udp");
14952114Snewton		dt_rawip = make_dev(&streams_cdevsw, dev_rawip, 0, 0, 0666,
15052114Snewton			"rawip");
15152114Snewton		dt_unix_dgram = make_dev(&streams_cdevsw, dev_unix_dgram,
15252114Snewton			0, 0, 0666, "ticlts");
15352114Snewton		dt_unix_stream = make_dev(&streams_cdevsw, dev_unix_stream,
15452114Snewton			0, 0, 0666, "ticots");
15552114Snewton		dt_unix_ord_stream = make_dev(&streams_cdevsw,
15652114Snewton			dev_unix_ord_stream, 0, 0, 0666, "ticotsord");
15752114Snewton
15852114Snewton		if (! (dt_ptm && dt_arp && dt_icmp && dt_ip && dt_tcp &&
15952114Snewton				dt_udp && dt_rawip && dt_unix_dgram &&
16052114Snewton				dt_unix_stream && dt_unix_ord_stream)) {
16152114Snewton			printf("WARNING: device config for STREAMS failed\n");
16252114Snewton			printf("Suggest unloading streams KLD\n");
16352114Snewton		}
16444208Snewton		return 0;
16544208Snewton	case MOD_UNLOAD:
16649344Snewton	  	/* XXX should check to see if it's busy first */
16753000Sphk		destroy_dev(dt_ptm);
16853000Sphk		destroy_dev(dt_arp);
16953000Sphk		destroy_dev(dt_icmp);
17053000Sphk		destroy_dev(dt_ip);
17153000Sphk		destroy_dev(dt_tcp);
17253000Sphk		destroy_dev(dt_udp);
17353000Sphk		destroy_dev(dt_rawip);
17453000Sphk		destroy_dev(dt_unix_dgram);
17553000Sphk		destroy_dev(dt_unix_stream);
17653000Sphk		destroy_dev(dt_unix_ord_stream);
17752114Snewton
17844208Snewton		return 0;
17944208Snewton	default:
18044208Snewton		break;
18144208Snewton	}
18244208Snewton	return 0;
18344208Snewton}
18444208Snewton
18544208Snewtonstatic moduledata_t streams_mod = {
18644208Snewton	"streams",
18744208Snewton	streams_modevent,
18844208Snewton	0
18944208Snewton};
19044208SnewtonDECLARE_MODULE(streams, streams_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
19160060SgreenMODULE_VERSION(streams, 1);
19244208Snewton
19343410Snewton/*
19443410Snewton * We only need open() and close() routines.  open() calls socreate()
19543410Snewton * to allocate a "real" object behind the stream and mallocs some state
19643410Snewton * info for use by the svr4 emulator;  close() deallocates the state
19743410Snewton * information and passes the underlying object to the normal socket close
19843410Snewton * routine.
19943410Snewton */
20043410Snewtonstatic  int
20183366Sjulianstreamsopen(dev_t dev, int oflags, int devtype, struct thread *td)
20243410Snewton{
20343410Snewton	int type, protocol;
20443410Snewton	int fd;
20543410Snewton	struct file *fp;
20643410Snewton	struct socket *so;
20743410Snewton	int error;
20843410Snewton	int family;
20983366Sjulian	struct proc *p = td->td_proc;
21043410Snewton
21171448Sjhb	PROC_LOCK(p);
21283366Sjulian	if (td->td_dupfd >= 0) {
21371448Sjhb	  PROC_UNLOCK(p);
21443410Snewton	  return ENODEV;
21571448Sjhb	}
21671448Sjhb	PROC_UNLOCK(p);
21743410Snewton
21843410Snewton	switch (minor(dev)) {
21943410Snewton	case dev_udp:
22043410Snewton	  family = AF_INET;
22143410Snewton	  type = SOCK_DGRAM;
22243410Snewton	  protocol = IPPROTO_UDP;
22343410Snewton	  break;
22443410Snewton
22543410Snewton	case dev_tcp:
22643410Snewton	  family = AF_INET;
22743410Snewton	  type = SOCK_STREAM;
22843410Snewton	  protocol = IPPROTO_TCP;
22943410Snewton	  break;
23043410Snewton
23143410Snewton	case dev_ip:
23243410Snewton	case dev_rawip:
23343410Snewton	  family = AF_INET;
23443410Snewton	  type = SOCK_RAW;
23543410Snewton	  protocol = IPPROTO_IP;
23643410Snewton	  break;
23743410Snewton
23843410Snewton	case dev_icmp:
23943410Snewton	  family = AF_INET;
24043410Snewton	  type = SOCK_RAW;
24143410Snewton	  protocol = IPPROTO_ICMP;
24243410Snewton	  break;
24343410Snewton
24443410Snewton	case dev_unix_dgram:
24543410Snewton	  family = AF_LOCAL;
24643410Snewton	  type = SOCK_DGRAM;
24743410Snewton	  protocol = 0;
24843410Snewton	  break;
24943410Snewton
25043410Snewton	case dev_unix_stream:
25143410Snewton	case dev_unix_ord_stream:
25243410Snewton	  family = AF_LOCAL;
25343410Snewton	  type = SOCK_STREAM;
25443410Snewton	  protocol = 0;
25543410Snewton	  break;
25643410Snewton
25743410Snewton	case dev_ptm:
25883366Sjulian	  return svr4_ptm_alloc(td);
25943410Snewton
26043410Snewton	default:
26143410Snewton	  return EOPNOTSUPP;
26243410Snewton	}
26343410Snewton
26483366Sjulian	if ((error = falloc(td, &fp, &fd)) != 0)
26543410Snewton	  return error;
26643410Snewton
26788739Srwatson	if ((error = socreate(family, &so, type, protocol,
26891406Sjhb	    td->td_ucred, td)) != 0) {
26989306Salfred	  FILEDESC_LOCK(p->p_fd);
27043410Snewton	  p->p_fd->fd_ofiles[fd] = 0;
27189306Salfred	  FILEDESC_UNLOCK(p->p_fd);
27243410Snewton	  ffree(fp);
27343410Snewton	  return error;
27443410Snewton	}
27543410Snewton
27689306Salfred	FILEDESC_LOCK(p->p_fd);
27749413Sgreen	fp->f_data = (caddr_t)so;
27843410Snewton	fp->f_flag = FREAD|FWRITE;
27949413Sgreen	fp->f_ops = &svr4_netops;
28043410Snewton	fp->f_type = DTYPE_SOCKET;
28189306Salfred	FILEDESC_UNLOCK(p->p_fd);
28243410Snewton
28343410Snewton	(void)svr4_stream_get(fp);
28471448Sjhb	PROC_LOCK(p);
28583366Sjulian	td->td_dupfd = fd;
28671448Sjhb	PROC_UNLOCK(p);
28743410Snewton	return ENXIO;
28843410Snewton}
28943410Snewton
29043410Snewtonstatic int
29183366Sjuliansvr4_ptm_alloc(td)
29283366Sjulian	struct thread *td;
29343410Snewton{
29483366Sjulian	struct proc *p = td->td_proc;
29543410Snewton	/*
29643410Snewton	 * XXX this is very, very ugly.  But I can't find a better
29743410Snewton	 * way that won't duplicate a big amount of code from
29843410Snewton	 * sys_open().  Ho hum...
29943410Snewton	 *
30043410Snewton	 * Fortunately for us, Solaris (at least 2.5.1) makes the
30143410Snewton	 * /dev/ptmx open automatically just open a pty, that (after
30243410Snewton	 * STREAMS I_PUSHes), is just a plain pty.  fstat() is used
30343410Snewton	 * to get the minor device number to map to a tty.
30443410Snewton	 *
30543410Snewton	 * Cycle through the names. If sys_open() returns ENOENT (or
30643410Snewton	 * ENXIO), short circuit the cycle and exit.
30743410Snewton	 */
30843410Snewton	static char ptyname[] = "/dev/ptyXX";
30943410Snewton	static char ttyletters[] = "pqrstuwxyzPQRST";
31043410Snewton	static char ttynumbers[] = "0123456789abcdef";
31143410Snewton	caddr_t sg = stackgap_init();
31243410Snewton	char *path = stackgap_alloc(&sg, sizeof(ptyname));
31343410Snewton	struct open_args oa;
31443410Snewton	int l = 0, n = 0;
31543410Snewton	register_t fd = -1;
31643410Snewton	int error;
31743410Snewton
31843410Snewton	SCARG(&oa, path) = path;
31943410Snewton	SCARG(&oa, flags) = O_RDWR;
32043410Snewton	SCARG(&oa, mode) = 0;
32143410Snewton
32243410Snewton	while (fd == -1) {
32343410Snewton		ptyname[8] = ttyletters[l];
32443410Snewton		ptyname[9] = ttynumbers[n];
32543410Snewton
32643410Snewton		if ((error = copyout(ptyname, path, sizeof(ptyname))) != 0)
32743410Snewton			return error;
32843410Snewton
32983366Sjulian		switch (error = open(td, &oa)) {
33043410Snewton		case ENOENT:
33143410Snewton		case ENXIO:
33243410Snewton			return error;
33343410Snewton		case 0:
33471448Sjhb			PROC_LOCK(p);
33583366Sjulian			td->td_dupfd = td->td_retval[0];
33671448Sjhb			PROC_UNLOCK(p);
33743410Snewton			return ENXIO;
33843410Snewton		default:
33943410Snewton			if (ttynumbers[++n] == '\0') {
34043410Snewton				if (ttyletters[++l] == '\0')
34143410Snewton					break;
34243410Snewton				n = 0;
34343410Snewton			}
34443410Snewton		}
34543410Snewton	}
34643410Snewton	return ENOENT;
34743410Snewton}
34843410Snewton
34943410Snewton
35043410Snewtonstruct svr4_strm *
35143410Snewtonsvr4_stream_get(fp)
35243410Snewton	struct file *fp;
35343410Snewton{
35443410Snewton	struct socket *so;
35543410Snewton	struct svr4_strm *st;
35643410Snewton
35743410Snewton	if (fp == NULL || fp->f_type != DTYPE_SOCKET)
35843410Snewton		return NULL;
35943410Snewton
36043410Snewton	so = (struct socket *) fp->f_data;
36143410Snewton
36289306Salfred	/*
36389306Salfred	 * mpfixme: lock socketbuffer here
36489306Salfred	 */
36589306Salfred	if (so->so_emuldata) {
36643410Snewton		return so->so_emuldata;
36789306Salfred	}
36843410Snewton
36943410Snewton	/* Allocate a new one. */
37043410Snewton	st = malloc(sizeof(struct svr4_strm), M_TEMP, M_WAITOK);
37143410Snewton	st->s_family = so->so_proto->pr_domain->dom_family;
37243410Snewton	st->s_cmd = ~0;
37343410Snewton	st->s_afd = -1;
37443410Snewton	st->s_eventmask = 0;
37589306Salfred	/*
37689306Salfred	 * avoid a race where we loose due to concurrancy issues
37789306Salfred	 * of two threads trying to allocate the so_emuldata.
37889306Salfred	 */
37989306Salfred	if (so->so_emuldata) {
38089306Salfred		/* lost the race, use the existing emuldata */
38189306Salfred		FREE(st, M_TEMP);
38289306Salfred		st = so->so_emuldata;
38389306Salfred	} else {
38489306Salfred		/* we won, or there was no race, use our copy */
38589306Salfred		so->so_emuldata = st;
38689306Salfred		fp->f_ops = &svr4_netops;
38789306Salfred	}
38843410Snewton
38943410Snewton	return st;
39043410Snewton}
39143410Snewton
39243410Snewtonvoid
39343410Snewtonsvr4_delete_socket(p, fp)
39443410Snewton	struct proc *p;
39543410Snewton	struct file *fp;
39643410Snewton{
39743410Snewton	struct svr4_sockcache_entry *e;
39843410Snewton	void *cookie = ((struct socket *) fp->f_data)->so_emuldata;
39943410Snewton
40071448Sjhb	while (svr4_str_initialized != 2) {
40171448Sjhb		if (atomic_cmpset_acq_int(&svr4_str_initialized, 0, 1)) {
40271448Sjhb			TAILQ_INIT(&svr4_head);
40371448Sjhb			atomic_store_rel_int(&svr4_str_initialized, 2);
40471448Sjhb		}
40543410Snewton		return;
40643410Snewton	}
40743410Snewton
40871448Sjhb	TAILQ_FOREACH(e, &svr4_head, entries)
40943410Snewton		if (e->p == p && e->cookie == cookie) {
41043410Snewton			TAILQ_REMOVE(&svr4_head, e, entries);
41143410Snewton			DPRINTF(("svr4_delete_socket: %s [%p,%d,%d]\n",
41285653Sdillon				 e->sock.sun_path, p, (int)e->dev, e->ino));
41343410Snewton			free(e, M_TEMP);
41443410Snewton			return;
41543410Snewton		}
41643410Snewton}
41743410Snewton
41843410Snewtonstatic int
41983366Sjuliansvr4_soo_close(struct file *fp, struct thread *td)
42043410Snewton{
42143410Snewton        struct socket *so = (struct socket *)fp->f_data;
42243410Snewton
42343410Snewton	/*	CHECKUNIT_DIAG(ENXIO);*/
42443410Snewton
42583366Sjulian	svr4_delete_socket(td->td_proc, fp);
42643410Snewton	free(so->so_emuldata, M_TEMP);
42783366Sjulian	return soo_close(fp, td);
42843410Snewton}
429