if_tap.c revision 111119
163670Snsayer/* 263670Snsayer * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com> 363670Snsayer * All rights reserved. 463670Snsayer * 563670Snsayer * Redistribution and use in source and binary forms, with or without 663670Snsayer * modification, are permitted provided that the following conditions 763670Snsayer * are met: 863670Snsayer * 1. Redistributions of source code must retain the above copyright 963670Snsayer * notice, this list of conditions and the following disclaimer. 1063670Snsayer * 2. Redistributions in binary form must reproduce the above copyright 1163670Snsayer * notice, this list of conditions and the following disclaimer in the 1263670Snsayer * documentation and/or other materials provided with the distribution. 1363670Snsayer * 1463670Snsayer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1563670Snsayer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1663670Snsayer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1763670Snsayer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1863670Snsayer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1963670Snsayer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2063670Snsayer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2163670Snsayer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2263670Snsayer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2363670Snsayer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2463670Snsayer * SUCH DAMAGE. 2563670Snsayer * 2663670Snsayer * BASED ON: 2763670Snsayer * ------------------------------------------------------------------------- 2863670Snsayer * 2963670Snsayer * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> 3063670Snsayer * Nottingham University 1987. 3163670Snsayer */ 3263670Snsayer 3363670Snsayer/* 3463670Snsayer * $FreeBSD: head/sys/net/if_tap.c 111119 2003-02-19 05:47:46Z imp $ 3563803Snsayer * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ 3663670Snsayer */ 3763670Snsayer 3863670Snsayer#include "opt_inet.h" 3963670Snsayer 4063670Snsayer#include <sys/param.h> 4163670Snsayer#include <sys/conf.h> 4263670Snsayer#include <sys/filedesc.h> 4363670Snsayer#include <sys/filio.h> 4463670Snsayer#include <sys/kernel.h> 4563670Snsayer#include <sys/malloc.h> 4663670Snsayer#include <sys/mbuf.h> 4763670Snsayer#include <sys/poll.h> 4863670Snsayer#include <sys/proc.h> 4963670Snsayer#include <sys/signalvar.h> 5063670Snsayer#include <sys/socket.h> 5163670Snsayer#include <sys/sockio.h> 5263670Snsayer#include <sys/sysctl.h> 5363670Snsayer#include <sys/systm.h> 5463670Snsayer#include <sys/ttycom.h> 5563670Snsayer#include <sys/uio.h> 5663670Snsayer#include <sys/vnode.h> 5783043Sbrooks#include <machine/bus.h> /* XXX: Shouldn't really be required! */ 5883043Sbrooks#include <sys/rman.h> 5983043Sbrooks#include <sys/queue.h> 6063670Snsayer 6163670Snsayer#include <net/bpf.h> 6263670Snsayer#include <net/ethernet.h> 6363670Snsayer#include <net/if.h> 6463670Snsayer#include <net/if_arp.h> 6563670Snsayer#include <net/route.h> 6663670Snsayer 6763670Snsayer#include <netinet/in.h> 6863670Snsayer 6963670Snsayer#include <net/if_tapvar.h> 7063670Snsayer#include <net/if_tap.h> 7163670Snsayer 7263670Snsayer 7363670Snsayer#define CDEV_NAME "tap" 7463670Snsayer#define CDEV_MAJOR 149 7563670Snsayer#define TAPDEBUG if (tapdebug) printf 7663670Snsayer 7763670Snsayer#define TAP "tap" 7863670Snsayer#define VMNET "vmnet" 7983043Sbrooks#define TAPMAXUNIT 0x7fff 8083043Sbrooks#define VMNET_DEV_MASK 0x00800000 8183043Sbrooks /* 0x007f00ff */ 8263670Snsayer 8363670Snsayer/* module */ 8493084Sbdestatic int tapmodevent(module_t, int, void *); 8563670Snsayer 8663670Snsayer/* device */ 8793084Sbdestatic void tapclone(void *, char *, int, dev_t *); 8893084Sbdestatic void tapcreate(dev_t); 8963670Snsayer 9063670Snsayer/* network interface */ 9193084Sbdestatic void tapifstart(struct ifnet *); 9293084Sbdestatic int tapifioctl(struct ifnet *, u_long, caddr_t); 9393084Sbdestatic void tapifinit(void *); 9463670Snsayer 9563670Snsayer/* character device */ 9663670Snsayerstatic d_open_t tapopen; 9763670Snsayerstatic d_close_t tapclose; 9863670Snsayerstatic d_read_t tapread; 9963670Snsayerstatic d_write_t tapwrite; 10063670Snsayerstatic d_ioctl_t tapioctl; 10163670Snsayerstatic d_poll_t tappoll; 10263670Snsayer 10363670Snsayerstatic struct cdevsw tap_cdevsw = { 10463670Snsayer /* open */ tapopen, 10563670Snsayer /* close */ tapclose, 10663670Snsayer /* read */ tapread, 10763670Snsayer /* write */ tapwrite, 10863670Snsayer /* ioctl */ tapioctl, 10963670Snsayer /* poll */ tappoll, 11063670Snsayer /* mmap */ nommap, 11163670Snsayer /* startegy */ nostrategy, 11263670Snsayer /* dev name */ CDEV_NAME, 11363670Snsayer /* dev major */ CDEV_MAJOR, 11463670Snsayer /* dump */ nodump, 11563670Snsayer /* psize */ nopsize, 11663670Snsayer /* flags */ 0, 11763670Snsayer}; 11863670Snsayer 11983043Sbrooksstatic int tapdebug = 0; /* debug flag */ 12083043Sbrooksstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 12183043Sbrooksstatic udev_t tapbasedev = NOUDEV; /* base device */ 12283043Sbrooksstatic struct rman tapdevunits[2]; /* device units */ 12383043Sbrooks#define tapunits tapdevunits 12483043Sbrooks#define vmnetunits (tapdevunits + 1) 12563670Snsayer 12663670SnsayerMALLOC_DECLARE(M_TAP); 12763670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 12863670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 12963670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL); 13063670Snsayer 13163670Snsayer/* 13263670Snsayer * tapmodevent 13363670Snsayer * 13463670Snsayer * module event handler 13563670Snsayer */ 13663670Snsayerstatic int 13763670Snsayertapmodevent(mod, type, data) 13863670Snsayer module_t mod; 13963670Snsayer int type; 14063670Snsayer void *data; 14163670Snsayer{ 14283043Sbrooks static eventhandler_tag eh_tag = NULL; 14383043Sbrooks struct tap_softc *tp = NULL; 14483043Sbrooks struct ifnet *ifp = NULL; 14583043Sbrooks int error, s; 14663670Snsayer 14763670Snsayer switch (type) { 14863670Snsayer case MOD_LOAD: 14983043Sbrooks /* initialize resources */ 15083043Sbrooks tapunits->rm_type = RMAN_ARRAY; 15183043Sbrooks tapunits->rm_descr = "open tap units"; 15283043Sbrooks vmnetunits->rm_type = RMAN_ARRAY; 15383043Sbrooks vmnetunits->rm_descr = "open vmnet units"; 15463670Snsayer 15583043Sbrooks error = rman_init(tapunits); 15683043Sbrooks if (error != 0) 15783043Sbrooks goto bail; 15883043Sbrooks 15983043Sbrooks error = rman_init(vmnetunits); 16083043Sbrooks if (error != 0) 16183043Sbrooks goto bail1; 16283043Sbrooks 16383043Sbrooks error = rman_manage_region(tapunits, 0, TAPMAXUNIT); 16483043Sbrooks if (error != 0) 16583043Sbrooks goto bail2; 16683043Sbrooks 16783043Sbrooks error = rman_manage_region(vmnetunits, 0, TAPMAXUNIT); 16883043Sbrooks if (error != 0) 16983043Sbrooks goto bail2; 17083043Sbrooks 17183043Sbrooks /* intitialize device */ 17283043Sbrooks 17383043Sbrooks SLIST_INIT(&taphead); 17483043Sbrooks 17571602Sphk eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 17683043Sbrooks if (eh_tag == NULL) { 17783043Sbrooks error = ENOMEM; 17883043Sbrooks goto bail2; 17983043Sbrooks } 18063670Snsayer 18171602Sphk 18283043Sbrooks return (0); 18383043Sbrooksbail2: 18483043Sbrooks rman_fini(vmnetunits); 18583043Sbrooksbail1: 18683043Sbrooks rman_fini(tapunits); 18783043Sbrooksbail: 18883043Sbrooks return (error); 18963670Snsayer 19083043Sbrooks case MOD_UNLOAD: 19183043Sbrooks SLIST_FOREACH(tp, &taphead, tap_next) 19283043Sbrooks if (tp->tap_unit != NULL) 19383043Sbrooks return (EBUSY); 19483043Sbrooks 19571602Sphk EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 19663670Snsayer 19783043Sbrooks error = rman_fini(tapunits); 19883043Sbrooks KASSERT((error == 0), ("Could not fini tap units")); 19983043Sbrooks error = rman_fini(vmnetunits); 20083043Sbrooks KASSERT((error == 0), ("Could not fini vmnet units")); 20171602Sphk 20283043Sbrooks while ((tp = SLIST_FIRST(&taphead)) != NULL) { 20383043Sbrooks SLIST_REMOVE_HEAD(&taphead, tap_next); 20483043Sbrooks 20583043Sbrooks ifp = &tp->tap_if; 20683043Sbrooks 20783043Sbrooks TAPDEBUG("detaching %s%d\n", ifp->if_name,ifp->if_unit); 20883043Sbrooks 20983043Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 21083043Sbrooks ("%s%d flags is out of sync", ifp->if_name, 21183043Sbrooks ifp->if_unit)); 21283043Sbrooks 21383043Sbrooks /* XXX makedev check? nah.. not right now :) */ 21483043Sbrooks 21563670Snsayer s = splimp(); 216106939Ssam ether_ifdetach(ifp); 21763670Snsayer splx(s); 21863670Snsayer 21993752Sluigi free(tp, M_TAP); 22083043Sbrooks } 22163670Snsayer 22283043Sbrooks if (tapbasedev != NOUDEV) 22383043Sbrooks destroy_dev(udev2dev(tapbasedev, 0)); 22463670Snsayer 22563670Snsayer 22683043Sbrooks break; 22763670Snsayer 22863670Snsayer default: 22963670Snsayer return (EOPNOTSUPP); 23063670Snsayer } 23163670Snsayer 23263670Snsayer return (0); 23363670Snsayer} /* tapmodevent */ 23463670Snsayer 23563670Snsayer 23663670Snsayer/* 23771602Sphk * DEVFS handler 23871602Sphk * 23971602Sphk * We need to support two kind of devices - tap and vmnet 24071602Sphk */ 24171602Sphkstatic void 24271602Sphktapclone(arg, name, namelen, dev) 24371602Sphk void *arg; 24471602Sphk char *name; 24571602Sphk int namelen; 24671602Sphk dev_t *dev; 24771602Sphk{ 24883043Sbrooks int unit, minor = 0 /* XXX avoid warning */ , error; 24983043Sbrooks char *device_name = name; 25083043Sbrooks struct resource *r = NULL; 25171602Sphk 25271602Sphk if (*dev != NODEV) 25371602Sphk return; 25471602Sphk 25583043Sbrooks if (strcmp(device_name, TAP) == 0) { 25683043Sbrooks /* get first free tap unit */ 25783043Sbrooks r = rman_reserve_resource(tapunits, 0, TAPMAXUNIT, 1, 25883043Sbrooks RF_ALLOCATED | RF_ACTIVE, NULL); 25983043Sbrooks unit = rman_get_start(r); 26083043Sbrooks minor = unit2minor(unit); 26183043Sbrooks } 26283043Sbrooks else if (strcmp(device_name, VMNET) == 0) { 26383043Sbrooks /* get first free vmnet unit */ 26483043Sbrooks r = rman_reserve_resource(vmnetunits, 0, TAPMAXUNIT, 1, 26583043Sbrooks RF_ALLOCATED | RF_ACTIVE, NULL); 26683043Sbrooks unit = rman_get_start(r); 26783043Sbrooks minor = unit2minor(unit) | VMNET_DEV_MASK; 26883043Sbrooks } 26971602Sphk 27083043Sbrooks if (r != NULL) { /* need cloning */ 27183043Sbrooks TAPDEBUG("%s%d is available. minor = %#x\n", 27283043Sbrooks device_name, unit, minor); 27371602Sphk 27483043Sbrooks error = rman_release_resource(r); 27583043Sbrooks KASSERT((error == 0), ("Could not release tap/vmnet unit")); 27683043Sbrooks 27783043Sbrooks /* check if device for the unit has been created */ 27883043Sbrooks *dev = makedev(CDEV_MAJOR, minor); 27983043Sbrooks if ((*dev)->si_flags & SI_NAMED) { 28083043Sbrooks TAPDEBUG("%s%d device exists. minor = %#x\n", 28183043Sbrooks device_name, unit, minor); 28283043Sbrooks return; /* device has been created */ 28383043Sbrooks } 28483043Sbrooks } else { /* try to match name/unit, first try tap then vmnet */ 28583043Sbrooks device_name = TAP; 28683043Sbrooks if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 28783043Sbrooks device_name = VMNET; 28883043Sbrooks 28983043Sbrooks if (dev_stdclone(name, NULL, device_name, &unit) != 1) 29083043Sbrooks return; 29183043Sbrooks 29283043Sbrooks minor = unit2minor(unit) | VMNET_DEV_MASK; 29383043Sbrooks } else 29483043Sbrooks minor = unit2minor(unit); 29571602Sphk } 29671602Sphk 29783043Sbrooks TAPDEBUG("make_dev(%s%d). minor = %#x\n", device_name, unit, minor); 29883043Sbrooks 29971602Sphk *dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d", 30071602Sphk device_name, unit); 30183043Sbrooks 30283043Sbrooks if (tapbasedev == NOUDEV) 30383043Sbrooks tapbasedev = (*dev)->si_udev; 30483043Sbrooks else { 30583043Sbrooks (*dev)->si_flags |= SI_CHEAPCLONE; 30683043Sbrooks dev_depends(udev2dev(tapbasedev, 0), *dev); 30783043Sbrooks } 30871602Sphk} /* tapclone */ 30971602Sphk 31071602Sphk 31171602Sphk/* 31263670Snsayer * tapcreate 31363670Snsayer * 31463670Snsayer * to create interface 31563670Snsayer */ 31663670Snsayerstatic void 31763670Snsayertapcreate(dev) 31863670Snsayer dev_t dev; 31963670Snsayer{ 32063670Snsayer struct ifnet *ifp = NULL; 32163670Snsayer struct tap_softc *tp = NULL; 32263670Snsayer unsigned short macaddr_hi; 32363803Snsayer int unit, s; 32463670Snsayer char *name = NULL; 32563670Snsayer 32663670Snsayer /* allocate driver storage and create device */ 327111119Simp MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 32883043Sbrooks SLIST_INSERT_HEAD(&taphead, tp, tap_next); 32963670Snsayer 33083043Sbrooks unit = dev2unit(dev) & TAPMAXUNIT; 33183043Sbrooks 33263670Snsayer /* select device: tap or vmnet */ 33363670Snsayer if (minor(dev) & VMNET_DEV_MASK) { 33463670Snsayer name = VMNET; 33563803Snsayer tp->tap_flags |= TAP_VMNET; 33683043Sbrooks } else 33763670Snsayer name = TAP; 33863670Snsayer 33983043Sbrooks TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 34083043Sbrooks 34183043Sbrooks if (!(dev->si_flags & SI_NAMED)) 34283043Sbrooks dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 34363670Snsayer 0600, "%s%d", name, unit); 34463670Snsayer 34563670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 34663670Snsayer macaddr_hi = htons(0x00bd); 34763670Snsayer bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 34863670Snsayer bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 34963670Snsayer tp->arpcom.ac_enaddr[5] = (u_char)unit; 35063670Snsayer 35163670Snsayer /* fill the rest and attach interface */ 35263670Snsayer ifp = &tp->tap_if; 35363670Snsayer ifp->if_softc = tp; 35463670Snsayer ifp->if_unit = unit; 35563670Snsayer ifp->if_name = name; 35663670Snsayer ifp->if_init = tapifinit; 35763670Snsayer ifp->if_start = tapifstart; 35863670Snsayer ifp->if_ioctl = tapifioctl; 35963670Snsayer ifp->if_mtu = ETHERMTU; 36063670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 36163670Snsayer ifp->if_snd.ifq_maxlen = ifqmaxlen; 36263670Snsayer 36383043Sbrooks dev->si_drv1 = tp; 36483043Sbrooks 36563803Snsayer s = splimp(); 366106939Ssam ether_ifattach(ifp, tp->arpcom.ac_enaddr); 36763803Snsayer splx(s); 36863670Snsayer 36963803Snsayer tp->tap_flags |= TAP_INITED; 37063803Snsayer 37183043Sbrooks TAPDEBUG("interface %s%d is created. minor = %#x\n", 37283043Sbrooks ifp->if_name, ifp->if_unit, minor(dev)); 37363670Snsayer} /* tapcreate */ 37463670Snsayer 37563670Snsayer 37663670Snsayer/* 37763670Snsayer * tapopen 37863670Snsayer * 37963670Snsayer * to open tunnel. must be superuser 38063670Snsayer */ 38163670Snsayerstatic int 38283366Sjuliantapopen(dev, flag, mode, td) 38363670Snsayer dev_t dev; 38463670Snsayer int flag; 38563670Snsayer int mode; 38683366Sjulian struct thread *td; 38763670Snsayer{ 38863670Snsayer struct tap_softc *tp = NULL; 38983043Sbrooks int unit, error; 39083043Sbrooks struct resource *r = NULL; 39163670Snsayer 39293593Sjhb if ((error = suser(td)) != 0) 39363670Snsayer return (error); 39463670Snsayer 39583043Sbrooks unit = dev2unit(dev) & TAPMAXUNIT; 39683043Sbrooks 39783043Sbrooks if (minor(dev) & VMNET_DEV_MASK) 39883043Sbrooks r = rman_reserve_resource(vmnetunits, unit, unit, 1, 39983043Sbrooks RF_ALLOCATED | RF_ACTIVE, NULL); 40083043Sbrooks else 40183043Sbrooks r = rman_reserve_resource(tapunits, unit, unit, 1, 40283043Sbrooks RF_ALLOCATED | RF_ACTIVE, NULL); 40383043Sbrooks 40483043Sbrooks if (r == NULL) 40583043Sbrooks return (EBUSY); 40683043Sbrooks 40783043Sbrooks dev->si_flags &= ~SI_CHEAPCLONE; 40883043Sbrooks 40963670Snsayer tp = dev->si_drv1; 41063670Snsayer if (tp == NULL) { 41163670Snsayer tapcreate(dev); 41263670Snsayer tp = dev->si_drv1; 41363670Snsayer } 41463670Snsayer 41583043Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 41683043Sbrooks ("%s%d flags is out of sync", tp->tap_if.if_name, unit)); 41763670Snsayer 41863861Snsayer bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 41963861Snsayer 42083043Sbrooks tp->tap_unit = r; 42183366Sjulian tp->tap_pid = td->td_proc->p_pid; 42263670Snsayer tp->tap_flags |= TAP_OPEN; 42363670Snsayer 42483043Sbrooks TAPDEBUG("%s%d is open. minor = %#x\n", 42583043Sbrooks tp->tap_if.if_name, unit, minor(dev)); 42663670Snsayer 42763670Snsayer return (0); 42863670Snsayer} /* tapopen */ 42963670Snsayer 43063670Snsayer 43163670Snsayer/* 43263670Snsayer * tapclose 43363670Snsayer * 43463670Snsayer * close the device - mark i/f down & delete routing info 43563670Snsayer */ 43663670Snsayerstatic int 43783366Sjuliantapclose(dev, foo, bar, td) 43863670Snsayer dev_t dev; 43963670Snsayer int foo; 44063670Snsayer int bar; 44183366Sjulian struct thread *td; 44263670Snsayer{ 44383043Sbrooks int s, error; 44463670Snsayer struct tap_softc *tp = dev->si_drv1; 44563670Snsayer struct ifnet *ifp = &tp->tap_if; 44663670Snsayer 44787914Sjlemon KASSERT((tp->tap_unit != NULL), 44883043Sbrooks ("%s%d is not open", ifp->if_name, ifp->if_unit)); 44983043Sbrooks 45063670Snsayer /* junk all pending output */ 45183043Sbrooks IF_DRAIN(&ifp->if_snd); 45263670Snsayer 45363803Snsayer /* 45463803Snsayer * do not bring the interface down, and do not anything with 45563803Snsayer * interface, if we are in VMnet mode. just close the device. 45663803Snsayer */ 45763803Snsayer 45863803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 45963670Snsayer s = splimp(); 46063670Snsayer if_down(ifp); 46163670Snsayer if (ifp->if_flags & IFF_RUNNING) { 46263670Snsayer /* find internet addresses and delete routes */ 46363670Snsayer struct ifaddr *ifa = NULL; 46463670Snsayer 46563803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 46663670Snsayer if (ifa->ifa_addr->sa_family == AF_INET) { 46763670Snsayer rtinit(ifa, (int)RTM_DELETE, 0); 46863670Snsayer 46963670Snsayer /* remove address from interface */ 47063670Snsayer bzero(ifa->ifa_addr, 47163670Snsayer sizeof(*(ifa->ifa_addr))); 47263670Snsayer bzero(ifa->ifa_dstaddr, 47363670Snsayer sizeof(*(ifa->ifa_dstaddr))); 47463670Snsayer bzero(ifa->ifa_netmask, 47563670Snsayer sizeof(*(ifa->ifa_netmask))); 47663670Snsayer } 47763670Snsayer } 47863670Snsayer 47963670Snsayer ifp->if_flags &= ~IFF_RUNNING; 48063670Snsayer } 48163670Snsayer splx(s); 48263670Snsayer } 48363670Snsayer 48496122Salfred funsetown(&tp->tap_sigio); 48563670Snsayer selwakeup(&tp->tap_rsel); 48663670Snsayer 48763670Snsayer tp->tap_flags &= ~TAP_OPEN; 48863670Snsayer tp->tap_pid = 0; 48983043Sbrooks error = rman_release_resource(tp->tap_unit); 49083043Sbrooks KASSERT((error == 0), 49183043Sbrooks ("%s%d could not release unit", ifp->if_name, ifp->if_unit)); 49283043Sbrooks tp->tap_unit = NULL; 49363670Snsayer 49483043Sbrooks TAPDEBUG("%s%d is closed. minor = %#x\n", 49583043Sbrooks ifp->if_name, ifp->if_unit, minor(dev)); 49663670Snsayer 49763670Snsayer return (0); 49863670Snsayer} /* tapclose */ 49963670Snsayer 50063670Snsayer 50163670Snsayer/* 50263670Snsayer * tapifinit 50363670Snsayer * 50463670Snsayer * network interface initialization function 50563670Snsayer */ 50663670Snsayerstatic void 50763670Snsayertapifinit(xtp) 50863670Snsayer void *xtp; 50963670Snsayer{ 51063670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 51163670Snsayer struct ifnet *ifp = &tp->tap_if; 51263670Snsayer 51383043Sbrooks TAPDEBUG("initializing %s%d\n", ifp->if_name, ifp->if_unit); 51463670Snsayer 51563670Snsayer ifp->if_flags |= IFF_RUNNING; 51663670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 51763670Snsayer 51863670Snsayer /* attempt to start output */ 51963670Snsayer tapifstart(ifp); 52063670Snsayer} /* tapifinit */ 52163670Snsayer 52263670Snsayer 52363670Snsayer/* 52463670Snsayer * tapifioctl 52563670Snsayer * 52663670Snsayer * Process an ioctl request on network interface 52763670Snsayer */ 528105228Sphkstatic int 52963670Snsayertapifioctl(ifp, cmd, data) 53063670Snsayer struct ifnet *ifp; 53163670Snsayer u_long cmd; 53263670Snsayer caddr_t data; 53363670Snsayer{ 53463670Snsayer struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 53563670Snsayer struct ifstat *ifs = NULL; 53663670Snsayer int s, dummy; 53763670Snsayer 53863670Snsayer switch (cmd) { 53963670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 54063670Snsayer case SIOCADDMULTI: 54163670Snsayer case SIOCDELMULTI: 54283043Sbrooks break; 54363670Snsayer 54463670Snsayer case SIOCGIFSTATUS: 54563670Snsayer s = splimp(); 54663670Snsayer ifs = (struct ifstat *)data; 54763670Snsayer dummy = strlen(ifs->ascii); 54863670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 54963670Snsayer snprintf(ifs->ascii + dummy, 55063670Snsayer sizeof(ifs->ascii) - dummy, 55163670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 55263670Snsayer splx(s); 55383043Sbrooks break; 55463670Snsayer 55563670Snsayer default: 556106939Ssam s = splimp(); 557106939Ssam dummy = ether_ioctl(ifp, cmd, data); 558106939Ssam splx(s); 559106939Ssam return (dummy); 56063670Snsayer } 56163670Snsayer 56263670Snsayer return (0); 56363670Snsayer} /* tapifioctl */ 56463670Snsayer 56563670Snsayer 56663670Snsayer/* 56763670Snsayer * tapifstart 56863670Snsayer * 56963670Snsayer * queue packets from higher level ready to put out 57063670Snsayer */ 57163670Snsayerstatic void 57263670Snsayertapifstart(ifp) 57363670Snsayer struct ifnet *ifp; 57463670Snsayer{ 57563670Snsayer struct tap_softc *tp = ifp->if_softc; 57663670Snsayer int s; 57763670Snsayer 57883043Sbrooks TAPDEBUG("%s%d starting\n", ifp->if_name, ifp->if_unit); 57963670Snsayer 58063803Snsayer /* 58163803Snsayer * do not junk pending output if we are in VMnet mode. 58263803Snsayer * XXX: can this do any harm because of queue overflow? 58363803Snsayer */ 58463803Snsayer 58563803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && 58663803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 58763670Snsayer struct mbuf *m = NULL; 58863670Snsayer 58983043Sbrooks TAPDEBUG("%s%d not ready, tap_flags = 0x%x\n", ifp->if_name, 59083043Sbrooks ifp->if_unit, tp->tap_flags); 59163670Snsayer 59263670Snsayer s = splimp(); 59363670Snsayer do { 59463670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 59563670Snsayer if (m != NULL) 59663670Snsayer m_freem(m); 59763670Snsayer ifp->if_oerrors ++; 59863670Snsayer } while (m != NULL); 59963670Snsayer splx(s); 60063670Snsayer 60163670Snsayer return; 60263670Snsayer } 60363670Snsayer 60463670Snsayer s = splimp(); 60563670Snsayer ifp->if_flags |= IFF_OACTIVE; 60663670Snsayer 60763670Snsayer if (ifp->if_snd.ifq_len != 0) { 60863670Snsayer if (tp->tap_flags & TAP_RWAIT) { 60963670Snsayer tp->tap_flags &= ~TAP_RWAIT; 61063670Snsayer wakeup((caddr_t)tp); 61163670Snsayer } 61263670Snsayer 61363670Snsayer if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) 61495883Salfred pgsigio(&tp->tap_sigio, SIGIO, 0); 61563670Snsayer 61663670Snsayer selwakeup(&tp->tap_rsel); 61763670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 61863670Snsayer } 61963670Snsayer 62063670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 62163670Snsayer splx(s); 62263670Snsayer} /* tapifstart */ 62363670Snsayer 62463670Snsayer 62563670Snsayer/* 62663670Snsayer * tapioctl 62763670Snsayer * 62863670Snsayer * the cdevsw interface is now pretty minimal 62963670Snsayer */ 63063670Snsayerstatic int 63183366Sjuliantapioctl(dev, cmd, data, flag, td) 63263670Snsayer dev_t dev; 63363670Snsayer u_long cmd; 63463670Snsayer caddr_t data; 63563670Snsayer int flag; 63683366Sjulian struct thread *td; 63763670Snsayer{ 63863670Snsayer struct tap_softc *tp = dev->si_drv1; 63963670Snsayer struct ifnet *ifp = &tp->tap_if; 64063670Snsayer struct tapinfo *tapp = NULL; 64163670Snsayer int s; 642102052Ssobomax int f; 64363670Snsayer 64463670Snsayer switch (cmd) { 64563670Snsayer case TAPSIFINFO: 64663670Snsayer s = splimp(); 64763670Snsayer tapp = (struct tapinfo *)data; 64863670Snsayer ifp->if_mtu = tapp->mtu; 64963670Snsayer ifp->if_type = tapp->type; 65063670Snsayer ifp->if_baudrate = tapp->baudrate; 65163670Snsayer splx(s); 65283043Sbrooks break; 65363670Snsayer 65463670Snsayer case TAPGIFINFO: 65563670Snsayer tapp = (struct tapinfo *)data; 65663670Snsayer tapp->mtu = ifp->if_mtu; 65763670Snsayer tapp->type = ifp->if_type; 65863670Snsayer tapp->baudrate = ifp->if_baudrate; 65983043Sbrooks break; 66063670Snsayer 66163670Snsayer case TAPSDEBUG: 66263670Snsayer tapdebug = *(int *)data; 66383043Sbrooks break; 66463670Snsayer 66563670Snsayer case TAPGDEBUG: 66663670Snsayer *(int *)data = tapdebug; 66783043Sbrooks break; 66863670Snsayer 66963670Snsayer case FIONBIO: 67083043Sbrooks break; 67163670Snsayer 67263670Snsayer case FIOASYNC: 67363803Snsayer s = splimp(); 67463670Snsayer if (*(int *)data) 67563670Snsayer tp->tap_flags |= TAP_ASYNC; 67663670Snsayer else 67763670Snsayer tp->tap_flags &= ~TAP_ASYNC; 67863803Snsayer splx(s); 67983043Sbrooks break; 68063670Snsayer 68163670Snsayer case FIONREAD: 68263670Snsayer s = splimp(); 68363670Snsayer if (ifp->if_snd.ifq_head) { 68463670Snsayer struct mbuf *mb = ifp->if_snd.ifq_head; 68563670Snsayer 68663803Snsayer for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 68763670Snsayer *(int *)data += mb->m_len; 68883043Sbrooks } else 68963670Snsayer *(int *)data = 0; 69063670Snsayer splx(s); 69183043Sbrooks break; 69263670Snsayer 69363670Snsayer case FIOSETOWN: 69463670Snsayer return (fsetown(*(int *)data, &tp->tap_sigio)); 69563670Snsayer 69663670Snsayer case FIOGETOWN: 697104393Struckman *(int *)data = fgetown(&tp->tap_sigio); 69863670Snsayer return (0); 69963670Snsayer 70063670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 70163670Snsayer case TIOCSPGRP: 70263670Snsayer return (fsetown(-(*(int *)data), &tp->tap_sigio)); 70363670Snsayer 70463670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 70563670Snsayer case TIOCGPGRP: 706104393Struckman *(int *)data = -fgetown(&tp->tap_sigio); 70763670Snsayer return (0); 70863670Snsayer 70963670Snsayer /* VMware/VMnet port ioctl's */ 71063670Snsayer 71163670Snsayer case SIOCGIFFLAGS: /* get ifnet flags */ 71263670Snsayer bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 71383043Sbrooks break; 71463670Snsayer 71583043Sbrooks case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 716102052Ssobomax f = *(int *)data; 71763670Snsayer f &= 0x0fff; 71863670Snsayer f &= ~IFF_CANTCHANGE; 71963670Snsayer f |= IFF_UP; 72063670Snsayer 72163670Snsayer s = splimp(); 72263670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 72363670Snsayer splx(s); 72483043Sbrooks break; 72563670Snsayer 72663861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 72763670Snsayer case SIOCGIFADDR: 72863861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 72983043Sbrooks break; 73063670Snsayer 73163861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 73263861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 73383043Sbrooks break; 73463670Snsayer 73563670Snsayer default: 73663670Snsayer return (ENOTTY); 73763670Snsayer } 73863670Snsayer return (0); 73963670Snsayer} /* tapioctl */ 74063670Snsayer 74163670Snsayer 74263670Snsayer/* 74363670Snsayer * tapread 74463670Snsayer * 74563670Snsayer * the cdevsw read interface - reads a packet at a time, or at 74663670Snsayer * least as much of a packet as can be read 74763670Snsayer */ 74863670Snsayerstatic int 74963670Snsayertapread(dev, uio, flag) 75063670Snsayer dev_t dev; 75163670Snsayer struct uio *uio; 75263670Snsayer int flag; 75363670Snsayer{ 75463670Snsayer struct tap_softc *tp = dev->si_drv1; 75563670Snsayer struct ifnet *ifp = &tp->tap_if; 75690227Sdillon struct mbuf *m = NULL; 75763670Snsayer int error = 0, len, s; 75863670Snsayer 75983043Sbrooks TAPDEBUG("%s%d reading, minor = %#x\n", 76083043Sbrooks ifp->if_name, ifp->if_unit, minor(dev)); 76163670Snsayer 76263670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 76363803Snsayer TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n", 76483043Sbrooks ifp->if_name, ifp->if_unit, minor(dev), tp->tap_flags); 76563803Snsayer 76663670Snsayer return (EHOSTDOWN); 76763670Snsayer } 76863670Snsayer 76963670Snsayer tp->tap_flags &= ~TAP_RWAIT; 77063670Snsayer 77163670Snsayer /* sleep until we get a packet */ 77263670Snsayer do { 77363670Snsayer s = splimp(); 77490227Sdillon IF_DEQUEUE(&ifp->if_snd, m); 77563670Snsayer splx(s); 77663670Snsayer 77790227Sdillon if (m == NULL) { 77863670Snsayer if (flag & IO_NDELAY) 77963670Snsayer return (EWOULDBLOCK); 78063670Snsayer 78163670Snsayer tp->tap_flags |= TAP_RWAIT; 78263670Snsayer error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0); 78363670Snsayer if (error) 78463670Snsayer return (error); 78563670Snsayer } 78690227Sdillon } while (m == NULL); 78763670Snsayer 78863670Snsayer /* feed packet to bpf */ 789106939Ssam BPF_MTAP(ifp, m); 79063670Snsayer 79163670Snsayer /* xfer packet to user space */ 79290227Sdillon while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 79390227Sdillon len = min(uio->uio_resid, m->m_len); 79463670Snsayer if (len == 0) 79563670Snsayer break; 79663670Snsayer 79790227Sdillon error = uiomove(mtod(m, caddr_t), len, uio); 79890227Sdillon m = m_free(m); 79963670Snsayer } 80063670Snsayer 80190227Sdillon if (m != NULL) { 80283043Sbrooks TAPDEBUG("%s%d dropping mbuf, minor = %#x\n", ifp->if_name, 80383043Sbrooks ifp->if_unit, minor(dev)); 80490227Sdillon m_freem(m); 80563670Snsayer } 80663670Snsayer 80763670Snsayer return (error); 80863670Snsayer} /* tapread */ 80963670Snsayer 81063670Snsayer 81163670Snsayer/* 81263670Snsayer * tapwrite 81363670Snsayer * 81463670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 81563670Snsayer */ 81663670Snsayerstatic int 81763670Snsayertapwrite(dev, uio, flag) 81863670Snsayer dev_t dev; 81963670Snsayer struct uio *uio; 82063670Snsayer int flag; 82163670Snsayer{ 82263670Snsayer struct tap_softc *tp = dev->si_drv1; 82363670Snsayer struct ifnet *ifp = &tp->tap_if; 82463670Snsayer struct mbuf *top = NULL, **mp = NULL, *m = NULL; 82563670Snsayer int error = 0, tlen, mlen; 82663670Snsayer 82783043Sbrooks TAPDEBUG("%s%d writting, minor = %#x\n", 82883043Sbrooks ifp->if_name, ifp->if_unit, minor(dev)); 82963670Snsayer 83063670Snsayer if (uio->uio_resid == 0) 83163670Snsayer return (0); 83263670Snsayer 83363670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 83463803Snsayer TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n", 83583043Sbrooks ifp->if_name, ifp->if_unit, uio->uio_resid, minor(dev)); 83663803Snsayer 83763670Snsayer return (EIO); 83863670Snsayer } 83963670Snsayer tlen = uio->uio_resid; 84063670Snsayer 84163670Snsayer /* get a header mbuf */ 842111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 84363670Snsayer if (m == NULL) 84463670Snsayer return (ENOBUFS); 84563670Snsayer mlen = MHLEN; 84663670Snsayer 84763670Snsayer top = 0; 84863670Snsayer mp = ⊤ 84963670Snsayer while ((error == 0) && (uio->uio_resid > 0)) { 85063670Snsayer m->m_len = min(mlen, uio->uio_resid); 85163670Snsayer error = uiomove(mtod(m, caddr_t), m->m_len, uio); 85263670Snsayer *mp = m; 85363670Snsayer mp = &m->m_next; 85463670Snsayer if (uio->uio_resid > 0) { 855111119Simp MGET(m, M_DONTWAIT, MT_DATA); 85663803Snsayer if (m == NULL) { 85763670Snsayer error = ENOBUFS; 85863670Snsayer break; 85963670Snsayer } 86063670Snsayer mlen = MLEN; 86163670Snsayer } 86263670Snsayer } 86363670Snsayer if (error) { 86463670Snsayer ifp->if_ierrors ++; 86563670Snsayer if (top) 86663670Snsayer m_freem(top); 86763670Snsayer return (error); 86863670Snsayer } 86963670Snsayer 87063670Snsayer top->m_pkthdr.len = tlen; 87163670Snsayer top->m_pkthdr.rcvif = ifp; 87263670Snsayer 873106939Ssam /* Pass packet up to parent. */ 874106939Ssam (*ifp->if_input)(ifp, top); 875106939Ssam ifp->if_ipackets ++; /* ibytes are counted in parent */ 87663670Snsayer 87763670Snsayer return (0); 87863670Snsayer} /* tapwrite */ 87963670Snsayer 88063670Snsayer 88163670Snsayer/* 88263670Snsayer * tappoll 88363670Snsayer * 88463670Snsayer * the poll interface, this is only useful on reads 88563670Snsayer * really. the write detect always returns true, write never blocks 88663670Snsayer * anyway, it either accepts the packet or drops it 88763670Snsayer */ 88863670Snsayerstatic int 88983366Sjuliantappoll(dev, events, td) 89063670Snsayer dev_t dev; 89163670Snsayer int events; 89283366Sjulian struct thread *td; 89363670Snsayer{ 89463670Snsayer struct tap_softc *tp = dev->si_drv1; 89563670Snsayer struct ifnet *ifp = &tp->tap_if; 89663670Snsayer int s, revents = 0; 89763670Snsayer 89883043Sbrooks TAPDEBUG("%s%d polling, minor = %#x\n", 89983043Sbrooks ifp->if_name, ifp->if_unit, minor(dev)); 90063670Snsayer 90163670Snsayer s = splimp(); 90263670Snsayer if (events & (POLLIN | POLLRDNORM)) { 90363670Snsayer if (ifp->if_snd.ifq_len > 0) { 90463803Snsayer TAPDEBUG("%s%d have data in queue. len = %d, " \ 90563803Snsayer "minor = %#x\n", ifp->if_name, ifp->if_unit, 90683043Sbrooks ifp->if_snd.ifq_len, minor(dev)); 90763803Snsayer 90863670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 90983043Sbrooks } else { 91063803Snsayer TAPDEBUG("%s%d waiting for data, minor = %#x\n", 91183043Sbrooks ifp->if_name, ifp->if_unit, minor(dev)); 91263803Snsayer 91383805Sjhb selrecord(td, &tp->tap_rsel); 91463670Snsayer } 91563670Snsayer } 91663670Snsayer 91763670Snsayer if (events & (POLLOUT | POLLWRNORM)) 91863670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 91963670Snsayer 92063670Snsayer splx(s); 92163670Snsayer return (revents); 92263670Snsayer} /* tappoll */ 923