streams.c revision 83366
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 83366 2001-09-12 08:38:13Z julian $
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
9852114Snewtondev_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
26783366Sjulian	if ((error = socreate(family, &so, type, protocol, td)) != 0) {
26843410Snewton	  p->p_fd->fd_ofiles[fd] = 0;
26943410Snewton	  ffree(fp);
27043410Snewton	  return error;
27143410Snewton	}
27243410Snewton
27349413Sgreen	fp->f_data = (caddr_t)so;
27443410Snewton	fp->f_flag = FREAD|FWRITE;
27549413Sgreen	fp->f_ops = &svr4_netops;
27643410Snewton	fp->f_type = DTYPE_SOCKET;
27743410Snewton
27843410Snewton	(void)svr4_stream_get(fp);
27971448Sjhb	PROC_LOCK(p);
28083366Sjulian	td->td_dupfd = fd;
28171448Sjhb	PROC_UNLOCK(p);
28243410Snewton	return ENXIO;
28343410Snewton}
28443410Snewton
28543410Snewtonstatic int
28683366Sjuliansvr4_ptm_alloc(td)
28783366Sjulian	struct thread *td;
28843410Snewton{
28983366Sjulian	struct proc *p = td->td_proc;
29043410Snewton	/*
29143410Snewton	 * XXX this is very, very ugly.  But I can't find a better
29243410Snewton	 * way that won't duplicate a big amount of code from
29343410Snewton	 * sys_open().  Ho hum...
29443410Snewton	 *
29543410Snewton	 * Fortunately for us, Solaris (at least 2.5.1) makes the
29643410Snewton	 * /dev/ptmx open automatically just open a pty, that (after
29743410Snewton	 * STREAMS I_PUSHes), is just a plain pty.  fstat() is used
29843410Snewton	 * to get the minor device number to map to a tty.
29943410Snewton	 *
30043410Snewton	 * Cycle through the names. If sys_open() returns ENOENT (or
30143410Snewton	 * ENXIO), short circuit the cycle and exit.
30243410Snewton	 */
30343410Snewton	static char ptyname[] = "/dev/ptyXX";
30443410Snewton	static char ttyletters[] = "pqrstuwxyzPQRST";
30543410Snewton	static char ttynumbers[] = "0123456789abcdef";
30643410Snewton	caddr_t sg = stackgap_init();
30743410Snewton	char *path = stackgap_alloc(&sg, sizeof(ptyname));
30843410Snewton	struct open_args oa;
30943410Snewton	int l = 0, n = 0;
31043410Snewton	register_t fd = -1;
31143410Snewton	int error;
31243410Snewton
31343410Snewton	SCARG(&oa, path) = path;
31443410Snewton	SCARG(&oa, flags) = O_RDWR;
31543410Snewton	SCARG(&oa, mode) = 0;
31643410Snewton
31743410Snewton	while (fd == -1) {
31843410Snewton		ptyname[8] = ttyletters[l];
31943410Snewton		ptyname[9] = ttynumbers[n];
32043410Snewton
32143410Snewton		if ((error = copyout(ptyname, path, sizeof(ptyname))) != 0)
32243410Snewton			return error;
32343410Snewton
32483366Sjulian		switch (error = open(td, &oa)) {
32543410Snewton		case ENOENT:
32643410Snewton		case ENXIO:
32743410Snewton			return error;
32843410Snewton		case 0:
32971448Sjhb			PROC_LOCK(p);
33083366Sjulian			td->td_dupfd = td->td_retval[0];
33171448Sjhb			PROC_UNLOCK(p);
33243410Snewton			return ENXIO;
33343410Snewton		default:
33443410Snewton			if (ttynumbers[++n] == '\0') {
33543410Snewton				if (ttyletters[++l] == '\0')
33643410Snewton					break;
33743410Snewton				n = 0;
33843410Snewton			}
33943410Snewton		}
34043410Snewton	}
34143410Snewton	return ENOENT;
34243410Snewton}
34343410Snewton
34443410Snewton
34543410Snewtonstruct svr4_strm *
34643410Snewtonsvr4_stream_get(fp)
34743410Snewton	struct file *fp;
34843410Snewton{
34943410Snewton	struct socket *so;
35043410Snewton	struct svr4_strm *st;
35143410Snewton
35243410Snewton	if (fp == NULL || fp->f_type != DTYPE_SOCKET)
35343410Snewton		return NULL;
35443410Snewton
35543410Snewton	so = (struct socket *) fp->f_data;
35643410Snewton
35743410Snewton       	if (so->so_emuldata)
35843410Snewton		return so->so_emuldata;
35943410Snewton
36043410Snewton	/* Allocate a new one. */
36143410Snewton	st = malloc(sizeof(struct svr4_strm), M_TEMP, M_WAITOK);
36243410Snewton	st->s_family = so->so_proto->pr_domain->dom_family;
36343410Snewton	st->s_cmd = ~0;
36443410Snewton	st->s_afd = -1;
36543410Snewton	st->s_eventmask = 0;
36643410Snewton	so->so_emuldata = st;
36749413Sgreen	fp->f_ops = &svr4_netops;
36843410Snewton
36943410Snewton	return st;
37043410Snewton}
37143410Snewton
37243410Snewtonvoid
37343410Snewtonsvr4_delete_socket(p, fp)
37443410Snewton	struct proc *p;
37543410Snewton	struct file *fp;
37643410Snewton{
37743410Snewton	struct svr4_sockcache_entry *e;
37843410Snewton	void *cookie = ((struct socket *) fp->f_data)->so_emuldata;
37943410Snewton
38071448Sjhb	while (svr4_str_initialized != 2) {
38171448Sjhb		if (atomic_cmpset_acq_int(&svr4_str_initialized, 0, 1)) {
38271448Sjhb			TAILQ_INIT(&svr4_head);
38371448Sjhb			atomic_store_rel_int(&svr4_str_initialized, 2);
38471448Sjhb		}
38543410Snewton		return;
38643410Snewton	}
38743410Snewton
38871448Sjhb	TAILQ_FOREACH(e, &svr4_head, entries)
38943410Snewton		if (e->p == p && e->cookie == cookie) {
39043410Snewton			TAILQ_REMOVE(&svr4_head, e, entries);
39143410Snewton			DPRINTF(("svr4_delete_socket: %s [%p,%d,%d]\n",
39243410Snewton				 e->sock.sun_path, p, e->dev, e->ino));
39343410Snewton			free(e, M_TEMP);
39443410Snewton			return;
39543410Snewton		}
39643410Snewton}
39743410Snewton
39843410Snewtonstatic int
39983366Sjuliansvr4_soo_close(struct file *fp, struct thread *td)
40043410Snewton{
40143410Snewton        struct socket *so = (struct socket *)fp->f_data;
40243410Snewton
40343410Snewton	/*	CHECKUNIT_DIAG(ENXIO);*/
40443410Snewton
40583366Sjulian	svr4_delete_socket(td->td_proc, fp);
40643410Snewton	free(so->so_emuldata, M_TEMP);
40783366Sjulian	return soo_close(fp, td);
40843410Snewton	return (0);
40943410Snewton}
410