streams.c revision 52987
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 52987 1999-11-08 03:34:53Z peter $
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
5743410Snewton#include <svr4/svr4_types.h>
5843410Snewton#include <svr4/svr4_util.h>
5943410Snewton#include <svr4/svr4_signal.h>
6043410Snewton#include <svr4/svr4_ioctl.h>
6143410Snewton#include <svr4/svr4_stropts.h>
6243410Snewton#include <svr4/svr4_socket.h>
6343410Snewton
6443410Snewtonstatic int svr4_soo_close __P((struct file *, struct proc *));
6543410Snewtonstatic int svr4_ptm_alloc __P((struct proc *));
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	*/
7443410Snewton	TAILQ_ENTRY(svr4_sockcache_entry) entries;
7543410Snewton};
7643410Snewton
7743410SnewtonTAILQ_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 = {
10252987Speter	soo_read, soo_write, soo_ioctl, soo_poll, soo_stat, svr4_soo_close
10343410Snewton};
10443410Snewton
10543410Snewton#define CDEV_MAJOR 103
10643410Snewtonstatic struct cdevsw streams_cdevsw = {
10747625Sphk	/* open */	streamsopen,
10847625Sphk	/* close */	noclose,
10947625Sphk	/* read */	noread,
11047625Sphk	/* write */	nowrite,
11147625Sphk	/* ioctl */	noioctl,
11247625Sphk	/* poll */	nopoll,
11347625Sphk	/* mmap */	nommap,
11447625Sphk	/* strategy */	nostrategy,
11547625Sphk	/* name */	"streams",
11647625Sphk	/* maj */	CDEV_MAJOR,
11747625Sphk	/* dump */	nodump,
11847625Sphk	/* psize */	nopsize,
11947625Sphk	/* flags */	0,
12047625Sphk	/* bmaj */	-1
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 */
16752114Snewton		remove_dev(dt_ptm);
16852114Snewton		remove_dev(dt_arp);
16952114Snewton		remove_dev(dt_icmp);
17052114Snewton		remove_dev(dt_ip);
17152114Snewton		remove_dev(dt_tcp);
17252114Snewton		remove_dev(dt_udp);
17352114Snewton		remove_dev(dt_rawip);
17452114Snewton		remove_dev(dt_unix_dgram);
17552114Snewton		remove_dev(dt_unix_stream);
17652114Snewton		remove_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);
19144208Snewton
19243410Snewton/*
19343410Snewton * We only need open() and close() routines.  open() calls socreate()
19443410Snewton * to allocate a "real" object behind the stream and mallocs some state
19543410Snewton * info for use by the svr4 emulator;  close() deallocates the state
19643410Snewton * information and passes the underlying object to the normal socket close
19743410Snewton * routine.
19843410Snewton */
19943410Snewtonstatic  int
20043410Snewtonstreamsopen(dev_t dev, int oflags, int devtype, struct proc *p)
20143410Snewton{
20243410Snewton	int type, protocol;
20343410Snewton	int fd;
20443410Snewton	struct file *fp;
20543410Snewton	struct socket *so;
20643410Snewton	int error;
20743410Snewton	int family;
20843410Snewton
20943410Snewton	if (p->p_dupfd >= 0)
21043410Snewton	  return ENODEV;
21143410Snewton
21243410Snewton	switch (minor(dev)) {
21343410Snewton	case dev_udp:
21443410Snewton	  family = AF_INET;
21543410Snewton	  type = SOCK_DGRAM;
21643410Snewton	  protocol = IPPROTO_UDP;
21743410Snewton	  break;
21843410Snewton
21943410Snewton	case dev_tcp:
22043410Snewton	  family = AF_INET;
22143410Snewton	  type = SOCK_STREAM;
22243410Snewton	  protocol = IPPROTO_TCP;
22343410Snewton	  break;
22443410Snewton
22543410Snewton	case dev_ip:
22643410Snewton	case dev_rawip:
22743410Snewton	  family = AF_INET;
22843410Snewton	  type = SOCK_RAW;
22943410Snewton	  protocol = IPPROTO_IP;
23043410Snewton	  break;
23143410Snewton
23243410Snewton	case dev_icmp:
23343410Snewton	  family = AF_INET;
23443410Snewton	  type = SOCK_RAW;
23543410Snewton	  protocol = IPPROTO_ICMP;
23643410Snewton	  break;
23743410Snewton
23843410Snewton	case dev_unix_dgram:
23943410Snewton	  family = AF_LOCAL;
24043410Snewton	  type = SOCK_DGRAM;
24143410Snewton	  protocol = 0;
24243410Snewton	  break;
24343410Snewton
24443410Snewton	case dev_unix_stream:
24543410Snewton	case dev_unix_ord_stream:
24643410Snewton	  family = AF_LOCAL;
24743410Snewton	  type = SOCK_STREAM;
24843410Snewton	  protocol = 0;
24943410Snewton	  break;
25043410Snewton
25143410Snewton	case dev_ptm:
25243410Snewton	  return svr4_ptm_alloc(p);
25343410Snewton
25443410Snewton	default:
25543410Snewton	  return EOPNOTSUPP;
25643410Snewton	}
25743410Snewton
25843410Snewton	if ((error = falloc(p, &fp, &fd)) != 0)
25943410Snewton	  return error;
26043410Snewton
26143410Snewton	if ((error = socreate(family, &so, type, protocol, p)) != 0) {
26243410Snewton	  p->p_fd->fd_ofiles[fd] = 0;
26343410Snewton	  ffree(fp);
26443410Snewton	  return error;
26543410Snewton	}
26643410Snewton
26749413Sgreen	fp->f_data = (caddr_t)so;
26843410Snewton	fp->f_flag = FREAD|FWRITE;
26949413Sgreen	fp->f_ops = &svr4_netops;
27043410Snewton	fp->f_type = DTYPE_SOCKET;
27143410Snewton
27243410Snewton	(void)svr4_stream_get(fp);
27343410Snewton	p->p_dupfd = fd;
27443410Snewton	return ENXIO;
27543410Snewton}
27643410Snewton
27743410Snewtonstatic int
27843410Snewtonsvr4_ptm_alloc(p)
27943410Snewton	struct proc *p;
28043410Snewton{
28143410Snewton	/*
28243410Snewton	 * XXX this is very, very ugly.  But I can't find a better
28343410Snewton	 * way that won't duplicate a big amount of code from
28443410Snewton	 * sys_open().  Ho hum...
28543410Snewton	 *
28643410Snewton	 * Fortunately for us, Solaris (at least 2.5.1) makes the
28743410Snewton	 * /dev/ptmx open automatically just open a pty, that (after
28843410Snewton	 * STREAMS I_PUSHes), is just a plain pty.  fstat() is used
28943410Snewton	 * to get the minor device number to map to a tty.
29043410Snewton	 *
29143410Snewton	 * Cycle through the names. If sys_open() returns ENOENT (or
29243410Snewton	 * ENXIO), short circuit the cycle and exit.
29343410Snewton	 */
29443410Snewton	static char ptyname[] = "/dev/ptyXX";
29543410Snewton	static char ttyletters[] = "pqrstuwxyzPQRST";
29643410Snewton	static char ttynumbers[] = "0123456789abcdef";
29743410Snewton	caddr_t sg = stackgap_init();
29843410Snewton	char *path = stackgap_alloc(&sg, sizeof(ptyname));
29943410Snewton	struct open_args oa;
30043410Snewton	int l = 0, n = 0;
30143410Snewton	register_t fd = -1;
30243410Snewton	int error;
30343410Snewton
30443410Snewton	SCARG(&oa, path) = path;
30543410Snewton	SCARG(&oa, flags) = O_RDWR;
30643410Snewton	SCARG(&oa, mode) = 0;
30743410Snewton
30843410Snewton	while (fd == -1) {
30943410Snewton		ptyname[8] = ttyletters[l];
31043410Snewton		ptyname[9] = ttynumbers[n];
31143410Snewton
31243410Snewton		if ((error = copyout(ptyname, path, sizeof(ptyname))) != 0)
31343410Snewton			return error;
31443410Snewton
31543410Snewton		switch (error = open(p, &oa)) {
31643410Snewton		case ENOENT:
31743410Snewton		case ENXIO:
31843410Snewton			return error;
31943410Snewton		case 0:
32043410Snewton			p->p_dupfd = p->p_retval[0];
32143410Snewton			return ENXIO;
32243410Snewton		default:
32343410Snewton			if (ttynumbers[++n] == '\0') {
32443410Snewton				if (ttyletters[++l] == '\0')
32543410Snewton					break;
32643410Snewton				n = 0;
32743410Snewton			}
32843410Snewton		}
32943410Snewton	}
33043410Snewton	return ENOENT;
33143410Snewton}
33243410Snewton
33343410Snewton
33443410Snewtonstruct svr4_strm *
33543410Snewtonsvr4_stream_get(fp)
33643410Snewton	struct file *fp;
33743410Snewton{
33843410Snewton	struct socket *so;
33943410Snewton	struct svr4_strm *st;
34043410Snewton
34143410Snewton	if (fp == NULL || fp->f_type != DTYPE_SOCKET)
34243410Snewton		return NULL;
34343410Snewton
34443410Snewton	so = (struct socket *) fp->f_data;
34543410Snewton
34643410Snewton       	if (so->so_emuldata)
34743410Snewton		return so->so_emuldata;
34843410Snewton
34943410Snewton	/* Allocate a new one. */
35043410Snewton	st = malloc(sizeof(struct svr4_strm), M_TEMP, M_WAITOK);
35143410Snewton	st->s_family = so->so_proto->pr_domain->dom_family;
35243410Snewton	st->s_cmd = ~0;
35343410Snewton	st->s_afd = -1;
35443410Snewton	st->s_eventmask = 0;
35543410Snewton	so->so_emuldata = st;
35649413Sgreen	fp->f_ops = &svr4_netops;
35743410Snewton
35843410Snewton	return st;
35943410Snewton}
36043410Snewton
36143410Snewtonvoid
36243410Snewtonsvr4_delete_socket(p, fp)
36343410Snewton	struct proc *p;
36443410Snewton	struct file *fp;
36543410Snewton{
36643410Snewton	struct svr4_sockcache_entry *e;
36743410Snewton	void *cookie = ((struct socket *) fp->f_data)->so_emuldata;
36843410Snewton
36943410Snewton	if (!svr4_str_initialized) {
37043410Snewton		TAILQ_INIT(&svr4_head);
37143410Snewton		svr4_str_initialized = 1;
37243410Snewton		return;
37343410Snewton	}
37443410Snewton
37543410Snewton	for (e = svr4_head.tqh_first; e != NULL; e = e->entries.tqe_next)
37643410Snewton		if (e->p == p && e->cookie == cookie) {
37743410Snewton			TAILQ_REMOVE(&svr4_head, e, entries);
37843410Snewton			DPRINTF(("svr4_delete_socket: %s [%p,%d,%d]\n",
37943410Snewton				 e->sock.sun_path, p, e->dev, e->ino));
38043410Snewton			free(e, M_TEMP);
38143410Snewton			return;
38243410Snewton		}
38343410Snewton}
38443410Snewton
38543410Snewtonstatic int
38643410Snewtonsvr4_soo_close(struct file *fp, struct proc *p)
38743410Snewton{
38843410Snewton        struct socket *so = (struct socket *)fp->f_data;
38943410Snewton
39043410Snewton	/*	CHECKUNIT_DIAG(ENXIO);*/
39143410Snewton
39243410Snewton	svr4_delete_socket(p, fp);
39343410Snewton	free(so->so_emuldata, M_TEMP);
39443410Snewton	return soo_close(fp, p);
39543410Snewton	return (0);
39643410Snewton}
397