if_tap.c revision 83366
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 83366 2001-09-12 08:38:13Z julian $ 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 */ 8463670Snsayerstatic int tapmodevent __P((module_t, int, void *)); 8563670Snsayer 8663670Snsayer/* device */ 8771602Sphkstatic void tapclone __P((void *, char *, int, dev_t *)); 8863670Snsayerstatic void tapcreate __P((dev_t)); 8963670Snsayer 9063670Snsayer/* network interface */ 9163670Snsayerstatic void tapifstart __P((struct ifnet *)); 9263670Snsayerstatic int tapifioctl __P((struct ifnet *, u_long, caddr_t)); 9363670Snsayerstatic void tapifinit __P((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 18183043Sbrooks if (!devfs_present) { 18283043Sbrooks error = cdevsw_add(&tap_cdevsw); 18383043Sbrooks if (error != 0) { 18483043Sbrooks EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 18583043Sbrooks goto bail2; 18683043Sbrooks } 18783043Sbrooks } 18871602Sphk 18983043Sbrooks return (0); 19083043Sbrooksbail2: 19183043Sbrooks rman_fini(vmnetunits); 19283043Sbrooksbail1: 19383043Sbrooks rman_fini(tapunits); 19483043Sbrooksbail: 19583043Sbrooks return (error); 19663670Snsayer 19783043Sbrooks case MOD_UNLOAD: 19883043Sbrooks SLIST_FOREACH(tp, &taphead, tap_next) 19983043Sbrooks if (tp->tap_unit != NULL) 20083043Sbrooks return (EBUSY); 20183043Sbrooks 20271602Sphk EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 20363670Snsayer 20483043Sbrooks error = rman_fini(tapunits); 20583043Sbrooks KASSERT((error == 0), ("Could not fini tap units")); 20683043Sbrooks error = rman_fini(vmnetunits); 20783043Sbrooks KASSERT((error == 0), ("Could not fini vmnet units")); 20871602Sphk 20983043Sbrooks while ((tp = SLIST_FIRST(&taphead)) != NULL) { 21083043Sbrooks SLIST_REMOVE_HEAD(&taphead, tap_next); 21183043Sbrooks 21283043Sbrooks ifp = &tp->tap_if; 21383043Sbrooks 21483043Sbrooks TAPDEBUG("detaching %s%d\n", ifp->if_name,ifp->if_unit); 21583043Sbrooks 21683043Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 21783043Sbrooks ("%s%d flags is out of sync", ifp->if_name, 21883043Sbrooks ifp->if_unit)); 21983043Sbrooks 22083043Sbrooks /* XXX makedev check? nah.. not right now :) */ 22183043Sbrooks 22263670Snsayer s = splimp(); 22383043Sbrooks ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); 22463670Snsayer splx(s); 22563670Snsayer 22683043Sbrooks FREE(tp, M_TAP); 22783043Sbrooks } 22863670Snsayer 22983043Sbrooks if (tapbasedev != NOUDEV) 23083043Sbrooks destroy_dev(udev2dev(tapbasedev, 0)); 23163670Snsayer 23283043Sbrooks if (!devfs_present) 23383043Sbrooks cdevsw_remove(&tap_cdevsw); 23463670Snsayer 23583043Sbrooks break; 23663670Snsayer 23763670Snsayer default: 23863670Snsayer return (EOPNOTSUPP); 23963670Snsayer } 24063670Snsayer 24163670Snsayer return (0); 24263670Snsayer} /* tapmodevent */ 24363670Snsayer 24463670Snsayer 24563670Snsayer/* 24671602Sphk * DEVFS handler 24771602Sphk * 24871602Sphk * We need to support two kind of devices - tap and vmnet 24971602Sphk */ 25071602Sphkstatic void 25171602Sphktapclone(arg, name, namelen, dev) 25271602Sphk void *arg; 25371602Sphk char *name; 25471602Sphk int namelen; 25571602Sphk dev_t *dev; 25671602Sphk{ 25783043Sbrooks int unit, minor = 0 /* XXX avoid warning */ , error; 25883043Sbrooks char *device_name = name; 25983043Sbrooks struct resource *r = NULL; 26071602Sphk 26171602Sphk if (*dev != NODEV) 26271602Sphk return; 26371602Sphk 26483043Sbrooks if (strcmp(device_name, TAP) == 0) { 26583043Sbrooks /* get first free tap unit */ 26683043Sbrooks r = rman_reserve_resource(tapunits, 0, TAPMAXUNIT, 1, 26783043Sbrooks RF_ALLOCATED | RF_ACTIVE, NULL); 26883043Sbrooks unit = rman_get_start(r); 26983043Sbrooks minor = unit2minor(unit); 27083043Sbrooks } 27183043Sbrooks else if (strcmp(device_name, VMNET) == 0) { 27283043Sbrooks /* get first free vmnet unit */ 27383043Sbrooks r = rman_reserve_resource(vmnetunits, 0, TAPMAXUNIT, 1, 27483043Sbrooks RF_ALLOCATED | RF_ACTIVE, NULL); 27583043Sbrooks unit = rman_get_start(r); 27683043Sbrooks minor = unit2minor(unit) | VMNET_DEV_MASK; 27783043Sbrooks } 27871602Sphk 27983043Sbrooks if (r != NULL) { /* need cloning */ 28083043Sbrooks TAPDEBUG("%s%d is available. minor = %#x\n", 28183043Sbrooks device_name, unit, minor); 28271602Sphk 28383043Sbrooks error = rman_release_resource(r); 28483043Sbrooks KASSERT((error == 0), ("Could not release tap/vmnet unit")); 28583043Sbrooks 28683043Sbrooks /* check if device for the unit has been created */ 28783043Sbrooks *dev = makedev(CDEV_MAJOR, minor); 28883043Sbrooks if ((*dev)->si_flags & SI_NAMED) { 28983043Sbrooks TAPDEBUG("%s%d device exists. minor = %#x\n", 29083043Sbrooks device_name, unit, minor); 29183043Sbrooks return; /* device has been created */ 29283043Sbrooks } 29383043Sbrooks } else { /* try to match name/unit, first try tap then vmnet */ 29483043Sbrooks device_name = TAP; 29583043Sbrooks if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 29683043Sbrooks device_name = VMNET; 29783043Sbrooks 29883043Sbrooks if (dev_stdclone(name, NULL, device_name, &unit) != 1) 29983043Sbrooks return; 30083043Sbrooks 30183043Sbrooks minor = unit2minor(unit) | VMNET_DEV_MASK; 30283043Sbrooks } else 30383043Sbrooks minor = unit2minor(unit); 30471602Sphk } 30571602Sphk 30683043Sbrooks TAPDEBUG("make_dev(%s%d). minor = %#x\n", device_name, unit, minor); 30783043Sbrooks 30871602Sphk *dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d", 30971602Sphk device_name, unit); 31083043Sbrooks 31183043Sbrooks if (tapbasedev == NOUDEV) 31283043Sbrooks tapbasedev = (*dev)->si_udev; 31383043Sbrooks else { 31483043Sbrooks (*dev)->si_flags |= SI_CHEAPCLONE; 31583043Sbrooks dev_depends(udev2dev(tapbasedev, 0), *dev); 31683043Sbrooks } 31771602Sphk} /* tapclone */ 31871602Sphk 31971602Sphk 32071602Sphk/* 32163670Snsayer * tapcreate 32263670Snsayer * 32363670Snsayer * to create interface 32463670Snsayer */ 32563670Snsayerstatic void 32663670Snsayertapcreate(dev) 32763670Snsayer dev_t dev; 32863670Snsayer{ 32963670Snsayer struct ifnet *ifp = NULL; 33063670Snsayer struct tap_softc *tp = NULL; 33163670Snsayer unsigned short macaddr_hi; 33263803Snsayer int unit, s; 33363670Snsayer char *name = NULL; 33463670Snsayer 33563670Snsayer /* allocate driver storage and create device */ 33669781Sdwmalone MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 33783043Sbrooks SLIST_INSERT_HEAD(&taphead, tp, tap_next); 33863670Snsayer 33983043Sbrooks unit = dev2unit(dev) & TAPMAXUNIT; 34083043Sbrooks 34163670Snsayer /* select device: tap or vmnet */ 34263670Snsayer if (minor(dev) & VMNET_DEV_MASK) { 34363670Snsayer name = VMNET; 34463803Snsayer tp->tap_flags |= TAP_VMNET; 34583043Sbrooks } else 34663670Snsayer name = TAP; 34763670Snsayer 34883043Sbrooks TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 34983043Sbrooks 35083043Sbrooks if (!(dev->si_flags & SI_NAMED)) 35183043Sbrooks dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 35263670Snsayer 0600, "%s%d", name, unit); 35363670Snsayer 35463670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 35563670Snsayer macaddr_hi = htons(0x00bd); 35663670Snsayer bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 35763670Snsayer bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 35863670Snsayer tp->arpcom.ac_enaddr[5] = (u_char)unit; 35963670Snsayer 36063670Snsayer /* fill the rest and attach interface */ 36163670Snsayer ifp = &tp->tap_if; 36263670Snsayer ifp->if_softc = tp; 36363670Snsayer ifp->if_unit = unit; 36463670Snsayer ifp->if_name = name; 36563670Snsayer ifp->if_init = tapifinit; 36663670Snsayer ifp->if_output = ether_output; 36763670Snsayer ifp->if_start = tapifstart; 36863670Snsayer ifp->if_ioctl = tapifioctl; 36963670Snsayer ifp->if_mtu = ETHERMTU; 37063670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 37163670Snsayer ifp->if_snd.ifq_maxlen = ifqmaxlen; 37263670Snsayer 37383043Sbrooks dev->si_drv1 = tp; 37483043Sbrooks 37563803Snsayer s = splimp(); 37683043Sbrooks ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 37763803Snsayer splx(s); 37863670Snsayer 37963803Snsayer tp->tap_flags |= TAP_INITED; 38063803Snsayer 38183043Sbrooks TAPDEBUG("interface %s%d is created. minor = %#x\n", 38283043Sbrooks ifp->if_name, ifp->if_unit, minor(dev)); 38363670Snsayer} /* tapcreate */ 38463670Snsayer 38563670Snsayer 38663670Snsayer/* 38763670Snsayer * tapopen 38863670Snsayer * 38963670Snsayer * to open tunnel. must be superuser 39063670Snsayer */ 39163670Snsayerstatic int 39283366Sjuliantapopen(dev, flag, mode, td) 39363670Snsayer dev_t dev; 39463670Snsayer int flag; 39563670Snsayer int mode; 39683366Sjulian struct thread *td; 39763670Snsayer{ 39863670Snsayer struct tap_softc *tp = NULL; 39983043Sbrooks int unit, error; 40083043Sbrooks struct resource *r = NULL; 40163670Snsayer 40283366Sjulian if ((error = suser_td(td)) != 0) 40363670Snsayer return (error); 40463670Snsayer 40583043Sbrooks unit = dev2unit(dev) & TAPMAXUNIT; 40683043Sbrooks 40783043Sbrooks if (minor(dev) & VMNET_DEV_MASK) 40883043Sbrooks r = rman_reserve_resource(vmnetunits, unit, unit, 1, 40983043Sbrooks RF_ALLOCATED | RF_ACTIVE, NULL); 41083043Sbrooks else 41183043Sbrooks r = rman_reserve_resource(tapunits, unit, unit, 1, 41283043Sbrooks RF_ALLOCATED | RF_ACTIVE, NULL); 41383043Sbrooks 41483043Sbrooks if (r == NULL) 41583043Sbrooks return (EBUSY); 41683043Sbrooks 41783043Sbrooks dev->si_flags &= ~SI_CHEAPCLONE; 41883043Sbrooks 41963670Snsayer tp = dev->si_drv1; 42063670Snsayer if (tp == NULL) { 42163670Snsayer tapcreate(dev); 42263670Snsayer tp = dev->si_drv1; 42363670Snsayer } 42463670Snsayer 42583043Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 42683043Sbrooks ("%s%d flags is out of sync", tp->tap_if.if_name, unit)); 42763670Snsayer 42863861Snsayer bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 42963861Snsayer 43083043Sbrooks tp->tap_unit = r; 43183366Sjulian tp->tap_pid = td->td_proc->p_pid; 43263670Snsayer tp->tap_flags |= TAP_OPEN; 43363670Snsayer 43483043Sbrooks TAPDEBUG("%s%d is open. minor = %#x\n", 43583043Sbrooks tp->tap_if.if_name, unit, minor(dev)); 43663670Snsayer 43763670Snsayer return (0); 43863670Snsayer} /* tapopen */ 43963670Snsayer 44063670Snsayer 44163670Snsayer/* 44263670Snsayer * tapclose 44363670Snsayer * 44463670Snsayer * close the device - mark i/f down & delete routing info 44563670Snsayer */ 44663670Snsayerstatic int 44783366Sjuliantapclose(dev, foo, bar, td) 44863670Snsayer dev_t dev; 44963670Snsayer int foo; 45063670Snsayer int bar; 45183366Sjulian struct thread *td; 45263670Snsayer{ 45383043Sbrooks int s, error; 45463670Snsayer struct tap_softc *tp = dev->si_drv1; 45563670Snsayer struct ifnet *ifp = &tp->tap_if; 45663670Snsayer 45783043Sbrooks KASSERT((tp->tap_unit != NULL), 45883043Sbrooks ("%s%d is not open", ifp->if_name, ifp->if_unit)); 45983043Sbrooks 46063670Snsayer /* junk all pending output */ 46183043Sbrooks IF_DRAIN(&ifp->if_snd); 46263670Snsayer 46363803Snsayer /* 46463803Snsayer * do not bring the interface down, and do not anything with 46563803Snsayer * interface, if we are in VMnet mode. just close the device. 46663803Snsayer */ 46763803Snsayer 46863803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 46963670Snsayer s = splimp(); 47063670Snsayer if_down(ifp); 47163670Snsayer if (ifp->if_flags & IFF_RUNNING) { 47263670Snsayer /* find internet addresses and delete routes */ 47363670Snsayer struct ifaddr *ifa = NULL; 47463670Snsayer 47563803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 47663670Snsayer if (ifa->ifa_addr->sa_family == AF_INET) { 47763670Snsayer rtinit(ifa, (int)RTM_DELETE, 0); 47863670Snsayer 47963670Snsayer /* remove address from interface */ 48063670Snsayer bzero(ifa->ifa_addr, 48163670Snsayer sizeof(*(ifa->ifa_addr))); 48263670Snsayer bzero(ifa->ifa_dstaddr, 48363670Snsayer sizeof(*(ifa->ifa_dstaddr))); 48463670Snsayer bzero(ifa->ifa_netmask, 48563670Snsayer sizeof(*(ifa->ifa_netmask))); 48663670Snsayer } 48763670Snsayer } 48863670Snsayer 48963670Snsayer ifp->if_flags &= ~IFF_RUNNING; 49063670Snsayer } 49163670Snsayer splx(s); 49263670Snsayer } 49363670Snsayer 49463670Snsayer funsetown(tp->tap_sigio); 49563670Snsayer selwakeup(&tp->tap_rsel); 49663670Snsayer 49763670Snsayer tp->tap_flags &= ~TAP_OPEN; 49863670Snsayer tp->tap_pid = 0; 49983043Sbrooks error = rman_release_resource(tp->tap_unit); 50083043Sbrooks KASSERT((error == 0), 50183043Sbrooks ("%s%d could not release unit", ifp->if_name, ifp->if_unit)); 50283043Sbrooks tp->tap_unit = NULL; 50363670Snsayer 50483043Sbrooks TAPDEBUG("%s%d is closed. minor = %#x\n", 50583043Sbrooks ifp->if_name, ifp->if_unit, minor(dev)); 50663670Snsayer 50763670Snsayer return (0); 50863670Snsayer} /* tapclose */ 50963670Snsayer 51063670Snsayer 51163670Snsayer/* 51263670Snsayer * tapifinit 51363670Snsayer * 51463670Snsayer * network interface initialization function 51563670Snsayer */ 51663670Snsayerstatic void 51763670Snsayertapifinit(xtp) 51863670Snsayer void *xtp; 51963670Snsayer{ 52063670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 52163670Snsayer struct ifnet *ifp = &tp->tap_if; 52263670Snsayer 52383043Sbrooks TAPDEBUG("initializing %s%d\n", ifp->if_name, ifp->if_unit); 52463670Snsayer 52563670Snsayer ifp->if_flags |= IFF_RUNNING; 52663670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 52763670Snsayer 52863670Snsayer /* attempt to start output */ 52963670Snsayer tapifstart(ifp); 53063670Snsayer} /* tapifinit */ 53163670Snsayer 53263670Snsayer 53363670Snsayer/* 53463670Snsayer * tapifioctl 53563670Snsayer * 53663670Snsayer * Process an ioctl request on network interface 53763670Snsayer */ 53863670Snsayerint 53963670Snsayertapifioctl(ifp, cmd, data) 54063670Snsayer struct ifnet *ifp; 54163670Snsayer u_long cmd; 54263670Snsayer caddr_t data; 54363670Snsayer{ 54463670Snsayer struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 54563670Snsayer struct ifstat *ifs = NULL; 54663670Snsayer int s, dummy; 54763670Snsayer 54863670Snsayer switch (cmd) { 54963670Snsayer case SIOCSIFADDR: 55063670Snsayer case SIOCGIFADDR: 55163670Snsayer case SIOCSIFMTU: 55263670Snsayer s = splimp(); 55363670Snsayer dummy = ether_ioctl(ifp, cmd, data); 55463670Snsayer splx(s); 55563670Snsayer return (dummy); 55663670Snsayer 55763670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 55863670Snsayer case SIOCADDMULTI: 55963670Snsayer case SIOCDELMULTI: 56083043Sbrooks break; 56163670Snsayer 56263670Snsayer case SIOCGIFSTATUS: 56363670Snsayer s = splimp(); 56463670Snsayer ifs = (struct ifstat *)data; 56563670Snsayer dummy = strlen(ifs->ascii); 56663670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 56763670Snsayer snprintf(ifs->ascii + dummy, 56863670Snsayer sizeof(ifs->ascii) - dummy, 56963670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 57063670Snsayer splx(s); 57183043Sbrooks break; 57263670Snsayer 57363670Snsayer default: 57463670Snsayer return (EINVAL); 57563670Snsayer } 57663670Snsayer 57763670Snsayer return (0); 57863670Snsayer} /* tapifioctl */ 57963670Snsayer 58063670Snsayer 58163670Snsayer/* 58263670Snsayer * tapifstart 58363670Snsayer * 58463670Snsayer * queue packets from higher level ready to put out 58563670Snsayer */ 58663670Snsayerstatic void 58763670Snsayertapifstart(ifp) 58863670Snsayer struct ifnet *ifp; 58963670Snsayer{ 59063670Snsayer struct tap_softc *tp = ifp->if_softc; 59163670Snsayer int s; 59263670Snsayer 59383043Sbrooks TAPDEBUG("%s%d starting\n", ifp->if_name, ifp->if_unit); 59463670Snsayer 59563803Snsayer /* 59663803Snsayer * do not junk pending output if we are in VMnet mode. 59763803Snsayer * XXX: can this do any harm because of queue overflow? 59863803Snsayer */ 59963803Snsayer 60063803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && 60163803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 60263670Snsayer struct mbuf *m = NULL; 60363670Snsayer 60483043Sbrooks TAPDEBUG("%s%d not ready, tap_flags = 0x%x\n", ifp->if_name, 60583043Sbrooks ifp->if_unit, tp->tap_flags); 60663670Snsayer 60763670Snsayer s = splimp(); 60863670Snsayer do { 60963670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 61063670Snsayer if (m != NULL) 61163670Snsayer m_freem(m); 61263670Snsayer ifp->if_oerrors ++; 61363670Snsayer } while (m != NULL); 61463670Snsayer splx(s); 61563670Snsayer 61663670Snsayer return; 61763670Snsayer } 61863670Snsayer 61963670Snsayer s = splimp(); 62063670Snsayer ifp->if_flags |= IFF_OACTIVE; 62163670Snsayer 62263670Snsayer if (ifp->if_snd.ifq_len != 0) { 62363670Snsayer if (tp->tap_flags & TAP_RWAIT) { 62463670Snsayer tp->tap_flags &= ~TAP_RWAIT; 62563670Snsayer wakeup((caddr_t)tp); 62663670Snsayer } 62763670Snsayer 62863670Snsayer if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) 62963670Snsayer pgsigio(tp->tap_sigio, SIGIO, 0); 63063670Snsayer 63163670Snsayer selwakeup(&tp->tap_rsel); 63263670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 63363670Snsayer } 63463670Snsayer 63563670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 63663670Snsayer splx(s); 63763670Snsayer} /* tapifstart */ 63863670Snsayer 63963670Snsayer 64063670Snsayer/* 64163670Snsayer * tapioctl 64263670Snsayer * 64363670Snsayer * the cdevsw interface is now pretty minimal 64463670Snsayer */ 64563670Snsayerstatic int 64683366Sjuliantapioctl(dev, cmd, data, flag, td) 64763670Snsayer dev_t dev; 64863670Snsayer u_long cmd; 64963670Snsayer caddr_t data; 65063670Snsayer int flag; 65183366Sjulian struct thread *td; 65263670Snsayer{ 65363670Snsayer struct tap_softc *tp = dev->si_drv1; 65463670Snsayer struct ifnet *ifp = &tp->tap_if; 65563670Snsayer struct tapinfo *tapp = NULL; 65663670Snsayer int s; 65783043Sbrooks short f; 65863670Snsayer 65963670Snsayer switch (cmd) { 66063670Snsayer case TAPSIFINFO: 66163670Snsayer s = splimp(); 66263670Snsayer tapp = (struct tapinfo *)data; 66363670Snsayer ifp->if_mtu = tapp->mtu; 66463670Snsayer ifp->if_type = tapp->type; 66563670Snsayer ifp->if_baudrate = tapp->baudrate; 66663670Snsayer splx(s); 66783043Sbrooks break; 66863670Snsayer 66963670Snsayer case TAPGIFINFO: 67063670Snsayer tapp = (struct tapinfo *)data; 67163670Snsayer tapp->mtu = ifp->if_mtu; 67263670Snsayer tapp->type = ifp->if_type; 67363670Snsayer tapp->baudrate = ifp->if_baudrate; 67483043Sbrooks break; 67563670Snsayer 67663670Snsayer case TAPSDEBUG: 67763670Snsayer tapdebug = *(int *)data; 67883043Sbrooks break; 67963670Snsayer 68063670Snsayer case TAPGDEBUG: 68163670Snsayer *(int *)data = tapdebug; 68283043Sbrooks break; 68363670Snsayer 68463670Snsayer case FIONBIO: 68583043Sbrooks break; 68663670Snsayer 68763670Snsayer case FIOASYNC: 68863803Snsayer s = splimp(); 68963670Snsayer if (*(int *)data) 69063670Snsayer tp->tap_flags |= TAP_ASYNC; 69163670Snsayer else 69263670Snsayer tp->tap_flags &= ~TAP_ASYNC; 69363803Snsayer splx(s); 69483043Sbrooks break; 69563670Snsayer 69663670Snsayer case FIONREAD: 69763670Snsayer s = splimp(); 69863670Snsayer if (ifp->if_snd.ifq_head) { 69963670Snsayer struct mbuf *mb = ifp->if_snd.ifq_head; 70063670Snsayer 70163803Snsayer for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 70263670Snsayer *(int *)data += mb->m_len; 70383043Sbrooks } else 70463670Snsayer *(int *)data = 0; 70563670Snsayer splx(s); 70683043Sbrooks break; 70763670Snsayer 70863670Snsayer case FIOSETOWN: 70963670Snsayer return (fsetown(*(int *)data, &tp->tap_sigio)); 71063670Snsayer 71163670Snsayer case FIOGETOWN: 71263670Snsayer *(int *)data = fgetown(tp->tap_sigio); 71363670Snsayer return (0); 71463670Snsayer 71563670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 71663670Snsayer case TIOCSPGRP: 71763670Snsayer return (fsetown(-(*(int *)data), &tp->tap_sigio)); 71863670Snsayer 71963670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 72063670Snsayer case TIOCGPGRP: 72163670Snsayer *(int *)data = -fgetown(tp->tap_sigio); 72263670Snsayer return (0); 72363670Snsayer 72463670Snsayer /* VMware/VMnet port ioctl's */ 72563670Snsayer 72663670Snsayer case SIOCGIFFLAGS: /* get ifnet flags */ 72763670Snsayer bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 72883043Sbrooks break; 72963670Snsayer 73083043Sbrooks case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 73183043Sbrooks f = *(short *)data; 73263670Snsayer f &= 0x0fff; 73363670Snsayer f &= ~IFF_CANTCHANGE; 73463670Snsayer f |= IFF_UP; 73563670Snsayer 73663670Snsayer s = splimp(); 73763670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 73863670Snsayer splx(s); 73983043Sbrooks break; 74063670Snsayer 74163861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 74263670Snsayer case SIOCGIFADDR: 74363861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 74483043Sbrooks break; 74563670Snsayer 74663861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 74763861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 74883043Sbrooks break; 74963670Snsayer 75063670Snsayer default: 75163670Snsayer return (ENOTTY); 75263670Snsayer } 75363670Snsayer return (0); 75463670Snsayer} /* tapioctl */ 75563670Snsayer 75663670Snsayer 75763670Snsayer/* 75863670Snsayer * tapread 75963670Snsayer * 76063670Snsayer * the cdevsw read interface - reads a packet at a time, or at 76163670Snsayer * least as much of a packet as can be read 76263670Snsayer */ 76363670Snsayerstatic int 76463670Snsayertapread(dev, uio, flag) 76563670Snsayer dev_t dev; 76663670Snsayer struct uio *uio; 76763670Snsayer int flag; 76863670Snsayer{ 76963670Snsayer struct tap_softc *tp = dev->si_drv1; 77063670Snsayer struct ifnet *ifp = &tp->tap_if; 77163670Snsayer struct mbuf *m = NULL, *m0 = NULL; 77263670Snsayer int error = 0, len, s; 77363670Snsayer 77483043Sbrooks TAPDEBUG("%s%d reading, minor = %#x\n", 77583043Sbrooks ifp->if_name, ifp->if_unit, minor(dev)); 77663670Snsayer 77763670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 77863803Snsayer TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n", 77983043Sbrooks ifp->if_name, ifp->if_unit, minor(dev), tp->tap_flags); 78063803Snsayer 78163670Snsayer return (EHOSTDOWN); 78263670Snsayer } 78363670Snsayer 78463670Snsayer tp->tap_flags &= ~TAP_RWAIT; 78563670Snsayer 78663670Snsayer /* sleep until we get a packet */ 78763670Snsayer do { 78863670Snsayer s = splimp(); 78963670Snsayer IF_DEQUEUE(&ifp->if_snd, m0); 79063670Snsayer splx(s); 79163670Snsayer 79263670Snsayer if (m0 == NULL) { 79363670Snsayer if (flag & IO_NDELAY) 79463670Snsayer return (EWOULDBLOCK); 79563670Snsayer 79663670Snsayer tp->tap_flags |= TAP_RWAIT; 79763670Snsayer error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0); 79863670Snsayer if (error) 79963670Snsayer return (error); 80063670Snsayer } 80163803Snsayer } while (m0 == NULL); 80263670Snsayer 80363670Snsayer /* feed packet to bpf */ 80463670Snsayer if (ifp->if_bpf != NULL) 80563670Snsayer bpf_mtap(ifp, m0); 80663670Snsayer 80763670Snsayer /* xfer packet to user space */ 80863670Snsayer while ((m0 != NULL) && (uio->uio_resid > 0) && (error == 0)) { 80963670Snsayer len = min(uio->uio_resid, m0->m_len); 81063670Snsayer if (len == 0) 81163670Snsayer break; 81263670Snsayer 81363670Snsayer error = uiomove(mtod(m0, caddr_t), len, uio); 81463670Snsayer MFREE(m0, m); 81563670Snsayer m0 = m; 81663670Snsayer } 81763670Snsayer 81863670Snsayer if (m0 != NULL) { 81983043Sbrooks TAPDEBUG("%s%d dropping mbuf, minor = %#x\n", ifp->if_name, 82083043Sbrooks ifp->if_unit, minor(dev)); 82163670Snsayer m_freem(m0); 82263670Snsayer } 82363670Snsayer 82463670Snsayer return (error); 82563670Snsayer} /* tapread */ 82663670Snsayer 82763670Snsayer 82863670Snsayer/* 82963670Snsayer * tapwrite 83063670Snsayer * 83163670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 83263670Snsayer */ 83363670Snsayerstatic int 83463670Snsayertapwrite(dev, uio, flag) 83563670Snsayer dev_t dev; 83663670Snsayer struct uio *uio; 83763670Snsayer int flag; 83863670Snsayer{ 83963670Snsayer struct tap_softc *tp = dev->si_drv1; 84063670Snsayer struct ifnet *ifp = &tp->tap_if; 84163670Snsayer struct mbuf *top = NULL, **mp = NULL, *m = NULL; 84263670Snsayer struct ether_header *eh = NULL; 84363670Snsayer int error = 0, tlen, mlen; 84463670Snsayer 84583043Sbrooks TAPDEBUG("%s%d writting, minor = %#x\n", 84683043Sbrooks ifp->if_name, ifp->if_unit, minor(dev)); 84763670Snsayer 84863670Snsayer if (uio->uio_resid == 0) 84963670Snsayer return (0); 85063670Snsayer 85163670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 85263803Snsayer TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n", 85383043Sbrooks ifp->if_name, ifp->if_unit, uio->uio_resid, minor(dev)); 85463803Snsayer 85563670Snsayer return (EIO); 85663670Snsayer } 85763670Snsayer tlen = uio->uio_resid; 85863670Snsayer 85963670Snsayer /* get a header mbuf */ 86063670Snsayer MGETHDR(m, M_DONTWAIT, MT_DATA); 86163670Snsayer if (m == NULL) 86263670Snsayer return (ENOBUFS); 86363670Snsayer mlen = MHLEN; 86463670Snsayer 86563670Snsayer top = 0; 86663670Snsayer mp = ⊤ 86763670Snsayer while ((error == 0) && (uio->uio_resid > 0)) { 86863670Snsayer m->m_len = min(mlen, uio->uio_resid); 86963670Snsayer error = uiomove(mtod(m, caddr_t), m->m_len, uio); 87063670Snsayer *mp = m; 87163670Snsayer mp = &m->m_next; 87263670Snsayer if (uio->uio_resid > 0) { 87363670Snsayer MGET(m, M_DONTWAIT, MT_DATA); 87463803Snsayer if (m == NULL) { 87563670Snsayer error = ENOBUFS; 87663670Snsayer break; 87763670Snsayer } 87863670Snsayer mlen = MLEN; 87963670Snsayer } 88063670Snsayer } 88163670Snsayer if (error) { 88263670Snsayer ifp->if_ierrors ++; 88363670Snsayer if (top) 88463670Snsayer m_freem(top); 88563670Snsayer return (error); 88663670Snsayer } 88763670Snsayer 88863670Snsayer top->m_pkthdr.len = tlen; 88963670Snsayer top->m_pkthdr.rcvif = ifp; 89063670Snsayer 89163670Snsayer /* 89263670Snsayer * Ethernet bridge and bpf are handled in ether_input 89363670Snsayer * 89463670Snsayer * adjust mbuf and give packet to the ether_input 89563670Snsayer */ 89663670Snsayer 89763670Snsayer eh = mtod(top, struct ether_header *); 89863670Snsayer m_adj(top, sizeof(struct ether_header)); 89963670Snsayer ether_input(ifp, eh, top); 90063670Snsayer ifp->if_ipackets ++; /* ibytes are counted in ether_input */ 90163670Snsayer 90263670Snsayer return (0); 90363670Snsayer} /* tapwrite */ 90463670Snsayer 90563670Snsayer 90663670Snsayer/* 90763670Snsayer * tappoll 90863670Snsayer * 90963670Snsayer * the poll interface, this is only useful on reads 91063670Snsayer * really. the write detect always returns true, write never blocks 91163670Snsayer * anyway, it either accepts the packet or drops it 91263670Snsayer */ 91363670Snsayerstatic int 91483366Sjuliantappoll(dev, events, td) 91563670Snsayer dev_t dev; 91663670Snsayer int events; 91783366Sjulian struct thread *td; 91863670Snsayer{ 91963670Snsayer struct tap_softc *tp = dev->si_drv1; 92063670Snsayer struct ifnet *ifp = &tp->tap_if; 92163670Snsayer int s, revents = 0; 92263670Snsayer 92383043Sbrooks TAPDEBUG("%s%d polling, minor = %#x\n", 92483043Sbrooks ifp->if_name, ifp->if_unit, minor(dev)); 92563670Snsayer 92663670Snsayer s = splimp(); 92763670Snsayer if (events & (POLLIN | POLLRDNORM)) { 92863670Snsayer if (ifp->if_snd.ifq_len > 0) { 92963803Snsayer TAPDEBUG("%s%d have data in queue. len = %d, " \ 93063803Snsayer "minor = %#x\n", ifp->if_name, ifp->if_unit, 93183043Sbrooks ifp->if_snd.ifq_len, minor(dev)); 93263803Snsayer 93363670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 93483043Sbrooks } else { 93563803Snsayer TAPDEBUG("%s%d waiting for data, minor = %#x\n", 93683043Sbrooks ifp->if_name, ifp->if_unit, minor(dev)); 93763803Snsayer 93883366Sjulian selrecord(curthread, &tp->tap_rsel); 93963670Snsayer } 94063670Snsayer } 94163670Snsayer 94263670Snsayer if (events & (POLLOUT | POLLWRNORM)) 94363670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 94463670Snsayer 94563670Snsayer splx(s); 94663670Snsayer return (revents); 94763670Snsayer} /* tappoll */ 948