OpenBSD Ethertap Support FOR OpenBSD 3.3

http://diehard.n-r-g.com/

Here is port of FreeBSD tap(4) - Ethernet tunnel software network interface.
I tested it on a i386 and sparc64. It does not implement all of the features of
FreeBSDs tap(4) driver, mainly the VMware stuff is probably not fully
functional.

You can apply the patch with:
	cd /sys
	patch -p0 < tap-3.3-20031016.patch
	
This will install the two new files if_tap.c and if_tap.h and modify
multiple configuration files (sys/conf.h, conf/files and the architecture
dependent conf.c file).
The patch was tested on i386 and sparc64 and for those two architectures I
have added the conf.c change. On other architectures the file 
/sys/arch/$ARCH/$ARCH/conf.c needs to be modified. You can use the i386 file
and the tun definitions as template.
NOTE: I'm currently not able to test the 3.3 version because I do no longer
have such a test system.

Next, you need to add the following line to your kernel config:
        pseudo-device tap N
where N is the number of tap devices you would like to have. 1 or 2 should
normally be enough. Now reconfigure and rebuild your kernel:
	config GENERIC
	make depend && make

Install the new kernel and reboot. An 'ifconfig -a' should now list
the new tap interface, if not you probably did not add the pseudo-device
directive to the kernel config.
Last but not least make the /dev/tap0 device by issuing the following command:
	mknod /dev/tap0 c 44 0 # for the first tap interface
	mknod /dev/tap0 c 44 1 # for the second tap interface
and so on until N-1

Untested are at the moment:
 - ALTQ integration
 - VMware support
 - non-INET protocols

Index: arch/i386/i386/conf.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/conf.c,v
retrieving revision 1.104
diff -u -p -r1.104 conf.c
--- arch/i386/i386/conf.c	23 Sep 2003 16:51:11 -0000	1.104
+++ arch/i386/i386/conf.c	16 Oct 2003 15:44:58 -0000
@@ -159,6 +159,7 @@ cdev_decl(pms);
 cdev_decl(cy);
 cdev_decl(mcd);
 #include "tun.h"
+#include "tap.h"
 #include "audio.h"
 #include "midi.h"
 #include "sequencer.h"
@@ -264,7 +265,7 @@ struct cdevsw	cdevsw[] =
 #else
 	cdev_notdef(),			/* 43 */
 #endif
-	cdev_notdef(),			/* 44 */
+	cdev_bpftun_init(NTAP,tap),	/* 44: XXX hijacked for now */
 	cdev_random_init(1,random),	/* 45: random data source */
 	cdev_ocis_init(NPCTR,pctr),	/* 46: pentium performance counters */
 	cdev_disk_init(NRD,rd),		/* 47: ram disk driver */
Index: arch/sparc64/sparc64/conf.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/sparc64/conf.c,v
retrieving revision 1.36
diff -u -p -r1.36 conf.c
--- arch/sparc64/sparc64/conf.c	27 Jun 2003 16:57:14 -0000	1.36
+++ arch/sparc64/sparc64/conf.c	16 Oct 2003 15:45:01 -0000
@@ -54,6 +54,7 @@
 #include "pty.h"
 #include "bpfilter.h"
 #include "tun.h"
+#include "tap.h"
 #include "audio.h"
 #include "vnd.h"
 #include "ccd.h"
@@ -199,7 +200,7 @@ struct cdevsw	cdevsw[] =
 	cdev_notdef(),			/* 41 */
 	cdev_notdef(),			/* 42: SMD disk */
 	cdev_svr4_net_init(NSVR4_NET,svr4_net),	/* 43: svr4 net pseudo-device */
-	cdev_notdef(),			/* 44 */
+	cdev_bpftun_init(NTAP,tap),	/* 44: XXX hijacked for now */
 	cdev_notdef(),			/* 45 */
 	cdev_notdef(),			/* 46 */
 	cdev_notdef(),			/* 47 */
Index: conf/files
===================================================================
RCS file: /cvs/src/sys/conf/files,v
retrieving revision 1.282
diff -u -p -r1.282 files
--- conf/files	7 Oct 2003 07:08:45 -0000	1.282
+++ conf/files	16 Oct 2003 15:45:01 -0000
@@ -355,6 +355,7 @@ pseudo-device loop: ifnet
 pseudo-device sl: ifnet
 pseudo-device ppp: ifnet
 pseudo-device tun: ifnet
+pseudo-device tap: ifnet
 pseudo-device bpfilter: ifnet
 pseudo-device strip: ifnet
 pseudo-device enc: ifnet
@@ -649,6 +650,7 @@ file net/ppp-deflate.c			ppp_deflate
 file net/zlib.c				ppp_deflate | ipsec | crypto
 file net/if_tokensubr.c			token			needs-flag
 file net/if_tun.c			tun			needs-count
+file net/if_tap.c			tap			needs-count
 file net/if_bridge.c			bridge			needs-count
 file net/bridgestp.c			bridge
 file net/if_vlan.c			vlan			needs-count
Index: sys/conf.h
===================================================================
RCS file: /cvs/src/sys/sys/conf.h,v
retrieving revision 1.72
diff -u -p -r1.72 conf.h
--- sys/conf.h	23 Sep 2003 16:51:13 -0000	1.72
+++ sys/conf.h	16 Oct 2003 15:45:03 -0000
@@ -581,6 +581,7 @@ cdev_decl(bpf);
 cdev_decl(pf);
 
 cdev_decl(tun);
+cdev_decl(tap);
 
 cdev_decl(random);
 
--- net/if_tap.h	Thu Jan  1 01:00:00 1970
+++ net/if_tap.h	Wed Oct 15 16:28:58 2003
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BASED ON:
+ * -------------------------------------------------------------------------
+ *
+ * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
+ * Nottingham University 1987.
+ */
+
+/*
+ * $OpenBSD$
+ * $FreeBSD: src/sys/net/if_tap.h,v 1.1 2000/07/20 17:01:10 nsayer Exp $
+ * $Id: if_tap.h,v 0.7 2000/07/12 04:12:51 max Exp $
+ */
+
+/*
+ * Ported to OpenBSD by Claudio Jeker.
+ */
+
+#ifndef _NET_IF_TAP_H_
+#define _NET_IF_TAP_H_
+
+/* maximum receive packet size (hard limit) */
+#define	TAPMRU		16384
+
+/* known TAP flags */
+#define	TAP_OPEN	(1 << 0)
+#define	TAP_INITED	(1 << 1)
+#define	TAP_RWAIT	(1 << 2)
+#define	TAP_ASYNC	(1 << 3)
+#define TAP_READY       (TAP_OPEN|TAP_INITED)
+#define	TAP_VMNET	(1 << 4)
+#define	TAP_NBIO	(1 << 5)
+#define	TAP_STAYUP	(1 << 6)
+
+struct tapinfo {
+	int	baudrate;	/* linespeed                 */
+	short	mtu;		/* maximum transmission unit */
+	u_char	type;		/* ethernet, tokenring, etc. */
+	u_char	flags;		/* tap flags */
+};
+
+/* ioctl's for get/set debug */
+#define	TAPSDEBUG		_IOW('t', 90, int)
+#define	TAPGDEBUG		_IOR('t', 89, int)
+#define	TAPSIFINFO		_IOW('t', 91, struct tapinfo)
+#define	TAPGIFINFO		_IOR('t', 92, struct tapinfo)
+
+/* VMware ioctl's */
+#define VMIO_SIOCSIFFLAGS	_IO('V', 0)
+#define VMIO_SIOCSKEEP		_IO('V', 1)
+#define VMIO_SIOCSIFBR		_IO('V', 2)
+#define VMIO_SIOCSLADRF		_IO('V', 3)
+
+/* XXX -- unimplemented */
+#define VMIO_SIOCSETMACADDR	_IO('V', 4)
+
+/* XXX -- not used? */
+#define VMIO_SIOCPORT		_IO('V', 5)
+#define VMIO_SIOCBRIDGE		_IO('V', 6)
+#define VMIO_SIOCNETIF		_IO('V', 7)
+
+#endif /* !_NET_IF_TAP_H_ */
--- net/if_tap.c	Thu Jan  1 01:00:00 1970
+++ net/if_tap.c	Wed Oct 15 16:28:58 2003
@@ -0,0 +1,650 @@
+/*
+ * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BASED ON:
+ * -------------------------------------------------------------------------
+ *
+ * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
+ * Nottingham University 1987.
+ */
+
+/*
+ * $OpenBSD$
+ * $FreeBSD: src/sys/net/if_tap.c,v 1.4 2000/09/19 10:28:41 phk Exp $
+ * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $
+ */
+
+/*
+ * Ported to OpenBSD by Claudio Jeker <cjeker@diehard.n-r-g.com>
+ */
+/* #define TAP_DEBUG 1 */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/device.h>
+#include <sys/vnode.h>
+#include <sys/signalvar.h>
+#include <sys/poll.h>
+#include <sys/conf.h>
+
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h> 
+#endif
+
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+
+#include <net/if_tap.h>
+
+struct tap_softc {
+	struct	arpcom arpcom;		/* ethernet common data */
+#define tap_if		arpcom.ac_if
+
+	u_short tap_flags;		/* misc flags */
+	u_int8_t ether_addr[ETHER_ADDR_LEN]; /* ether addr of the remote side */
+	/* information needed for async IO */
+	pid_t tap_pgid;			/* the process group - if any */
+	uid_t tap_siguid;		/* uid for process that set tun_pgid */
+	uid_t tap_sigeuid;		/* euid for process that set tun_pgid */
+	struct	selinfo	tap_rsel;	/* read select */
+	struct	selinfo	tap_wsel;	/* write select (not used) */
+};
+
+#ifdef	TAP_DEBUG
+int	tapdebug = TAP_DEBUG;
+#define TAPDEBUG(a)	(tapdebug? printf a : 0)
+#else
+#define TAPDEBUG(a)	/* (tapdebug? printf a : 0) */
+#endif
+
+struct	tap_softc *tapctl;
+int ntap;
+
+extern int ifqmaxlen;
+
+void	tapattach(int);
+int	tapopen(dev_t, int, int, struct proc *);
+int	tapclose(dev_t, int, int, struct proc *);
+int	tapifioctl(struct ifnet *, u_long, caddr_t);
+int	tapioctl(dev_t, u_long, caddr_t, int, struct proc *);
+int	tapread(dev_t, struct uio *, int);
+int	tapwrite(dev_t, struct uio *, int);
+int	tapselect(dev_t, int, struct proc *);
+int	tapkqfilter(dev_t, struct knote *);
+
+
+static int tapinit(struct tap_softc *);
+static void tapifstart(struct ifnet *);
+
+void
+tapattach(int n)
+{
+	int		i;
+	struct ifnet	*ifp;
+	u_int32_t	macaddr_rnd;
+
+	ntap = n;
+	tapctl = malloc(ntap * sizeof(*tapctl), M_DEVBUF, M_WAITOK);
+	bzero(tapctl, ntap * sizeof(*tapctl));
+	for (i = 0; i < ntap; i++) {
+		tapctl[i].tap_flags = TAP_INITED;
+
+		/* generate fake MAC address: 00 bd xx xx xx unit_no */
+		tapctl[i].arpcom.ac_enaddr[0] = 0x00;
+		tapctl[i].arpcom.ac_enaddr[1] = 0xbd;
+		/*
+		 * XXX use of random() by anything except the scheduler is
+		 * normally invalid, but this is boot time, so pre-scheduler,
+		 * and the random subsystem is not alive yet
+		 */
+		macaddr_rnd = random();
+		bcopy(&macaddr_rnd, &tapctl[i].arpcom.ac_enaddr[2],
+		    sizeof(u_int32_t));
+		tapctl[i].arpcom.ac_enaddr[5] = (u_char)i+1;
+		
+		ifp = &tapctl[i].tap_if;
+		snprintf(ifp->if_xname, sizeof ifp->if_xname, "tap%d", i);
+		ifp->if_softc = &tapctl[i];
+		ifp->if_mtu = ETHERMTU;
+		ifp->if_ioctl = tapifioctl;
+		ifp->if_output = ether_output;
+		ifp->if_start = tapifstart;
+		ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
+		IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
+		IFQ_SET_READY(&ifp->if_snd);
+		if_attach(ifp);
+		ether_ifattach(ifp);
+		
+	}
+}
+
+
+/*
+ * tap open - must be superuser & the device must be
+ * configured in
+ */
+int
+tapopen(dev_t dev, int flag, int mode, struct proc *p)
+{
+	struct tap_softc *tp;
+	struct ifnet	*ifp;
+	int		unit, error;
+
+	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
+		return (error);
+
+	if ((unit = minor(dev)) >= ntap)
+		return (ENXIO);
+
+	tp = &tapctl[unit];
+	if (tp->tap_flags & TAP_OPEN)
+		return EBUSY;
+
+	ifp = &tp->tap_if;
+	bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
+	tp->tap_flags |= TAP_OPEN;
+	tapinit(tp);
+	TAPDEBUG(("%s: open\n", ifp->if_xname));
+	return (0);
+}
+
+/*
+ * tapclose - close the device; if closing the real device, flush pending
+ *  output and (unless set STAYUP) bring down the interface.
+ */
+int
+tapclose(dev_t dev, int flag, int mode,	struct	proc *p)
+{
+	int		unit, s;
+	struct tap_softc *tp;
+	struct ifnet	*ifp;
+
+	if ((unit = minor(dev)) >= ntap)
+		return (ENXIO);
+
+	tp = &tapctl[unit];
+	ifp = &tp->tap_if;
+	tp->tap_flags &= ~TAP_OPEN;
+
+	/*
+	 * junk all pending output
+	 */
+	s = splimp();
+	IFQ_PURGE(&ifp->if_snd);
+	splx(s);
+
+	if ((ifp->if_flags & IFF_UP) && !(tp->tap_flags & TAP_STAYUP)) {
+		s = splimp();
+		if_down(ifp);
+		if (ifp->if_flags & IFF_RUNNING) {
+			/* find internet addresses and delete routes */
+			struct ifaddr *ifa;
+			TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
+#ifdef INET
+				if (ifa->ifa_addr->sa_family == AF_INET) {
+					rtinit(ifa, (int)RTM_DELETE, 0);
+				}
+#endif
+				/* XXX INET6 and other protocols ? */
+			}
+		}
+		splx(s);
+	}
+	tp->tap_pgid = 0;
+	selwakeup(&tp->tap_rsel);
+		
+	TAPDEBUG(("%s: closed\n", ifp->if_xname));
+	return (0);
+}
+
+/*
+ * network interface initialization function
+ */
+static int
+tapinit(struct tap_softc *tp)
+{
+	struct	ifnet *ifp = &tp->tap_if;
+
+	TAPDEBUG(("%s: tapinit\n", ifp->if_xname));
+	TAPDEBUG(("%s: ethernet address: %s\n", ifp->if_xname,
+		    ether_sprintf(tp->arpcom.ac_enaddr)));
+
+	ifp->if_flags |= IFF_UP | IFF_RUNNING;
+	ifp->if_flags &= ~IFF_OACTIVE; /* we are never active */
+
+	return 0;
+}
+
+/*
+ * Process an ioctl request on network interface
+ */
+int
+tapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+	struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc);
+	struct ifreq	*ifr = (struct ifreq *) data;
+	struct ifaddr	*ifa = (struct ifaddr *)data;
+	int		error = 0, s;
+
+	s = splimp();
+	if ((error = ether_ioctl(ifp, &tp->arpcom, cmd, data)) > 0) {
+		splx(s);
+		return (error);
+	}
+	switch (cmd) {
+	case SIOCSIFADDR:
+		tapinit(tp);
+		switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+		case AF_INET:
+			arp_ifinit(&tp->arpcom, ifa);
+			break;
+#endif
+		default:
+			break;
+		}
+		break;
+	case SIOCSIFMTU:
+		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > 16384)
+			error = EINVAL;
+		else {
+			ifp->if_mtu = ifr->ifr_mtu;
+		}
+		break;
+	case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		break;
+	/*
+	 * CJ - I'm not interested in vmnet I will add it somewhen,
+	 * but first I need to test it. Currently I don't have a test app.
+	 */
+#if 0
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		error = (command == SIOCADDMULTI) ?
+		    ether_addmulti(ifr, &tp->arpcom) :
+		    ether_delmulti(ifr, &tp->arpcom);
+		if (error == ENETRESET) {
+			/*
+			 * Multicast list has changed; set the hardware
+			 * filter accordingly. The good thing is we do 
+			 * not have a hardware filter (:
+			 */
+			error = 0;
+		}
+		break;
+	/* XXX stuff that could be cool */
+	case SIOCSIFPHYADDR:
+		break;
+#endif
+	default:
+		error = EINVAL;
+	}
+	splx(s);
+	return (error);
+}
+
+/*
+ * the cdevsw interface is now pretty minimal.
+ */
+int
+tapioctl(dev_t dev, u_long cmd, caddr_t data, int flag,	struct proc *p)
+{
+	int		unit, s;
+	struct tap_softc *tp;
+	struct tapinfo	*tapp;
+	struct ifnet	*ifp;
+	struct mbuf	*m;
+	
+	if ((unit = minor(dev)) >= ntap)
+		return (ENXIO);
+
+	tp = &tapctl[unit];
+
+	ifp = &tp->tap_if;
+
+	s = splimp();
+	switch (cmd) {
+	case TAPSIFINFO:
+		tapp = (struct tapinfo *)data;
+		ifp->if_baudrate = tapp->baudrate;
+		ifp->if_mtu = tapp->mtu;
+		ifp->if_type = tapp->type;
+		ifp->if_flags = tapp->flags;
+		break;
+	case TAPGIFINFO:
+		tapp = (struct tapinfo *)data;
+		tapp->baudrate = ifp->if_baudrate;
+		tapp->mtu = ifp->if_mtu;
+		tapp->type = ifp->if_type;
+		ifp->if_flags = tapp->flags;
+		break;
+#ifdef TAP_DEBUG
+	case TAPSDEBUG:
+		tapdebug = *(int *)data;
+		break;
+	case TAPGDEBUG:
+		*(int *)data = tapdebug;
+		break;
+#endif
+	case FIONBIO:
+		if (*(int *)data)
+			tp->tap_flags |= TAP_NBIO;
+		else
+			tp->tap_flags &= ~TAP_NBIO;
+		break;
+	case FIOASYNC:
+		if (*(int *)data)
+			tp->tap_flags |= TAP_ASYNC;
+		else
+			tp->tap_flags &= ~TAP_ASYNC;
+		break;
+	case FIONREAD:
+		IFQ_POLL(&tp->tap_if.if_snd, m);
+		if (m != NULL)
+			*(int *)data = m->m_pkthdr.len;
+		else	
+			*(int *)data = 0;
+		break;
+	case TIOCSPGRP:
+		tp->tap_pgid = *(int *)data;
+		tp->tap_siguid = p->p_cred->p_ruid;
+		tp->tap_sigeuid = p->p_ucred->cr_uid;
+		break;
+	case TIOCGPGRP:
+		*(int *)data = tp->tap_pgid;
+		break;
+
+	/* VMware/VMnet port ioctl's */
+	case SIOCGIFFLAGS:	/* get ifnet flags */
+		bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
+		break;
+	case VMIO_SIOCSIFFLAGS:
+	    {	/* VMware/VMnet SIOCSIFFLAGS */
+		short	f = *(short *)data;
+
+		f &= 0x0fff;
+		f &= ~IFF_CANTCHANGE;
+		f |= IFF_UP;
+
+		ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
+	    }
+		break;
+	case OSIOCGIFADDR:	/* get MAC address of the remote side */
+	case SIOCGIFADDR:	/* NOTE: this is the user program view */
+		bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
+		break;
+	case SIOCSIFADDR:	/* set MAC address of the remote side */
+		bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
+		break;
+	default:
+		splx(s);
+		return (ENOTTY);
+	}
+	splx(s);
+	return (0);
+}
+
+
+/*
+ * The cdevsw read interface - reads a packet at a time, or at
+ * least as much of a packet as can be read.
+ */
+int
+tapread(dev_t dev, struct uio *uio, int ioflag)
+{
+	int		unit;
+	struct tap_softc *tp;
+	struct ifnet	*ifp;
+	struct mbuf	*m, *m0;
+	int		error = 0, len, s;
+
+	if ((unit = minor(dev)) >= ntap)
+		return (ENXIO);
+
+	tp = &tapctl[unit];
+	ifp = &tp->tap_if;
+	TAPDEBUG(("%s: read\n", ifp->if_xname));
+	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
+		TAPDEBUG(("%s: not ready 0%o\n", ifp->if_xname,
+			  tp->tap_flags));
+		return EHOSTDOWN;
+	}
+
+	tp->tap_flags &= ~TAP_RWAIT;
+
+	s = splimp();
+	do {
+		while ((tp->tap_flags & TAP_READY) != TAP_READY)
+			if ((error = tsleep((caddr_t)tp,
+			    (PZERO+1)|PCATCH, "tapread", 0)) != 0) {
+				splx(s);
+				return (error);
+			}
+		IFQ_DEQUEUE(&ifp->if_snd, m0);
+		if (m0 == 0) {
+			if (tp->tap_flags & TAP_NBIO && ioflag & IO_NDELAY) {
+				splx(s);
+				return EWOULDBLOCK;
+			}
+			tp->tap_flags |= TAP_RWAIT;
+			if ((error = tsleep((caddr_t)tp,
+			    (PZERO + 1)|PCATCH, "tapread", 0)) != 0) {
+				splx(s);
+				return (error);
+			}
+		}
+	} while (m0 == NULL);
+	splx(s);
+
+#if NBPFILTER > 0
+	/* feed packet to bpf */
+	if (ifp->if_bpf != NULL)
+		bpf_mtap(ifp->if_bpf, m0);
+#endif
+
+	/* xfer packet to user space */
+	while (m0 && uio->uio_resid > 0 && error == 0) {
+		len = min(uio->uio_resid, m0->m_len);
+		if (len != 0)
+			error = uiomove(mtod(m0, caddr_t), len, uio);
+		MFREE(m0, m);
+		m0 = m;
+	}
+
+	if (m0) {
+		TAPDEBUG(("Dropping mbuf\n"));
+		m_freem(m0);
+	}
+	if (error)
+		ifp->if_ierrors++;
+
+	return error;
+}
+
+/*
+ * the cdevsw write interface - an atomic write is a packet - or else!
+ */
+int
+tapwrite(dev_t dev, struct uio *uio, int ioflag)
+{
+	int unit;
+	struct	ifnet *ifp;
+	struct	mbuf *top, **mp, *m;
+	int error=0, tlen, mlen;
+
+	if ((unit = minor(dev)) >= ntap)
+		return (ENXIO);
+
+	ifp = &tapctl[unit].tap_if;
+	TAPDEBUG(("%s: tapwrite\n", ifp->if_xname));
+
+	if (uio->uio_resid == 0 || uio->uio_resid > TAPMRU) {
+		TAPDEBUG(("%s: len=%d!\n", ifp->if_xname, uio->uio_resid));
+		return EMSGSIZE;
+	}
+	tlen = uio->uio_resid;
+
+	/* get a header mbuf */
+	MGETHDR(m, M_DONTWAIT, MT_DATA);
+	if (m == NULL)
+		return ENOBUFS;
+	mlen = MHLEN;
+
+	top = 0;
+	mp = &top;
+	while (error == 0 && uio->uio_resid > 0) {
+		m->m_len = min(mlen, uio->uio_resid);
+		error = uiomove(mtod (m, caddr_t), m->m_len, uio);
+		*mp = m;
+		mp = &m->m_next;
+		if (uio->uio_resid > 0) {
+			MGET (m, M_DONTWAIT, MT_DATA);
+			if (m == 0) {
+				error = ENOBUFS;
+				break;
+			}
+			mlen = MLEN;
+		}
+	}
+	if (error) {
+		if (top)
+			m_freem (top);
+		ifp->if_ierrors++;
+		return error;
+	}
+
+	top->m_pkthdr.len = tlen;
+	top->m_pkthdr.rcvif = ifp;
+	/*
+	 * Ethernet bridge is handled in ether_input but bpf isn't
+	 */
+#if NBPFILTER > 0
+	if (ifp->if_bpf)
+		bpf_mtap(ifp->if_bpf, top);
+#endif /* NBPFILTER > 0 */ 
+
+	ether_input_mbuf(ifp, top);
+	ifp->if_ipackets++; /* ibytes are counted in ether_input */
+
+	return (0);
+}
+
+/*
+ * tapselect - the select interface, this is only useful on reads
+ * really. The write detect always returns true, write never blocks
+ * anyway, it either accepts the packet or drops it.
+ */
+int
+tapselect(dev_t dev, int rw, struct proc *p)
+{
+	int		unit, s;
+	struct tap_softc *tp;
+	struct ifnet	*ifp;
+
+	if ((unit = minor(dev)) >= ntap)
+		return (ENXIO);
+
+	tp = &tapctl[unit];
+	ifp = &tp->tap_if;
+	s = splimp();
+	TAPDEBUG(("%s: tapselect\n", ifp->if_xname));
+
+	switch (rw) {
+	case FREAD:
+		if (ifp->if_snd.ifq_len > 0) {
+			splx(s);
+			TAPDEBUG(("%s: tapselect q=%d\n", ifp->if_xname,
+				  ifp->if_snd.ifq_len));
+			return 1;
+		}
+		selrecord(curproc, &tp->tap_rsel);
+		break;
+	case FWRITE:
+		splx(s);
+		return 1;
+	}
+	splx(s);
+	TAPDEBUG(("%s: tapselect waiting\n", ifp->if_xname));
+	return 0;
+}
+
+/* Does not currently work */
+
+int
+tapkqfilter(dev_t dev, struct knote *kn)
+{
+	return (1);
+}
+
+/*
+ * Start packet transmission on the interface.
+ */
+static void
+tapifstart(struct ifnet *ifp)
+{
+	struct	tap_softc *tp = ifp->if_softc;
+	struct	mbuf *m;
+
+	TAPDEBUG(("%s: tapifstart q=%d\n", ifp->if_xname, ifp->if_snd.ifq_len));
+
+	IFQ_POLL(&ifp->if_snd, m);
+	if (m != NULL) {
+		ifp->if_opackets++;
+		if (tp->tap_flags & TAP_RWAIT) {
+			tp->tap_flags &= ~TAP_RWAIT;
+			wakeup((caddr_t)tp);
+		}
+		if (tp->tap_flags & TAP_ASYNC && tp->tap_pgid)
+			csignal(tp->tap_pgid, SIGIO,
+			    tp->tap_siguid, tp->tap_sigeuid);
+		selwakeup(&tp->tap_rsel);
+	}
+}
