if_tap.c revision 122352
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 122352 2003-11-09 09:17:26Z tanimura $ 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 */ 84111742Sdesstatic 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 = { 104111815Sphk .d_open = tapopen, 105111815Sphk .d_close = tapclose, 106111815Sphk .d_read = tapread, 107111815Sphk .d_write = tapwrite, 108111815Sphk .d_ioctl = tapioctl, 109111815Sphk .d_poll = tappoll, 110111815Sphk .d_name = CDEV_NAME, 111111815Sphk .d_maj = CDEV_MAJOR, 11263670Snsayer}; 11363670Snsayer 11483043Sbrooksstatic int tapdebug = 0; /* debug flag */ 11583043Sbrooksstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 11683043Sbrooksstatic udev_t tapbasedev = NOUDEV; /* base device */ 11783043Sbrooksstatic struct rman tapdevunits[2]; /* device units */ 11883043Sbrooks#define tapunits tapdevunits 11983043Sbrooks#define vmnetunits (tapdevunits + 1) 12063670Snsayer 12163670SnsayerMALLOC_DECLARE(M_TAP); 12263670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 12363670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 12463670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL); 12563670Snsayer 12663670Snsayer/* 12763670Snsayer * tapmodevent 12863670Snsayer * 12963670Snsayer * module event handler 13063670Snsayer */ 13163670Snsayerstatic int 13263670Snsayertapmodevent(mod, type, data) 13363670Snsayer module_t mod; 13463670Snsayer int type; 13563670Snsayer void *data; 13663670Snsayer{ 13783043Sbrooks static eventhandler_tag eh_tag = NULL; 13883043Sbrooks struct tap_softc *tp = NULL; 13983043Sbrooks struct ifnet *ifp = NULL; 14083043Sbrooks int error, s; 14163670Snsayer 14263670Snsayer switch (type) { 14363670Snsayer case MOD_LOAD: 14483043Sbrooks /* initialize resources */ 14583043Sbrooks tapunits->rm_type = RMAN_ARRAY; 14683043Sbrooks tapunits->rm_descr = "open tap units"; 14783043Sbrooks vmnetunits->rm_type = RMAN_ARRAY; 14883043Sbrooks vmnetunits->rm_descr = "open vmnet units"; 14963670Snsayer 15083043Sbrooks error = rman_init(tapunits); 15183043Sbrooks if (error != 0) 15283043Sbrooks goto bail; 15383043Sbrooks 15483043Sbrooks error = rman_init(vmnetunits); 15583043Sbrooks if (error != 0) 15683043Sbrooks goto bail1; 15783043Sbrooks 15883043Sbrooks error = rman_manage_region(tapunits, 0, TAPMAXUNIT); 15983043Sbrooks if (error != 0) 16083043Sbrooks goto bail2; 16183043Sbrooks 16283043Sbrooks error = rman_manage_region(vmnetunits, 0, TAPMAXUNIT); 16383043Sbrooks if (error != 0) 16483043Sbrooks goto bail2; 16583043Sbrooks 16683043Sbrooks /* intitialize device */ 16783043Sbrooks 16883043Sbrooks SLIST_INIT(&taphead); 16983043Sbrooks 17071602Sphk eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 17183043Sbrooks if (eh_tag == NULL) { 17283043Sbrooks error = ENOMEM; 17383043Sbrooks goto bail2; 17483043Sbrooks } 17563670Snsayer 17671602Sphk 17783043Sbrooks return (0); 17883043Sbrooksbail2: 17983043Sbrooks rman_fini(vmnetunits); 18083043Sbrooksbail1: 18183043Sbrooks rman_fini(tapunits); 18283043Sbrooksbail: 18383043Sbrooks return (error); 18463670Snsayer 18583043Sbrooks case MOD_UNLOAD: 18683043Sbrooks SLIST_FOREACH(tp, &taphead, tap_next) 18783043Sbrooks if (tp->tap_unit != NULL) 18883043Sbrooks return (EBUSY); 18983043Sbrooks 19071602Sphk EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 19163670Snsayer 19283043Sbrooks error = rman_fini(tapunits); 19383043Sbrooks KASSERT((error == 0), ("Could not fini tap units")); 19483043Sbrooks error = rman_fini(vmnetunits); 19583043Sbrooks KASSERT((error == 0), ("Could not fini vmnet units")); 19671602Sphk 19783043Sbrooks while ((tp = SLIST_FIRST(&taphead)) != NULL) { 19883043Sbrooks SLIST_REMOVE_HEAD(&taphead, tap_next); 19983043Sbrooks 20083043Sbrooks ifp = &tp->tap_if; 20183043Sbrooks 202121816Sbrooks TAPDEBUG("detaching %s\n", ifp->if_xname); 20383043Sbrooks 204121816Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 205121816Sbrooks ("%s flags is out of sync", ifp->if_xname)); 20683043Sbrooks 20783043Sbrooks /* XXX makedev check? nah.. not right now :) */ 20883043Sbrooks 20963670Snsayer s = splimp(); 210106939Ssam ether_ifdetach(ifp); 21163670Snsayer splx(s); 21263670Snsayer 21393752Sluigi free(tp, M_TAP); 21483043Sbrooks } 21563670Snsayer 216111742Sdes if (tapbasedev != NOUDEV) 21783043Sbrooks destroy_dev(udev2dev(tapbasedev, 0)); 21863670Snsayer 21963670Snsayer 22083043Sbrooks break; 22163670Snsayer 22263670Snsayer default: 22363670Snsayer return (EOPNOTSUPP); 22463670Snsayer } 22563670Snsayer 22663670Snsayer return (0); 22763670Snsayer} /* tapmodevent */ 22863670Snsayer 22963670Snsayer 23063670Snsayer/* 23171602Sphk * DEVFS handler 23271602Sphk * 23371602Sphk * We need to support two kind of devices - tap and vmnet 23471602Sphk */ 23571602Sphkstatic void 23671602Sphktapclone(arg, name, namelen, dev) 23771602Sphk void *arg; 23871602Sphk char *name; 23971602Sphk int namelen; 24071602Sphk dev_t *dev; 24171602Sphk{ 24283043Sbrooks int unit, minor = 0 /* XXX avoid warning */ , error; 24383043Sbrooks char *device_name = name; 24483043Sbrooks struct resource *r = NULL; 24571602Sphk 24671602Sphk if (*dev != NODEV) 24771602Sphk return; 24871602Sphk 24983043Sbrooks if (strcmp(device_name, TAP) == 0) { 25083043Sbrooks /* get first free tap unit */ 251111742Sdes r = rman_reserve_resource(tapunits, 0, TAPMAXUNIT, 1, 25283043Sbrooks RF_ALLOCATED | RF_ACTIVE, NULL); 25383043Sbrooks unit = rman_get_start(r); 25483043Sbrooks minor = unit2minor(unit); 25583043Sbrooks } 25683043Sbrooks else if (strcmp(device_name, VMNET) == 0) { 25783043Sbrooks /* get first free vmnet unit */ 258111742Sdes r = rman_reserve_resource(vmnetunits, 0, TAPMAXUNIT, 1, 25983043Sbrooks RF_ALLOCATED | RF_ACTIVE, NULL); 26083043Sbrooks unit = rman_get_start(r); 26183043Sbrooks minor = unit2minor(unit) | VMNET_DEV_MASK; 26283043Sbrooks } 26371602Sphk 26483043Sbrooks if (r != NULL) { /* need cloning */ 26583043Sbrooks TAPDEBUG("%s%d is available. minor = %#x\n", 26683043Sbrooks device_name, unit, minor); 26771602Sphk 26883043Sbrooks error = rman_release_resource(r); 26983043Sbrooks KASSERT((error == 0), ("Could not release tap/vmnet unit")); 27083043Sbrooks 27183043Sbrooks /* check if device for the unit has been created */ 27283043Sbrooks *dev = makedev(CDEV_MAJOR, minor); 27383043Sbrooks if ((*dev)->si_flags & SI_NAMED) { 274111742Sdes TAPDEBUG("%s%d device exists. minor = %#x\n", 27583043Sbrooks device_name, unit, minor); 27683043Sbrooks return; /* device has been created */ 27783043Sbrooks } 27883043Sbrooks } else { /* try to match name/unit, first try tap then vmnet */ 27983043Sbrooks device_name = TAP; 28083043Sbrooks if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 28183043Sbrooks device_name = VMNET; 28283043Sbrooks 28383043Sbrooks if (dev_stdclone(name, NULL, device_name, &unit) != 1) 28483043Sbrooks return; 28583043Sbrooks 28683043Sbrooks minor = unit2minor(unit) | VMNET_DEV_MASK; 28783043Sbrooks } else 28883043Sbrooks minor = unit2minor(unit); 28971602Sphk } 29071602Sphk 29183043Sbrooks TAPDEBUG("make_dev(%s%d). minor = %#x\n", device_name, unit, minor); 29283043Sbrooks 29371602Sphk *dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d", 29471602Sphk device_name, unit); 29583043Sbrooks 29683043Sbrooks if (tapbasedev == NOUDEV) 29783043Sbrooks tapbasedev = (*dev)->si_udev; 29883043Sbrooks else { 29983043Sbrooks (*dev)->si_flags |= SI_CHEAPCLONE; 30083043Sbrooks dev_depends(udev2dev(tapbasedev, 0), *dev); 30183043Sbrooks } 30271602Sphk} /* tapclone */ 30371602Sphk 30471602Sphk 30571602Sphk/* 30663670Snsayer * tapcreate 30763670Snsayer * 30863670Snsayer * to create interface 30963670Snsayer */ 31063670Snsayerstatic void 31163670Snsayertapcreate(dev) 31263670Snsayer dev_t dev; 31363670Snsayer{ 31463670Snsayer struct ifnet *ifp = NULL; 31563670Snsayer struct tap_softc *tp = NULL; 31663670Snsayer unsigned short macaddr_hi; 31763803Snsayer int unit, s; 31863670Snsayer char *name = NULL; 31963670Snsayer 32063670Snsayer /* allocate driver storage and create device */ 321111119Simp MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 32283043Sbrooks SLIST_INSERT_HEAD(&taphead, tp, tap_next); 32363670Snsayer 32483043Sbrooks unit = dev2unit(dev) & TAPMAXUNIT; 32583043Sbrooks 32663670Snsayer /* select device: tap or vmnet */ 32763670Snsayer if (minor(dev) & VMNET_DEV_MASK) { 32863670Snsayer name = VMNET; 32963803Snsayer tp->tap_flags |= TAP_VMNET; 33083043Sbrooks } else 33163670Snsayer name = TAP; 33263670Snsayer 33383043Sbrooks TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 33483043Sbrooks 33583043Sbrooks if (!(dev->si_flags & SI_NAMED)) 336111742Sdes dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 33763670Snsayer 0600, "%s%d", name, unit); 33863670Snsayer 33963670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 34063670Snsayer macaddr_hi = htons(0x00bd); 34163670Snsayer bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 34263670Snsayer bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 34363670Snsayer tp->arpcom.ac_enaddr[5] = (u_char)unit; 34463670Snsayer 345111742Sdes /* fill the rest and attach interface */ 34663670Snsayer ifp = &tp->tap_if; 34763670Snsayer ifp->if_softc = tp; 348121816Sbrooks if_initname(ifp, name, unit); 34963670Snsayer ifp->if_init = tapifinit; 35063670Snsayer ifp->if_start = tapifstart; 35163670Snsayer ifp->if_ioctl = tapifioctl; 35263670Snsayer ifp->if_mtu = ETHERMTU; 35363670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 35463670Snsayer ifp->if_snd.ifq_maxlen = ifqmaxlen; 35563670Snsayer 35683043Sbrooks dev->si_drv1 = tp; 35783043Sbrooks 35863803Snsayer s = splimp(); 359106939Ssam ether_ifattach(ifp, tp->arpcom.ac_enaddr); 36063803Snsayer splx(s); 36163670Snsayer 36263803Snsayer tp->tap_flags |= TAP_INITED; 36363803Snsayer 364121816Sbrooks TAPDEBUG("interface %s is created. minor = %#x\n", 365121816Sbrooks ifp->if_xname, minor(dev)); 36663670Snsayer} /* tapcreate */ 36763670Snsayer 36863670Snsayer 36963670Snsayer/* 370111742Sdes * tapopen 37163670Snsayer * 37263670Snsayer * to open tunnel. must be superuser 37363670Snsayer */ 37463670Snsayerstatic int 37583366Sjuliantapopen(dev, flag, mode, td) 37663670Snsayer dev_t dev; 37763670Snsayer int flag; 37863670Snsayer int mode; 37983366Sjulian struct thread *td; 38063670Snsayer{ 38163670Snsayer struct tap_softc *tp = NULL; 38283043Sbrooks int unit, error; 38383043Sbrooks struct resource *r = NULL; 38463670Snsayer 38593593Sjhb if ((error = suser(td)) != 0) 38663670Snsayer return (error); 38763670Snsayer 38883043Sbrooks unit = dev2unit(dev) & TAPMAXUNIT; 38983043Sbrooks 39083043Sbrooks if (minor(dev) & VMNET_DEV_MASK) 391111742Sdes r = rman_reserve_resource(vmnetunits, unit, unit, 1, 39283043Sbrooks RF_ALLOCATED | RF_ACTIVE, NULL); 39383043Sbrooks else 394111742Sdes r = rman_reserve_resource(tapunits, unit, unit, 1, 39583043Sbrooks RF_ALLOCATED | RF_ACTIVE, NULL); 39683043Sbrooks 39783043Sbrooks if (r == NULL) 39883043Sbrooks return (EBUSY); 39983043Sbrooks 40083043Sbrooks dev->si_flags &= ~SI_CHEAPCLONE; 40183043Sbrooks 40263670Snsayer tp = dev->si_drv1; 40363670Snsayer if (tp == NULL) { 40463670Snsayer tapcreate(dev); 40563670Snsayer tp = dev->si_drv1; 40663670Snsayer } 40763670Snsayer 408121816Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 409121816Sbrooks ("%s flags is out of sync", tp->tap_if.if_xname)); 41063670Snsayer 41163861Snsayer bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 41263861Snsayer 41383043Sbrooks tp->tap_unit = r; 41483366Sjulian tp->tap_pid = td->td_proc->p_pid; 41563670Snsayer tp->tap_flags |= TAP_OPEN; 41663670Snsayer 417121816Sbrooks TAPDEBUG("%s is open. minor = %#x\n", 418121816Sbrooks tp->tap_if.if_xname, minor(dev)); 41963670Snsayer 42063670Snsayer return (0); 42163670Snsayer} /* tapopen */ 42263670Snsayer 42363670Snsayer 42463670Snsayer/* 42563670Snsayer * tapclose 42663670Snsayer * 42763670Snsayer * close the device - mark i/f down & delete routing info 42863670Snsayer */ 42963670Snsayerstatic int 43083366Sjuliantapclose(dev, foo, bar, td) 43163670Snsayer dev_t dev; 43263670Snsayer int foo; 43363670Snsayer int bar; 43483366Sjulian struct thread *td; 43563670Snsayer{ 43683043Sbrooks int s, error; 43763670Snsayer struct tap_softc *tp = dev->si_drv1; 43863670Snsayer struct ifnet *ifp = &tp->tap_if; 43963670Snsayer 44087914Sjlemon KASSERT((tp->tap_unit != NULL), 441121816Sbrooks ("%s is not open", ifp->if_xname)); 44283043Sbrooks 44363670Snsayer /* junk all pending output */ 44483043Sbrooks IF_DRAIN(&ifp->if_snd); 44563670Snsayer 44663803Snsayer /* 44763803Snsayer * do not bring the interface down, and do not anything with 44863803Snsayer * interface, if we are in VMnet mode. just close the device. 44963803Snsayer */ 45063803Snsayer 45163803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 45263670Snsayer s = splimp(); 45363670Snsayer if_down(ifp); 45463670Snsayer if (ifp->if_flags & IFF_RUNNING) { 45563670Snsayer /* find internet addresses and delete routes */ 45663670Snsayer struct ifaddr *ifa = NULL; 45763670Snsayer 45863803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 45963670Snsayer if (ifa->ifa_addr->sa_family == AF_INET) { 46063670Snsayer rtinit(ifa, (int)RTM_DELETE, 0); 46163670Snsayer 46263670Snsayer /* remove address from interface */ 463111742Sdes bzero(ifa->ifa_addr, 46463670Snsayer sizeof(*(ifa->ifa_addr))); 465111742Sdes bzero(ifa->ifa_dstaddr, 46663670Snsayer sizeof(*(ifa->ifa_dstaddr))); 467111742Sdes bzero(ifa->ifa_netmask, 46863670Snsayer sizeof(*(ifa->ifa_netmask))); 46963670Snsayer } 47063670Snsayer } 47163670Snsayer 47263670Snsayer ifp->if_flags &= ~IFF_RUNNING; 47363670Snsayer } 47463670Snsayer splx(s); 47563670Snsayer } 47663670Snsayer 47796122Salfred funsetown(&tp->tap_sigio); 478122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 47963670Snsayer 48063670Snsayer tp->tap_flags &= ~TAP_OPEN; 48163670Snsayer tp->tap_pid = 0; 48283043Sbrooks error = rman_release_resource(tp->tap_unit); 483121816Sbrooks KASSERT((error == 0), 484121816Sbrooks ("%s could not release unit", ifp->if_xname)); 48583043Sbrooks tp->tap_unit = NULL; 48663670Snsayer 487121816Sbrooks TAPDEBUG("%s is closed. minor = %#x\n", 488121816Sbrooks ifp->if_xname, minor(dev)); 48963670Snsayer 49063670Snsayer return (0); 49163670Snsayer} /* tapclose */ 49263670Snsayer 49363670Snsayer 49463670Snsayer/* 49563670Snsayer * tapifinit 49663670Snsayer * 49763670Snsayer * network interface initialization function 49863670Snsayer */ 49963670Snsayerstatic void 50063670Snsayertapifinit(xtp) 50163670Snsayer void *xtp; 50263670Snsayer{ 50363670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 50463670Snsayer struct ifnet *ifp = &tp->tap_if; 50563670Snsayer 506121816Sbrooks TAPDEBUG("initializing %s\n", ifp->if_xname); 50763670Snsayer 50863670Snsayer ifp->if_flags |= IFF_RUNNING; 50963670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 51063670Snsayer 51163670Snsayer /* attempt to start output */ 51263670Snsayer tapifstart(ifp); 51363670Snsayer} /* tapifinit */ 51463670Snsayer 51563670Snsayer 51663670Snsayer/* 51763670Snsayer * tapifioctl 51863670Snsayer * 51963670Snsayer * Process an ioctl request on network interface 52063670Snsayer */ 521105228Sphkstatic int 52263670Snsayertapifioctl(ifp, cmd, data) 52363670Snsayer struct ifnet *ifp; 52463670Snsayer u_long cmd; 52563670Snsayer caddr_t data; 52663670Snsayer{ 527111742Sdes struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 52863670Snsayer struct ifstat *ifs = NULL; 52963670Snsayer int s, dummy; 53063670Snsayer 53163670Snsayer switch (cmd) { 53263670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 53363670Snsayer case SIOCADDMULTI: 53463670Snsayer case SIOCDELMULTI: 53583043Sbrooks break; 53663670Snsayer 53763670Snsayer case SIOCGIFSTATUS: 53863670Snsayer s = splimp(); 53963670Snsayer ifs = (struct ifstat *)data; 54063670Snsayer dummy = strlen(ifs->ascii); 54163670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 54263670Snsayer snprintf(ifs->ascii + dummy, 54363670Snsayer sizeof(ifs->ascii) - dummy, 54463670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 54563670Snsayer splx(s); 54683043Sbrooks break; 54763670Snsayer 54863670Snsayer default: 549106939Ssam s = splimp(); 550106939Ssam dummy = ether_ioctl(ifp, cmd, data); 551106939Ssam splx(s); 552106939Ssam return (dummy); 55363670Snsayer } 55463670Snsayer 55563670Snsayer return (0); 55663670Snsayer} /* tapifioctl */ 55763670Snsayer 55863670Snsayer 55963670Snsayer/* 560111742Sdes * tapifstart 561111742Sdes * 56263670Snsayer * queue packets from higher level ready to put out 56363670Snsayer */ 56463670Snsayerstatic void 56563670Snsayertapifstart(ifp) 56663670Snsayer struct ifnet *ifp; 56763670Snsayer{ 56863670Snsayer struct tap_softc *tp = ifp->if_softc; 56963670Snsayer int s; 57063670Snsayer 571121816Sbrooks TAPDEBUG("%s starting\n", ifp->if_xname); 57263670Snsayer 57363803Snsayer /* 57463803Snsayer * do not junk pending output if we are in VMnet mode. 57563803Snsayer * XXX: can this do any harm because of queue overflow? 57663803Snsayer */ 57763803Snsayer 578111742Sdes if (((tp->tap_flags & TAP_VMNET) == 0) && 57963803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 58063670Snsayer struct mbuf *m = NULL; 58163670Snsayer 582121816Sbrooks TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 583121816Sbrooks tp->tap_flags); 58463670Snsayer 58563670Snsayer s = splimp(); 58663670Snsayer do { 58763670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 58863670Snsayer if (m != NULL) 58963670Snsayer m_freem(m); 59063670Snsayer ifp->if_oerrors ++; 59163670Snsayer } while (m != NULL); 59263670Snsayer splx(s); 59363670Snsayer 59463670Snsayer return; 59563670Snsayer } 59663670Snsayer 59763670Snsayer s = splimp(); 59863670Snsayer ifp->if_flags |= IFF_OACTIVE; 59963670Snsayer 60063670Snsayer if (ifp->if_snd.ifq_len != 0) { 60163670Snsayer if (tp->tap_flags & TAP_RWAIT) { 60263670Snsayer tp->tap_flags &= ~TAP_RWAIT; 603111748Sdes wakeup(tp); 60463670Snsayer } 60563670Snsayer 60663670Snsayer if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) 60795883Salfred pgsigio(&tp->tap_sigio, SIGIO, 0); 60863670Snsayer 609122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 61063670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 61163670Snsayer } 61263670Snsayer 61363670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 61463670Snsayer splx(s); 61563670Snsayer} /* tapifstart */ 61663670Snsayer 61763670Snsayer 61863670Snsayer/* 61963670Snsayer * tapioctl 62063670Snsayer * 62163670Snsayer * the cdevsw interface is now pretty minimal 62263670Snsayer */ 62363670Snsayerstatic int 62483366Sjuliantapioctl(dev, cmd, data, flag, td) 62563670Snsayer dev_t dev; 62663670Snsayer u_long cmd; 62763670Snsayer caddr_t data; 62863670Snsayer int flag; 62983366Sjulian struct thread *td; 63063670Snsayer{ 63163670Snsayer struct tap_softc *tp = dev->si_drv1; 63263670Snsayer struct ifnet *ifp = &tp->tap_if; 633111742Sdes struct tapinfo *tapp = NULL; 63463670Snsayer int s; 635102052Ssobomax int f; 63663670Snsayer 63763670Snsayer switch (cmd) { 638111742Sdes case TAPSIFINFO: 63963670Snsayer s = splimp(); 640111742Sdes tapp = (struct tapinfo *)data; 641111742Sdes ifp->if_mtu = tapp->mtu; 642111742Sdes ifp->if_type = tapp->type; 643111742Sdes ifp->if_baudrate = tapp->baudrate; 64463670Snsayer splx(s); 645111742Sdes break; 64663670Snsayer 647111742Sdes case TAPGIFINFO: 648111742Sdes tapp = (struct tapinfo *)data; 649111742Sdes tapp->mtu = ifp->if_mtu; 650111742Sdes tapp->type = ifp->if_type; 651111742Sdes tapp->baudrate = ifp->if_baudrate; 652111742Sdes break; 65363670Snsayer 65463670Snsayer case TAPSDEBUG: 65563670Snsayer tapdebug = *(int *)data; 65683043Sbrooks break; 65763670Snsayer 65863670Snsayer case TAPGDEBUG: 65963670Snsayer *(int *)data = tapdebug; 66083043Sbrooks break; 66163670Snsayer 66263670Snsayer case FIONBIO: 66383043Sbrooks break; 66463670Snsayer 66563670Snsayer case FIOASYNC: 66663803Snsayer s = splimp(); 66763670Snsayer if (*(int *)data) 66863670Snsayer tp->tap_flags |= TAP_ASYNC; 66963670Snsayer else 67063670Snsayer tp->tap_flags &= ~TAP_ASYNC; 67163803Snsayer splx(s); 67283043Sbrooks break; 67363670Snsayer 67463670Snsayer case FIONREAD: 67563670Snsayer s = splimp(); 67663670Snsayer if (ifp->if_snd.ifq_head) { 67763670Snsayer struct mbuf *mb = ifp->if_snd.ifq_head; 67863670Snsayer 67963803Snsayer for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 68063670Snsayer *(int *)data += mb->m_len; 68183043Sbrooks } else 68263670Snsayer *(int *)data = 0; 68363670Snsayer splx(s); 68483043Sbrooks break; 68563670Snsayer 68663670Snsayer case FIOSETOWN: 68763670Snsayer return (fsetown(*(int *)data, &tp->tap_sigio)); 68863670Snsayer 68963670Snsayer case FIOGETOWN: 690104393Struckman *(int *)data = fgetown(&tp->tap_sigio); 69163670Snsayer return (0); 69263670Snsayer 69363670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 69463670Snsayer case TIOCSPGRP: 69563670Snsayer return (fsetown(-(*(int *)data), &tp->tap_sigio)); 69663670Snsayer 69763670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 69863670Snsayer case TIOCGPGRP: 699104393Struckman *(int *)data = -fgetown(&tp->tap_sigio); 70063670Snsayer return (0); 70163670Snsayer 70263670Snsayer /* VMware/VMnet port ioctl's */ 70363670Snsayer 70463670Snsayer case SIOCGIFFLAGS: /* get ifnet flags */ 70563670Snsayer bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 70683043Sbrooks break; 70763670Snsayer 70883043Sbrooks case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 709102052Ssobomax f = *(int *)data; 71063670Snsayer f &= 0x0fff; 71163670Snsayer f &= ~IFF_CANTCHANGE; 71263670Snsayer f |= IFF_UP; 71363670Snsayer 71463670Snsayer s = splimp(); 71563670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 71663670Snsayer splx(s); 71783043Sbrooks break; 71863670Snsayer 71963861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 72063670Snsayer case SIOCGIFADDR: 72163861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 72283043Sbrooks break; 72363670Snsayer 72463861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 72563861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 72683043Sbrooks break; 72763670Snsayer 72863670Snsayer default: 72963670Snsayer return (ENOTTY); 73063670Snsayer } 73163670Snsayer return (0); 73263670Snsayer} /* tapioctl */ 73363670Snsayer 73463670Snsayer 73563670Snsayer/* 73663670Snsayer * tapread 73763670Snsayer * 73863670Snsayer * the cdevsw read interface - reads a packet at a time, or at 73963670Snsayer * least as much of a packet as can be read 74063670Snsayer */ 74163670Snsayerstatic int 74263670Snsayertapread(dev, uio, flag) 74363670Snsayer dev_t dev; 74463670Snsayer struct uio *uio; 74563670Snsayer int flag; 74663670Snsayer{ 74763670Snsayer struct tap_softc *tp = dev->si_drv1; 74863670Snsayer struct ifnet *ifp = &tp->tap_if; 74990227Sdillon struct mbuf *m = NULL; 75063670Snsayer int error = 0, len, s; 75163670Snsayer 752121816Sbrooks TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev)); 75363670Snsayer 75463670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 755121816Sbrooks TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 756121816Sbrooks ifp->if_xname, minor(dev), tp->tap_flags); 75763803Snsayer 75863670Snsayer return (EHOSTDOWN); 75963670Snsayer } 76063670Snsayer 76163670Snsayer tp->tap_flags &= ~TAP_RWAIT; 76263670Snsayer 76363670Snsayer /* sleep until we get a packet */ 76463670Snsayer do { 76563670Snsayer s = splimp(); 76690227Sdillon IF_DEQUEUE(&ifp->if_snd, m); 76763670Snsayer splx(s); 76863670Snsayer 76990227Sdillon if (m == NULL) { 77063670Snsayer if (flag & IO_NDELAY) 77163670Snsayer return (EWOULDBLOCK); 772111742Sdes 77363670Snsayer tp->tap_flags |= TAP_RWAIT; 774111748Sdes error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); 77563670Snsayer if (error) 77663670Snsayer return (error); 77763670Snsayer } 77890227Sdillon } while (m == NULL); 77963670Snsayer 78063670Snsayer /* feed packet to bpf */ 781106939Ssam BPF_MTAP(ifp, m); 78263670Snsayer 78363670Snsayer /* xfer packet to user space */ 78490227Sdillon while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 78590227Sdillon len = min(uio->uio_resid, m->m_len); 78663670Snsayer if (len == 0) 78763670Snsayer break; 78863670Snsayer 789111741Sdes error = uiomove(mtod(m, void *), len, uio); 79090227Sdillon m = m_free(m); 79163670Snsayer } 79263670Snsayer 79390227Sdillon if (m != NULL) { 794121816Sbrooks TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 795121816Sbrooks minor(dev)); 79690227Sdillon m_freem(m); 79763670Snsayer } 79863670Snsayer 79963670Snsayer return (error); 80063670Snsayer} /* tapread */ 80163670Snsayer 80263670Snsayer 80363670Snsayer/* 80463670Snsayer * tapwrite 80563670Snsayer * 80663670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 80763670Snsayer */ 80863670Snsayerstatic int 80963670Snsayertapwrite(dev, uio, flag) 81063670Snsayer dev_t dev; 81163670Snsayer struct uio *uio; 81263670Snsayer int flag; 81363670Snsayer{ 81463670Snsayer struct tap_softc *tp = dev->si_drv1; 81563670Snsayer struct ifnet *ifp = &tp->tap_if; 81663670Snsayer struct mbuf *top = NULL, **mp = NULL, *m = NULL; 817111742Sdes int error = 0, tlen, mlen; 81863670Snsayer 819121816Sbrooks TAPDEBUG("%s writting, minor = %#x\n", 820121816Sbrooks ifp->if_xname, minor(dev)); 82163670Snsayer 82263670Snsayer if (uio->uio_resid == 0) 82363670Snsayer return (0); 82463670Snsayer 82563670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 826121816Sbrooks TAPDEBUG("%s invalid packet len = %d, minor = %#x\n", 827121816Sbrooks ifp->if_xname, uio->uio_resid, minor(dev)); 82863803Snsayer 82963670Snsayer return (EIO); 83063670Snsayer } 83163670Snsayer tlen = uio->uio_resid; 83263670Snsayer 83363670Snsayer /* get a header mbuf */ 834111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 83563670Snsayer if (m == NULL) 83663670Snsayer return (ENOBUFS); 83763670Snsayer mlen = MHLEN; 83863670Snsayer 83963670Snsayer top = 0; 84063670Snsayer mp = ⊤ 84163670Snsayer while ((error == 0) && (uio->uio_resid > 0)) { 84263670Snsayer m->m_len = min(mlen, uio->uio_resid); 843111741Sdes error = uiomove(mtod(m, void *), m->m_len, uio); 84463670Snsayer *mp = m; 84563670Snsayer mp = &m->m_next; 84663670Snsayer if (uio->uio_resid > 0) { 847111119Simp MGET(m, M_DONTWAIT, MT_DATA); 84863803Snsayer if (m == NULL) { 84963670Snsayer error = ENOBUFS; 85063670Snsayer break; 85163670Snsayer } 85263670Snsayer mlen = MLEN; 85363670Snsayer } 85463670Snsayer } 85563670Snsayer if (error) { 85663670Snsayer ifp->if_ierrors ++; 85763670Snsayer if (top) 85863670Snsayer m_freem(top); 85963670Snsayer return (error); 86063670Snsayer } 86163670Snsayer 86263670Snsayer top->m_pkthdr.len = tlen; 86363670Snsayer top->m_pkthdr.rcvif = ifp; 864111742Sdes 865106939Ssam /* Pass packet up to parent. */ 866106939Ssam (*ifp->if_input)(ifp, top); 867106939Ssam ifp->if_ipackets ++; /* ibytes are counted in parent */ 86863670Snsayer 86963670Snsayer return (0); 87063670Snsayer} /* tapwrite */ 87163670Snsayer 87263670Snsayer 87363670Snsayer/* 87463670Snsayer * tappoll 87563670Snsayer * 87663670Snsayer * the poll interface, this is only useful on reads 87763670Snsayer * really. the write detect always returns true, write never blocks 87863670Snsayer * anyway, it either accepts the packet or drops it 87963670Snsayer */ 88063670Snsayerstatic int 88183366Sjuliantappoll(dev, events, td) 88263670Snsayer dev_t dev; 88363670Snsayer int events; 88483366Sjulian struct thread *td; 88563670Snsayer{ 88663670Snsayer struct tap_softc *tp = dev->si_drv1; 88763670Snsayer struct ifnet *ifp = &tp->tap_if; 888111742Sdes int s, revents = 0; 88963670Snsayer 890121816Sbrooks TAPDEBUG("%s polling, minor = %#x\n", 891121816Sbrooks ifp->if_xname, minor(dev)); 89263670Snsayer 89363670Snsayer s = splimp(); 89463670Snsayer if (events & (POLLIN | POLLRDNORM)) { 89563670Snsayer if (ifp->if_snd.ifq_len > 0) { 896121816Sbrooks TAPDEBUG("%s have data in queue. len = %d, " \ 897121816Sbrooks "minor = %#x\n", ifp->if_xname, 89883043Sbrooks ifp->if_snd.ifq_len, minor(dev)); 89963803Snsayer 90063670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 90183043Sbrooks } else { 902121816Sbrooks TAPDEBUG("%s waiting for data, minor = %#x\n", 903121816Sbrooks ifp->if_xname, minor(dev)); 90463803Snsayer 90583805Sjhb selrecord(td, &tp->tap_rsel); 90663670Snsayer } 90763670Snsayer } 90863670Snsayer 90963670Snsayer if (events & (POLLOUT | POLLWRNORM)) 91063670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 91163670Snsayer 91263670Snsayer splx(s); 91363670Snsayer return (revents); 91463670Snsayer} /* tappoll */ 915