if_tap.c revision 137101
11590Srgrimes/*
21590Srgrimes * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com>
31590Srgrimes * All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes *
141590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241590Srgrimes * SUCH DAMAGE.
251590Srgrimes *
261590Srgrimes * BASED ON:
271590Srgrimes * -------------------------------------------------------------------------
281590Srgrimes *
291590Srgrimes * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
301590Srgrimes * Nottingham University 1987.
311590Srgrimes */
321590Srgrimes
331590Srgrimes/*
3487690Smarkm * $FreeBSD: head/sys/net/if_tap.c 137101 2004-10-31 17:39:46Z glebius $
3587690Smarkm * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $
3687690Smarkm */
3787690Smarkm
381590Srgrimes#include "opt_inet.h"
3928693Scharnier
401590Srgrimes#include <sys/param.h>
411590Srgrimes#include <sys/conf.h>
4287690Smarkm#include <sys/filedesc.h>
431590Srgrimes#include <sys/filio.h>
441590Srgrimes#include <sys/kernel.h>
4587690Smarkm#include <sys/malloc.h>
4628693Scharnier#include <sys/mbuf.h>
471590Srgrimes#include <sys/module.h>
481590Srgrimes#include <sys/poll.h>
491590Srgrimes#include <sys/proc.h>
501590Srgrimes#include <sys/signalvar.h>
511590Srgrimes#include <sys/socket.h>
5212811Sbde#include <sys/sockio.h>
531590Srgrimes#include <sys/sysctl.h>
541590Srgrimes#include <sys/systm.h>
551590Srgrimes#include <sys/ttycom.h>
561590Srgrimes#include <sys/uio.h>
571590Srgrimes#include <sys/vnode.h>
581590Srgrimes#include <sys/queue.h>
5912804Speter
6012811Sbde#include <net/bpf.h>
6112811Sbde#include <net/ethernet.h>
6212811Sbde#include <net/if.h>
6328693Scharnier#include <net/if_arp.h>
6487690Smarkm#include <net/route.h>
6528693Scharnier
6628693Scharnier#include <netinet/in.h>
6728693Scharnier
6828693Scharnier#include <net/if_tapvar.h>
691590Srgrimes#include <net/if_tap.h>
7028693Scharnier
711590Srgrimes
721590Srgrimes#define CDEV_NAME	"tap"
731590Srgrimes#define TAPDEBUG	if (tapdebug) printf
7430180Sdima
7528693Scharnier#define TAP		"tap"
7628693Scharnier#define VMNET		"vmnet"
771590Srgrimes#define TAPMAXUNIT	0x7fff
7887690Smarkm#define VMNET_DEV_MASK	CLONE_FLAG0
7987690Smarkm
8087690Smarkm/* module */
811590Srgrimesstatic int		tapmodevent(module_t, int, void *);
821590Srgrimes
8339230Sgibbs/* device */
841590Srgrimesstatic void		tapclone(void *, char *, int, struct cdev **);
8539230Sgibbsstatic void		tapcreate(struct cdev *);
861590Srgrimes
8739230Sgibbs/* network interface */
881590Srgrimesstatic void		tapifstart(struct ifnet *);
8939230Sgibbsstatic int		tapifioctl(struct ifnet *, u_long, caddr_t);
901590Srgrimesstatic void		tapifinit(void *);
9139230Sgibbs
921590Srgrimes/* character device */
9339230Sgibbsstatic d_open_t		tapopen;
941590Srgrimesstatic d_close_t	tapclose;
9539230Sgibbsstatic d_read_t		tapread;
961590Srgrimesstatic d_write_t	tapwrite;
9739230Sgibbsstatic d_ioctl_t	tapioctl;
981590Srgrimesstatic d_poll_t		tappoll;
9939230Sgibbs
1001590Srgrimesstatic struct cdevsw	tap_cdevsw = {
10130180Sdima	.d_version =	D_VERSION,
10294729Sjeff	.d_flags =	D_PSEUDO | D_NEEDGIANT,
1031590Srgrimes	.d_open =	tapopen,
10494729Sjeff	.d_close =	tapclose,
1051590Srgrimes	.d_read =	tapread,
10694729Sjeff	.d_write =	tapwrite,
1071590Srgrimes	.d_ioctl =	tapioctl,
10894729Sjeff	.d_poll =	tappoll,
1091590Srgrimes	.d_name =	CDEV_NAME,
11094729Sjeff};
1111590Srgrimes
11294729Sjeff/*
11392653Sjeff * All global variables in if_tap.c are locked with tapmtx, with the
11494729Sjeff * exception of tapdebug, which is accessed unlocked; tapclones is
1151590Srgrimes * static at runtime.
1161590Srgrimes */
1171590Srgrimesstatic struct mtx		tapmtx;
1181590Srgrimesstatic int			tapdebug = 0;        /* debug flag   */
11939230Sgibbsstatic SLIST_HEAD(, tap_softc)	taphead;             /* first device */
12039498Skenstatic struct clonedevs 	*tapclones;
12139498Sken
12239230SgibbsMALLOC_DECLARE(M_TAP);
12339230SgibbsMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
12439230SgibbsSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
12539230SgibbsDEV_MODULE(if_tap, tapmodevent, NULL);
12639498Sken
12739498Sken/*
12839230Sgibbs * tapmodevent
12939230Sgibbs *
1301590Srgrimes * module event handler
1311590Srgrimes */
1321590Srgrimesstatic int
1331590Srgrimestapmodevent(mod, type, data)
13439372Sdillon	module_t	 mod;
1351590Srgrimes	int		 type;
1361590Srgrimes	void		*data;
1371590Srgrimes{
1381590Srgrimes	static eventhandler_tag	 eh_tag = NULL;
1391590Srgrimes	struct tap_softc	*tp = NULL;
1401590Srgrimes	struct ifnet		*ifp = NULL;
1411590Srgrimes	int			 s;
1421590Srgrimes
1431590Srgrimes	switch (type) {
14443962Sdillon	case MOD_LOAD:
1451590Srgrimes
14692922Simp		/* intitialize device */
14792922Simp
14894729Sjeff		mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF);
14992922Simp		SLIST_INIT(&taphead);
15092922Simp
15192922Simp		clone_setup(&tapclones);
15292922Simp		eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
15392922Simp		if (eh_tag == NULL) {
15492922Simp			clone_cleanup(&tapclones);
15592922Simp			mtx_destroy(&tapmtx);
15692922Simp			return (ENOMEM);
15792922Simp		}
1581590Srgrimes		return (0);
15992922Simp
16092922Simp	case MOD_UNLOAD:
16187690Smarkm		/*
16292922Simp		 * The EBUSY algorithm here can't quite atomically
16387690Smarkm		 * guarantee that this is race-free since we have to
16428693Scharnier		 * release the tap mtx to deregister the clone handler.
1651590Srgrimes		 */
16687690Smarkm		mtx_lock(&tapmtx);
16787690Smarkm		SLIST_FOREACH(tp, &taphead, tap_next) {
1681590Srgrimes			mtx_lock(&tp->tap_mtx);
16987690Smarkm			if (tp->tap_flags & TAP_OPEN) {
1701590Srgrimes				mtx_unlock(&tp->tap_mtx);
1711590Srgrimes				mtx_unlock(&tapmtx);
1721590Srgrimes				return (EBUSY);
17378474Sschweikh			}
1741590Srgrimes			mtx_unlock(&tp->tap_mtx);
1751590Srgrimes		}
1761590Srgrimes		mtx_unlock(&tapmtx);
17743822Sken
17844067Sbde		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
1791590Srgrimes
1801590Srgrimes		mtx_lock(&tapmtx);
1811590Srgrimes		while ((tp = SLIST_FIRST(&taphead)) != NULL) {
1821590Srgrimes			SLIST_REMOVE_HEAD(&taphead, tap_next);
1831590Srgrimes			mtx_unlock(&tapmtx);
18430180Sdima
1851590Srgrimes			ifp = &tp->tap_if;
1861590Srgrimes
1871590Srgrimes			TAPDEBUG("detaching %s\n", ifp->if_xname);
1881590Srgrimes
1891590Srgrimes			/* Unlocked read. */
1901590Srgrimes			KASSERT(!(tp->tap_flags & TAP_OPEN),
1911590Srgrimes				("%s flags is out of sync", ifp->if_xname));
1921590Srgrimes
1931590Srgrimes			destroy_dev(tp->tap_dev);
1941590Srgrimes			s = splimp();
1951590Srgrimes			ether_ifdetach(ifp);
1961590Srgrimes			splx(s);
1971590Srgrimes
19839230Sgibbs			mtx_destroy(&tp->tap_mtx);
19939372Sdillon			free(tp, M_TAP);
20039230Sgibbs			mtx_lock(&tapmtx);
20139230Sgibbs		}
20239230Sgibbs		mtx_unlock(&tapmtx);
20339230Sgibbs		clone_cleanup(&tapclones);
20439230Sgibbs
20539230Sgibbs		mtx_destroy(&tapmtx);
20639230Sgibbs
20739230Sgibbs		break;
20839230Sgibbs
2091590Srgrimes	default:
2101590Srgrimes		return (EOPNOTSUPP);
2111590Srgrimes	}
2121590Srgrimes
21330180Sdima	return (0);
2141590Srgrimes} /* tapmodevent */
21530180Sdima
21630180Sdima
21730180Sdima/*
2181590Srgrimes * DEVFS handler
2191590Srgrimes *
2201590Srgrimes * We need to support two kind of devices - tap and vmnet
2211590Srgrimes */
22244067Sbdestatic void
22344067Sbdetapclone(arg, name, namelen, dev)
22444067Sbde	void	*arg;
2251590Srgrimes	char	*name;
2261590Srgrimes	int	 namelen;
2271590Srgrimes	struct cdev **dev;
2281590Srgrimes{
2291590Srgrimes	u_int		extra;
2301590Srgrimes	int		i, unit;
2311590Srgrimes	char		*device_name = name;
2321590Srgrimes
2331590Srgrimes	if (*dev != NULL)
2341590Srgrimes		return;
2351590Srgrimes
2361590Srgrimes	device_name = TAP;
2371590Srgrimes	extra = 0;
2381590Srgrimes	if (strcmp(name, TAP) == 0) {
2391590Srgrimes		unit = -1;
2401590Srgrimes	} else if (strcmp(name, VMNET) == 0) {
2411590Srgrimes		device_name = VMNET;
2421590Srgrimes		extra = VMNET_DEV_MASK;
24328693Scharnier		unit = -1;
24428693Scharnier	} else if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
24528693Scharnier		device_name = VMNET;
24682664Sru		extra = VMNET_DEV_MASK;
2471590Srgrimes		if (dev_stdclone(name, NULL, device_name, &unit) != 1)
2481590Srgrimes			return;
2491590Srgrimes	}
25028693Scharnier
2511590Srgrimes	/* find any existing device, or allocate new unit number */
25287690Smarkm	i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
25387690Smarkm	if (i) {
2541590Srgrimes		*dev = make_dev(&tap_cdevsw, unit2minor(unit | extra),
25581537Sken		     UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit);
2561590Srgrimes		if (*dev != NULL)
2571590Srgrimes			(*dev)->si_flags |= SI_CHEAPCLONE;
2581590Srgrimes	}
25928693Scharnier} /* tapclone */
2601590Srgrimes
2611590Srgrimes
2621590Srgrimes/*
2631590Srgrimes * tapcreate
2641590Srgrimes *
2651590Srgrimes * to create interface
26643819Sken */
26743819Skenstatic void
26843819Skentapcreate(dev)
26943819Sken	struct cdev *dev;
27043819Sken{
27143819Sken	struct ifnet		*ifp = NULL;
27243819Sken	struct tap_softc	*tp = NULL;
27343819Sken	unsigned short		 macaddr_hi;
27443819Sken	int			 unit, s;
2751590Srgrimes	char			*name = NULL;
2761590Srgrimes
2771590Srgrimes	dev->si_flags &= ~SI_CHEAPCLONE;
2781590Srgrimes
2791590Srgrimes	/* allocate driver storage and create device */
2801590Srgrimes	MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
2811590Srgrimes	mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF);
2821590Srgrimes	mtx_lock(&tapmtx);
2831590Srgrimes	SLIST_INSERT_HEAD(&taphead, tp, tap_next);
2841590Srgrimes	mtx_unlock(&tapmtx);
2851590Srgrimes
2861590Srgrimes	unit = dev2unit(dev);
2871590Srgrimes
2881590Srgrimes	/* select device: tap or vmnet */
2891590Srgrimes	if (unit & VMNET_DEV_MASK) {
2901590Srgrimes		name = VMNET;
2911590Srgrimes		tp->tap_flags |= TAP_VMNET;
2921590Srgrimes	} else
2931590Srgrimes		name = TAP;
2941590Srgrimes
2951590Srgrimes	unit &= TAPMAXUNIT;
2961590Srgrimes
2971590Srgrimes	TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev));
29830180Sdima
2991590Srgrimes	/* generate fake MAC address: 00 bd xx xx xx unit_no */
3001590Srgrimes	macaddr_hi = htons(0x00bd);
3011590Srgrimes	bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
3021590Srgrimes	bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
3031590Srgrimes	tp->arpcom.ac_enaddr[5] = (u_char)unit;
30443962Sdillon
30543962Sdillon	/* fill the rest and attach interface */
3061590Srgrimes	ifp = &tp->tap_if;
3071590Srgrimes	ifp->if_softc = tp;
30830180Sdima	if_initname(ifp, name, unit);
3091590Srgrimes	ifp->if_init = tapifinit;
3101590Srgrimes	ifp->if_start = tapifstart;
3111590Srgrimes	ifp->if_ioctl = tapifioctl;
3121590Srgrimes	ifp->if_mtu = ETHERMTU;
3131590Srgrimes	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
3141590Srgrimes	ifp->if_snd.ifq_maxlen = ifqmaxlen;
3151590Srgrimes
3161590Srgrimes	dev->si_drv1 = tp;
3171590Srgrimes	tp->tap_dev = dev;
3181590Srgrimes
3191590Srgrimes	s = splimp();
3201590Srgrimes	ether_ifattach(ifp, tp->arpcom.ac_enaddr);
3211590Srgrimes	splx(s);
3221590Srgrimes
32339230Sgibbs	mtx_lock(&tp->tap_mtx);
32439230Sgibbs	tp->tap_flags |= TAP_INITED;
3251590Srgrimes	mtx_unlock(&tp->tap_mtx);
32639230Sgibbs
32739230Sgibbs	TAPDEBUG("interface %s is created. minor = %#x\n",
32839230Sgibbs		ifp->if_xname, minor(dev));
32939230Sgibbs} /* tapcreate */
33039230Sgibbs
33139230Sgibbs
33239230Sgibbs/*
33339230Sgibbs * tapopen
33439230Sgibbs *
33539230Sgibbs * to open tunnel. must be superuser
33639230Sgibbs */
33739230Sgibbsstatic int
33839230Sgibbstapopen(dev, flag, mode, td)
3391590Srgrimes	struct cdev *dev;
3401590Srgrimes	int		 flag;
34139230Sgibbs	int		 mode;
34239230Sgibbs	struct thread	*td;
34339230Sgibbs{
34439230Sgibbs	struct tap_softc	*tp = NULL;
34539230Sgibbs	struct ifnet		*ifp = NULL;
3461590Srgrimes	int			 error, s;
34739230Sgibbs
34839230Sgibbs	if ((error = suser(td)) != 0)
34939372Sdillon		return (error);
35039372Sdillon
35139372Sdillon	if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT)
35239230Sgibbs		return (ENXIO);
35339230Sgibbs
35439230Sgibbs	/*
35539230Sgibbs	 * XXXRW: Non-atomic test-and-set of si_drv1.  Currently protected
35639230Sgibbs	 * by Giant, but the race actually exists under memory pressure as
35739230Sgibbs	 * well even when running with Giant, as malloc() may sleep.
35839230Sgibbs	 */
35939230Sgibbs	tp = dev->si_drv1;
36039230Sgibbs	if (tp == NULL) {
36139230Sgibbs		tapcreate(dev);
36239230Sgibbs		tp = dev->si_drv1;
36387690Smarkm	}
36439230Sgibbs
36539230Sgibbs	mtx_lock(&tp->tap_mtx);
36639230Sgibbs	if (tp->tap_flags & TAP_OPEN) {
36739230Sgibbs		mtx_unlock(&tp->tap_mtx);
36839230Sgibbs		return (EBUSY);
36939230Sgibbs	}
37039230Sgibbs
37139230Sgibbs	bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
37239230Sgibbs	tp->tap_pid = td->td_proc->p_pid;
37339230Sgibbs	tp->tap_flags |= TAP_OPEN;
37439230Sgibbs	ifp = &tp->tap_if;
37539230Sgibbs	mtx_unlock(&tp->tap_mtx);
37639230Sgibbs
37739230Sgibbs	s = splimp();
37839230Sgibbs	ifp->if_flags |= IFF_RUNNING;
37939230Sgibbs	ifp->if_flags &= ~IFF_OACTIVE;
38039230Sgibbs	splx(s);
38139230Sgibbs
3821590Srgrimes	TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev));
3831590Srgrimes
3841590Srgrimes	return (0);
3851590Srgrimes} /* tapopen */
3861590Srgrimes
3871590Srgrimes
388101590Stmm/*
389101590Stmm * tapclose
3901590Srgrimes *
3911590Srgrimes * close the device - mark i/f down & delete routing info
392101590Stmm */
3931590Srgrimesstatic int
3941590Srgrimestapclose(dev, foo, bar, td)
395101590Stmm	struct cdev *dev;
39628693Scharnier	int		 foo;
39728693Scharnier	int		 bar;
3981590Srgrimes	struct thread	*td;
3991590Srgrimes{
4001590Srgrimes	struct tap_softc	*tp = dev->si_drv1;
4011590Srgrimes	struct ifnet		*ifp = &tp->tap_if;
4021590Srgrimes	int			s;
4031590Srgrimes
4041590Srgrimes	/* junk all pending output */
4051590Srgrimes	IF_DRAIN(&ifp->if_snd);
4061590Srgrimes
4071590Srgrimes	/*
4081590Srgrimes	 * do not bring the interface down, and do not anything with
4091590Srgrimes	 * interface, if we are in VMnet mode. just close the device.
41039230Sgibbs	 */
41180551Stmm
41280551Stmm	mtx_lock(&tp->tap_mtx);
4131590Srgrimes	if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
4141590Srgrimes		mtx_unlock(&tp->tap_mtx);
4151590Srgrimes		s = splimp();
4161590Srgrimes		if_down(ifp);
4171590Srgrimes		if (ifp->if_flags & IFF_RUNNING) {
4181590Srgrimes			/* find internet addresses and delete routes */
4191590Srgrimes			struct ifaddr	*ifa = NULL;
4201590Srgrimes
4211590Srgrimes			/* In desparate need of ifaddr locking. */
4221590Srgrimes			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
4231590Srgrimes				if (ifa->ifa_addr->sa_family == AF_INET) {
4241590Srgrimes					rtinit(ifa, (int)RTM_DELETE, 0);
4251590Srgrimes
42639230Sgibbs					/* remove address from interface */
42739230Sgibbs					bzero(ifa->ifa_addr,
42839230Sgibbs						   sizeof(*(ifa->ifa_addr)));
42939230Sgibbs					bzero(ifa->ifa_dstaddr,
43039230Sgibbs						   sizeof(*(ifa->ifa_dstaddr)));
43139230Sgibbs					bzero(ifa->ifa_netmask,
43239230Sgibbs						   sizeof(*(ifa->ifa_netmask)));
43339230Sgibbs				}
43439230Sgibbs			}
43539230Sgibbs
43639230Sgibbs			ifp->if_flags &= ~IFF_RUNNING;
43739230Sgibbs		}
43839230Sgibbs		splx(s);
43939230Sgibbs	} else
44039230Sgibbs		mtx_unlock(&tp->tap_mtx);
44139230Sgibbs
44239230Sgibbs	funsetown(&tp->tap_sigio);
44339230Sgibbs	selwakeuppri(&tp->tap_rsel, PZERO+1);
44439230Sgibbs
44539230Sgibbs	mtx_lock(&tp->tap_mtx);
44639230Sgibbs	tp->tap_flags &= ~TAP_OPEN;
44739230Sgibbs	tp->tap_pid = 0;
44839230Sgibbs	mtx_unlock(&tp->tap_mtx);
44939230Sgibbs
45039230Sgibbs	TAPDEBUG("%s is closed. minor = %#x\n",
45139230Sgibbs		ifp->if_xname, minor(dev));
45239230Sgibbs
45339230Sgibbs	return (0);
45439230Sgibbs} /* tapclose */
45539230Sgibbs
45639230Sgibbs
45739230Sgibbs/*
45839230Sgibbs * tapifinit
45939230Sgibbs *
46039230Sgibbs * network interface initialization function
46139230Sgibbs */
46239230Sgibbsstatic void
46339230Sgibbstapifinit(xtp)
46439230Sgibbs	void	*xtp;
46539230Sgibbs{
46639230Sgibbs	struct tap_softc	*tp = (struct tap_softc *)xtp;
46739230Sgibbs	struct ifnet		*ifp = &tp->tap_if;
46839230Sgibbs
46939230Sgibbs	TAPDEBUG("initializing %s\n", ifp->if_xname);
47039230Sgibbs
47139230Sgibbs	ifp->if_flags |= IFF_RUNNING;
4721590Srgrimes	ifp->if_flags &= ~IFF_OACTIVE;
4731590Srgrimes
4741590Srgrimes	/* attempt to start output */
4751590Srgrimes	tapifstart(ifp);
4761590Srgrimes} /* tapifinit */
47781537Sken
47881537Sken
4791590Srgrimes/*
4801590Srgrimes * tapifioctl
48178672Sschweikh *
4821590Srgrimes * Process an ioctl request on network interface
48372887Salfred */
4841590Srgrimesstatic int
48581537Skentapifioctl(ifp, cmd, data)
48681537Sken	struct ifnet	*ifp;
48737453Sbde	u_long		 cmd;
48837453Sbde	caddr_t		 data;
4891590Srgrimes{
49037453Sbde	struct tap_softc	*tp = (struct tap_softc *)(ifp->if_softc);
49137453Sbde	struct ifstat		*ifs = NULL;
49237453Sbde	int			 s, dummy;
4933659Sdg
49437453Sbde	switch (cmd) {
49537453Sbde		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
4963693Sdg		case SIOCADDMULTI:
49737453Sbde		case SIOCDELMULTI:
49837453Sbde			break;
49937453Sbde
50037453Sbde		case SIOCGIFSTATUS:
50139230Sgibbs			s = splimp();
5021590Srgrimes			ifs = (struct ifstat *)data;
50337453Sbde			dummy = strlen(ifs->ascii);
50437453Sbde			mtx_lock(&tp->tap_mtx);
50537453Sbde			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
5061590Srgrimes				snprintf(ifs->ascii + dummy,
5071590Srgrimes					sizeof(ifs->ascii) - dummy,
5081590Srgrimes					"\tOpened by PID %d\n", tp->tap_pid);
5091590Srgrimes			mtx_unlock(&tp->tap_mtx);
5101590Srgrimes			splx(s);
5111590Srgrimes			break;
5121590Srgrimes
5131590Srgrimes		default:
5141590Srgrimes			s = splimp();
5151590Srgrimes			dummy = ether_ioctl(ifp, cmd, data);
5161590Srgrimes			splx(s);
5173659Sdg			return (dummy);
5183659Sdg	}
5193659Sdg
5203659Sdg	return (0);
5211590Srgrimes} /* tapifioctl */
5221590Srgrimes
5231590Srgrimes
5241590Srgrimes/*
52528693Scharnier * tapifstart
5261590Srgrimes *
5271590Srgrimes * queue packets from higher level ready to put out
52843822Sken */
5291590Srgrimesstatic void
53043822Skentapifstart(ifp)
53178672Sschweikh	struct ifnet	*ifp;
53243822Sken{
53343822Sken	struct tap_softc	*tp = ifp->if_softc;
53443822Sken	int			 s;
53543822Sken
53643822Sken	TAPDEBUG("%s starting\n", ifp->if_xname);
53778672Sschweikh
53839230Sgibbs	/*
53939230Sgibbs	 * do not junk pending output if we are in VMnet mode.
54039230Sgibbs	 * XXX: can this do any harm because of queue overflow?
54139230Sgibbs	 */
54239230Sgibbs
54339230Sgibbs	mtx_lock(&tp->tap_mtx);
5441590Srgrimes	if (((tp->tap_flags & TAP_VMNET) == 0) &&
5451590Srgrimes	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
5461590Srgrimes		struct mbuf	*m = NULL;
5471590Srgrimes
5481590Srgrimes		mtx_unlock(&tp->tap_mtx);
5491590Srgrimes
5501590Srgrimes		/* Unlocked read. */
5511590Srgrimes		TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
55287690Smarkm		    tp->tap_flags);
55387690Smarkm
5541590Srgrimes		s = splimp();
5551590Srgrimes		do {
5561590Srgrimes			IF_DEQUEUE(&ifp->if_snd, m);
5571590Srgrimes			if (m != NULL)
5581590Srgrimes				m_freem(m);
55930180Sdima			ifp->if_oerrors ++;
5601590Srgrimes		} while (m != NULL);
5611590Srgrimes		splx(s);
5621590Srgrimes
5631590Srgrimes		return;
5641590Srgrimes	}
5651590Srgrimes	mtx_unlock(&tp->tap_mtx);
5661590Srgrimes
5671590Srgrimes	s = splimp();
5681590Srgrimes	ifp->if_flags |= IFF_OACTIVE;
5691590Srgrimes
5701590Srgrimes	if (ifp->if_snd.ifq_len != 0) {
5711590Srgrimes		mtx_lock(&tp->tap_mtx);
5721590Srgrimes		if (tp->tap_flags & TAP_RWAIT) {
5731590Srgrimes			tp->tap_flags &= ~TAP_RWAIT;
5741590Srgrimes			wakeup(tp);
5751590Srgrimes		}
5761590Srgrimes
5771590Srgrimes		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) {
5781590Srgrimes			mtx_unlock(&tp->tap_mtx);
57928693Scharnier			pgsigio(&tp->tap_sigio, SIGIO, 0);
5801590Srgrimes		} else
5811590Srgrimes			mtx_unlock(&tp->tap_mtx);
5821590Srgrimes
5831590Srgrimes		selwakeuppri(&tp->tap_rsel, PZERO+1);
5841590Srgrimes		ifp->if_opackets ++; /* obytes are counted in ether_output */
5851590Srgrimes	}
5861590Srgrimes
5871590Srgrimes	ifp->if_flags &= ~IFF_OACTIVE;
5881590Srgrimes	splx(s);
5891590Srgrimes} /* tapifstart */
5901590Srgrimes
5911590Srgrimes
5921590Srgrimes/*
5931590Srgrimes * tapioctl
5941590Srgrimes *
5951590Srgrimes * the cdevsw interface is now pretty minimal
59687690Smarkm */
5971590Srgrimesstatic int
5981590Srgrimestapioctl(dev, cmd, data, flag, td)
5991590Srgrimes	struct cdev *dev;
6001590Srgrimes	u_long		 cmd;
6011590Srgrimes	caddr_t		 data;
6021590Srgrimes	int		 flag;
6031590Srgrimes	struct thread	*td;
6041590Srgrimes{
60571429Sume	struct tap_softc	*tp = dev->si_drv1;
60671429Sume	struct ifnet		*ifp = &tp->tap_if;
60771429Sume	struct tapinfo		*tapp = NULL;
60871429Sume	int			 s;
6093659Sdg	int			 f;
6103693Sdg
6113659Sdg	switch (cmd) {
6123659Sdg		case TAPSIFINFO:
6133659Sdg			s = splimp();
6143693Sdg			tapp = (struct tapinfo *)data;
6153659Sdg			ifp->if_mtu = tapp->mtu;
6163659Sdg			ifp->if_type = tapp->type;
6173693Sdg			ifp->if_baudrate = tapp->baudrate;
6183693Sdg			splx(s);
6191590Srgrimes			break;
6207351Sdg
62134214Sdyson		case TAPGIFINFO:
6227351Sdg			tapp = (struct tapinfo *)data;
62334214Sdyson			tapp->mtu = ifp->if_mtu;
6241590Srgrimes			tapp->type = ifp->if_type;
6251590Srgrimes			tapp->baudrate = ifp->if_baudrate;
62671429Sume			break;
62771429Sume
62871429Sume		case TAPSDEBUG:
62971429Sume			tapdebug = *(int *)data;
6303693Sdg			break;
6311590Srgrimes
6321590Srgrimes		case TAPGDEBUG:
6331590Srgrimes			*(int *)data = tapdebug;
6341590Srgrimes			break;
6355463Sdg
6363693Sdg		case FIONBIO:
6373693Sdg			break;
6381590Srgrimes
63987690Smarkm		case FIOASYNC:
64087690Smarkm			s = splimp();
64187690Smarkm			mtx_lock(&tp->tap_mtx);
64287690Smarkm			if (*(int *)data)
6431590Srgrimes				tp->tap_flags |= TAP_ASYNC;
6441590Srgrimes			else
64528693Scharnier				tp->tap_flags &= ~TAP_ASYNC;
64687690Smarkm			mtx_unlock(&tp->tap_mtx);
64787690Smarkm			splx(s);
64887690Smarkm			break;
64928693Scharnier
65087690Smarkm		case FIONREAD:
65187690Smarkm			s = splimp();
65287690Smarkm			if (ifp->if_snd.ifq_head) {
6531590Srgrimes				struct mbuf	*mb = ifp->if_snd.ifq_head;
6541590Srgrimes
65530180Sdima				for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
6561590Srgrimes					*(int *)data += mb->m_len;
6571590Srgrimes			} else
6581590Srgrimes				*(int *)data = 0;
6591590Srgrimes			splx(s);
6601590Srgrimes			break;
6611590Srgrimes
6621590Srgrimes		case FIOSETOWN:
6631590Srgrimes			return (fsetown(*(int *)data, &tp->tap_sigio));
6641590Srgrimes
6651590Srgrimes		case FIOGETOWN:
6661590Srgrimes			*(int *)data = fgetown(&tp->tap_sigio);
6671590Srgrimes			return (0);
6681590Srgrimes
66939230Sgibbs		/* this is deprecated, FIOSETOWN should be used instead */
67039230Sgibbs		case TIOCSPGRP:
6711590Srgrimes			return (fsetown(-(*(int *)data), &tp->tap_sigio));
67287690Smarkm
67339230Sgibbs		/* this is deprecated, FIOGETOWN should be used instead */
67439230Sgibbs		case TIOCGPGRP:
6751590Srgrimes			*(int *)data = -fgetown(&tp->tap_sigio);
67639230Sgibbs			return (0);
6771590Srgrimes
67839230Sgibbs		/* VMware/VMnet port ioctl's */
67939230Sgibbs
68039230Sgibbs		case SIOCGIFFLAGS:	/* get ifnet flags */
6811590Srgrimes			bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
68239230Sgibbs			break;
68339230Sgibbs
68439230Sgibbs		case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
68539230Sgibbs			f = *(int *)data;
68639230Sgibbs			f &= 0x0fff;
68739230Sgibbs			f &= ~IFF_CANTCHANGE;
68839230Sgibbs			f |= IFF_UP;
68939230Sgibbs
6901590Srgrimes			s = splimp();
69139230Sgibbs			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
69239230Sgibbs			splx(s);
69339230Sgibbs			break;
69481537Sken
69581537Sken		case OSIOCGIFADDR:	/* get MAC address of the remote side */
69681537Sken		case SIOCGIFADDR:
69781537Sken			mtx_lock(&tp->tap_mtx);
69839230Sgibbs			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
69939230Sgibbs			mtx_unlock(&tp->tap_mtx);
70081537Sken			break;
7011590Srgrimes
7021590Srgrimes		case SIOCSIFADDR:	/* set MAC address of the remote side */
7031590Srgrimes			mtx_lock(&tp->tap_mtx);
7041590Srgrimes			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
7051590Srgrimes			mtx_unlock(&tp->tap_mtx);
7061590Srgrimes			break;
70787690Smarkm
70887690Smarkm		default:
7091590Srgrimes			return (ENOTTY);
7101590Srgrimes	}
7111590Srgrimes	return (0);
71239230Sgibbs} /* tapioctl */
7131590Srgrimes
71487690Smarkm
7151590Srgrimes/*
71687690Smarkm * tapread
71739230Sgibbs *
71887690Smarkm * the cdevsw read interface - reads a packet at a time, or at
71939230Sgibbs * least as much of a packet as can be read
72087690Smarkm */
72187690Smarkmstatic int
7221590Srgrimestapread(dev, uio, flag)
7231590Srgrimes	struct cdev *dev;
7241590Srgrimes	struct uio	*uio;
7251590Srgrimes	int		 flag;
7261590Srgrimes{
72787690Smarkm	struct tap_softc	*tp = dev->si_drv1;
72887690Smarkm	struct ifnet		*ifp = &tp->tap_if;
72987690Smarkm	struct mbuf		*m = NULL;
73087690Smarkm	int			 error = 0, len, s;
7311590Srgrimes
7321590Srgrimes	TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev));
7331590Srgrimes
7341590Srgrimes	mtx_lock(&tp->tap_mtx);
7351590Srgrimes	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
7361590Srgrimes		mtx_unlock(&tp->tap_mtx);
7371590Srgrimes
73828693Scharnier		/* Unlocked read. */
73928693Scharnier		TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
7401590Srgrimes			ifp->if_xname, minor(dev), tp->tap_flags);
7411590Srgrimes
74278849Sschweikh		return (EHOSTDOWN);
7431590Srgrimes	}
7441590Srgrimes
7451590Srgrimes	tp->tap_flags &= ~TAP_RWAIT;
7461590Srgrimes	mtx_unlock(&tp->tap_mtx);
74778849Sschweikh
7481590Srgrimes	/* sleep until we get a packet */
7491590Srgrimes	do {
7501590Srgrimes		s = splimp();
7511590Srgrimes		IF_DEQUEUE(&ifp->if_snd, m);
75278849Sschweikh		splx(s);
75349107Sn_hibma
7541590Srgrimes		if (m == NULL) {
7551590Srgrimes			if (flag & IO_NDELAY)
75694729Sjeff				return (EWOULDBLOCK);
75794729Sjeff
75894729Sjeff			mtx_lock(&tp->tap_mtx);
75994729Sjeff			tp->tap_flags |= TAP_RWAIT;
76094729Sjeff			mtx_unlock(&tp->tap_mtx);
76146852Simp			error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0);
7621590Srgrimes			if (error)
76394729Sjeff				return (error);
7641590Srgrimes		}
76594729Sjeff	} while (m == NULL);
7661590Srgrimes
7671590Srgrimes	/* feed packet to bpf */
76843962Sdillon	BPF_MTAP(ifp, m);
76994729Sjeff
77043962Sdillon	/* xfer packet to user space */
77171404Sdes	while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
77271404Sdes		len = min(uio->uio_resid, m->m_len);
77343962Sdillon		if (len == 0)
77471404Sdes			break;
77571404Sdes
77671404Sdes		error = uiomove(mtod(m, void *), len, uio);
77771404Sdes		m = m_free(m);
77871404Sdes	}
77994729Sjeff
78043962Sdillon	if (m != NULL) {
78171404Sdes		TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname,
78271404Sdes			minor(dev));
78371404Sdes		m_freem(m);
78443962Sdillon	}
78571404Sdes
78671404Sdes	return (error);
78771404Sdes} /* tapread */
78843962Sdillon
78943962Sdillon
7901590Srgrimes/*
7911590Srgrimes * tapwrite
7921590Srgrimes *
7931590Srgrimes * the cdevsw write interface - an atomic write is a packet - or else!
7941590Srgrimes */
7951590Srgrimesstatic int
7961590Srgrimestapwrite(dev, uio, flag)
7971590Srgrimes	struct cdev *dev;
7981590Srgrimes	struct uio	*uio;
7991590Srgrimes	int		 flag;
8001590Srgrimes{
80140690Sjdp	struct tap_softc	*tp = dev->si_drv1;
8021590Srgrimes	struct ifnet		*ifp = &tp->tap_if;
8031590Srgrimes	struct mbuf		*m;
8041590Srgrimes	int			 error = 0;
80528693Scharnier
8061590Srgrimes	TAPDEBUG("%s writting, minor = %#x\n",
80787690Smarkm		ifp->if_xname, minor(dev));
8081590Srgrimes
8091590Srgrimes	if (uio->uio_resid == 0)
8101590Srgrimes		return (0);
81128693Scharnier
8121590Srgrimes	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
8131590Srgrimes		TAPDEBUG("%s invalid packet len = %d, minor = %#x\n",
8141590Srgrimes			ifp->if_xname, uio->uio_resid, minor(dev));
8151590Srgrimes
8161590Srgrimes		return (EIO);
8171590Srgrimes	}
81872887Salfred
81972887Salfred	if ((m = m_uiotombuf(uio, M_DONTWAIT, 0)) == NULL) {
82072887Salfred		ifp->if_ierrors ++;
8211590Srgrimes		return (error);
8221590Srgrimes	}
823
824	m->m_pkthdr.rcvif = ifp;
825
826	/* Pass packet up to parent. */
827	(*ifp->if_input)(ifp, m);
828	ifp->if_ipackets ++; /* ibytes are counted in parent */
829
830	return (0);
831} /* tapwrite */
832
833
834/*
835 * tappoll
836 *
837 * the poll interface, this is only useful on reads
838 * really. the write detect always returns true, write never blocks
839 * anyway, it either accepts the packet or drops it
840 */
841static int
842tappoll(dev, events, td)
843	struct cdev *dev;
844	int		 events;
845	struct thread	*td;
846{
847	struct tap_softc	*tp = dev->si_drv1;
848	struct ifnet		*ifp = &tp->tap_if;
849	int			 s, revents = 0;
850
851	TAPDEBUG("%s polling, minor = %#x\n",
852		ifp->if_xname, minor(dev));
853
854	s = splimp();
855	if (events & (POLLIN | POLLRDNORM)) {
856		if (ifp->if_snd.ifq_len > 0) {
857			TAPDEBUG("%s have data in queue. len = %d, " \
858				"minor = %#x\n", ifp->if_xname,
859				ifp->if_snd.ifq_len, minor(dev));
860
861			revents |= (events & (POLLIN | POLLRDNORM));
862		} else {
863			TAPDEBUG("%s waiting for data, minor = %#x\n",
864				ifp->if_xname, minor(dev));
865
866			selrecord(td, &tp->tap_rsel);
867		}
868	}
869
870	if (events & (POLLOUT | POLLWRNORM))
871		revents |= (events & (POLLOUT | POLLWRNORM));
872
873	splx(s);
874	return (revents);
875} /* tappoll */
876