if_tap.c revision 127170
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 127170 2004-03-18 14:18:51Z rwatson $ 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 <sys/queue.h> 5863670Snsayer 5963670Snsayer#include <net/bpf.h> 6063670Snsayer#include <net/ethernet.h> 6163670Snsayer#include <net/if.h> 6263670Snsayer#include <net/if_arp.h> 6363670Snsayer#include <net/route.h> 6463670Snsayer 6563670Snsayer#include <netinet/in.h> 6663670Snsayer 6763670Snsayer#include <net/if_tapvar.h> 6863670Snsayer#include <net/if_tap.h> 6963670Snsayer 7063670Snsayer 7163670Snsayer#define CDEV_NAME "tap" 7263670Snsayer#define TAPDEBUG if (tapdebug) printf 7363670Snsayer 7463670Snsayer#define TAP "tap" 7563670Snsayer#define VMNET "vmnet" 7683043Sbrooks#define TAPMAXUNIT 0x7fff 77126077Sphk#define VMNET_DEV_MASK CLONE_FLAG0 7863670Snsayer 7963670Snsayer/* module */ 80111742Sdesstatic int tapmodevent(module_t, int, void *); 8163670Snsayer 8263670Snsayer/* device */ 8393084Sbdestatic void tapclone(void *, char *, int, dev_t *); 8493084Sbdestatic void tapcreate(dev_t); 8563670Snsayer 8663670Snsayer/* network interface */ 8793084Sbdestatic void tapifstart(struct ifnet *); 8893084Sbdestatic int tapifioctl(struct ifnet *, u_long, caddr_t); 8993084Sbdestatic void tapifinit(void *); 9063670Snsayer 9163670Snsayer/* character device */ 9263670Snsayerstatic d_open_t tapopen; 9363670Snsayerstatic d_close_t tapclose; 9463670Snsayerstatic d_read_t tapread; 9563670Snsayerstatic d_write_t tapwrite; 9663670Snsayerstatic d_ioctl_t tapioctl; 9763670Snsayerstatic d_poll_t tappoll; 9863670Snsayer 9963670Snsayerstatic struct cdevsw tap_cdevsw = { 100126080Sphk .d_version = D_VERSION, 101126188Sbde .d_flags = D_PSEUDO | D_NEEDGIANT, 102111815Sphk .d_open = tapopen, 103111815Sphk .d_close = tapclose, 104111815Sphk .d_read = tapread, 105111815Sphk .d_write = tapwrite, 106111815Sphk .d_ioctl = tapioctl, 107111815Sphk .d_poll = tappoll, 108111815Sphk .d_name = CDEV_NAME, 10963670Snsayer}; 11063670Snsayer 111127003Srwatson/* 112127003Srwatson * All global variables in if_tap.c are locked with tapmtx, with the 113127003Srwatson * exception of tapdebug, which is accessed unlocked; tapclones is 114127003Srwatson * static at runtime. 115127003Srwatson */ 116127003Srwatsonstatic struct mtx tapmtx; 11783043Sbrooksstatic int tapdebug = 0; /* debug flag */ 11883043Sbrooksstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 119126077Sphkstatic struct clonedevs *tapclones; 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; 140126077Sphk int s; 14163670Snsayer 14263670Snsayer switch (type) { 14363670Snsayer case MOD_LOAD: 14463670Snsayer 14583043Sbrooks /* intitialize device */ 14683043Sbrooks 147127003Srwatson mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF); 14883043Sbrooks SLIST_INIT(&taphead); 14983043Sbrooks 150126845Sphk clone_setup(&tapclones); 15171602Sphk eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 152127003Srwatson if (eh_tag == NULL) { 153127170Srwatson clone_cleanup(&tapclones); 154127003Srwatson mtx_destroy(&tapmtx); 155126077Sphk return (ENOMEM); 156127003Srwatson } 15783043Sbrooks return (0); 15863670Snsayer 15983043Sbrooks case MOD_UNLOAD: 160127003Srwatson /* 161127003Srwatson * The EBUSY algorithm here can't quite atomically 162127003Srwatson * guarantee that this is race-free since we have to 163127003Srwatson * release the tap mtx to deregister the clone handler. 164127003Srwatson */ 165127003Srwatson mtx_lock(&tapmtx); 166127003Srwatson SLIST_FOREACH(tp, &taphead, tap_next) { 167127098Srwatson mtx_lock(&tp->tap_mtx); 168127003Srwatson if (tp->tap_flags & TAP_OPEN) { 169127098Srwatson mtx_unlock(&tp->tap_mtx); 170127003Srwatson mtx_unlock(&tapmtx); 17183043Sbrooks return (EBUSY); 172127003Srwatson } 173127098Srwatson mtx_unlock(&tp->tap_mtx); 174127003Srwatson } 175127003Srwatson mtx_unlock(&tapmtx); 17683043Sbrooks 17771602Sphk EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 17863670Snsayer 179127003Srwatson mtx_lock(&tapmtx); 18083043Sbrooks while ((tp = SLIST_FIRST(&taphead)) != NULL) { 18183043Sbrooks SLIST_REMOVE_HEAD(&taphead, tap_next); 182127003Srwatson mtx_unlock(&tapmtx); 18383043Sbrooks 18483043Sbrooks ifp = &tp->tap_if; 18583043Sbrooks 186121816Sbrooks TAPDEBUG("detaching %s\n", ifp->if_xname); 18783043Sbrooks 188127098Srwatson /* Unlocked read. */ 189121816Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 190121816Sbrooks ("%s flags is out of sync", ifp->if_xname)); 19183043Sbrooks 192126077Sphk destroy_dev(tp->tap_dev); 19363670Snsayer s = splimp(); 194106939Ssam ether_ifdetach(ifp); 19563670Snsayer splx(s); 19663670Snsayer 197127098Srwatson mtx_destroy(&tp->tap_mtx); 19893752Sluigi free(tp, M_TAP); 199127003Srwatson mtx_lock(&tapmtx); 20083043Sbrooks } 201127003Srwatson mtx_unlock(&tapmtx); 202126077Sphk clone_cleanup(&tapclones); 20363670Snsayer 20483043Sbrooks break; 20563670Snsayer 20663670Snsayer default: 20763670Snsayer return (EOPNOTSUPP); 20863670Snsayer } 20963670Snsayer 21063670Snsayer return (0); 21163670Snsayer} /* tapmodevent */ 21263670Snsayer 21363670Snsayer 21463670Snsayer/* 21571602Sphk * DEVFS handler 21671602Sphk * 21771602Sphk * We need to support two kind of devices - tap and vmnet 21871602Sphk */ 21971602Sphkstatic void 22071602Sphktapclone(arg, name, namelen, dev) 22171602Sphk void *arg; 22271602Sphk char *name; 22371602Sphk int namelen; 22471602Sphk dev_t *dev; 22571602Sphk{ 226126077Sphk u_int extra; 227126077Sphk int i, unit; 22883043Sbrooks char *device_name = name; 22971602Sphk 23071602Sphk if (*dev != NODEV) 23171602Sphk return; 23271602Sphk 233126077Sphk device_name = TAP; 234126077Sphk extra = 0; 235126077Sphk if (strcmp(name, TAP) == 0) { 236126077Sphk unit = -1; 237126077Sphk } else if (strcmp(name, VMNET) == 0) { 238126077Sphk device_name = VMNET; 239126077Sphk extra = VMNET_DEV_MASK; 240126077Sphk unit = -1; 241126077Sphk } else if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 242126077Sphk device_name = VMNET; 243126077Sphk extra = VMNET_DEV_MASK; 244126077Sphk if (dev_stdclone(name, NULL, device_name, &unit) != 1) 245126077Sphk return; 24683043Sbrooks } 24771602Sphk 248126077Sphk /* find any existing device, or allocate new unit number */ 249126077Sphk i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra); 250126077Sphk if (i) { 251126796Sphk *dev = make_dev(&tap_cdevsw, unit2minor(unit | extra), 252126077Sphk UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit); 253126077Sphk if (*dev != NULL) 254126077Sphk (*dev)->si_flags |= SI_CHEAPCLONE; 25571602Sphk } 25671602Sphk} /* tapclone */ 25771602Sphk 25871602Sphk 25971602Sphk/* 26063670Snsayer * tapcreate 26163670Snsayer * 26263670Snsayer * to create interface 26363670Snsayer */ 26463670Snsayerstatic void 26563670Snsayertapcreate(dev) 26663670Snsayer dev_t dev; 26763670Snsayer{ 26863670Snsayer struct ifnet *ifp = NULL; 26963670Snsayer struct tap_softc *tp = NULL; 27063670Snsayer unsigned short macaddr_hi; 27163803Snsayer int unit, s; 27263670Snsayer char *name = NULL; 27363670Snsayer 274126077Sphk dev->si_flags &= ~SI_CHEAPCLONE; 275126077Sphk 27663670Snsayer /* allocate driver storage and create device */ 277111119Simp MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 278127098Srwatson mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF); 279127003Srwatson mtx_lock(&tapmtx); 28083043Sbrooks SLIST_INSERT_HEAD(&taphead, tp, tap_next); 281127003Srwatson mtx_unlock(&tapmtx); 28263670Snsayer 283126796Sphk unit = dev2unit(dev); 28483043Sbrooks 28563670Snsayer /* select device: tap or vmnet */ 286126796Sphk if (unit & VMNET_DEV_MASK) { 28763670Snsayer name = VMNET; 28863803Snsayer tp->tap_flags |= TAP_VMNET; 28983043Sbrooks } else 29063670Snsayer name = TAP; 29163670Snsayer 292126796Sphk unit &= TAPMAXUNIT; 293126796Sphk 29483043Sbrooks TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 29583043Sbrooks 29663670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 29763670Snsayer macaddr_hi = htons(0x00bd); 29863670Snsayer bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 29963670Snsayer bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 30063670Snsayer tp->arpcom.ac_enaddr[5] = (u_char)unit; 30163670Snsayer 302111742Sdes /* fill the rest and attach interface */ 30363670Snsayer ifp = &tp->tap_if; 30463670Snsayer ifp->if_softc = tp; 305121816Sbrooks if_initname(ifp, name, unit); 30663670Snsayer ifp->if_init = tapifinit; 30763670Snsayer ifp->if_start = tapifstart; 30863670Snsayer ifp->if_ioctl = tapifioctl; 30963670Snsayer ifp->if_mtu = ETHERMTU; 31063670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 31163670Snsayer ifp->if_snd.ifq_maxlen = ifqmaxlen; 31263670Snsayer 31383043Sbrooks dev->si_drv1 = tp; 314126077Sphk tp->tap_dev = dev; 31583043Sbrooks 31663803Snsayer s = splimp(); 317106939Ssam ether_ifattach(ifp, tp->arpcom.ac_enaddr); 31863803Snsayer splx(s); 31963670Snsayer 320127098Srwatson mtx_lock(&tp->tap_mtx); 32163803Snsayer tp->tap_flags |= TAP_INITED; 322127098Srwatson mtx_unlock(&tp->tap_mtx); 32363803Snsayer 324121816Sbrooks TAPDEBUG("interface %s is created. minor = %#x\n", 325121816Sbrooks ifp->if_xname, minor(dev)); 32663670Snsayer} /* tapcreate */ 32763670Snsayer 32863670Snsayer 32963670Snsayer/* 330111742Sdes * tapopen 33163670Snsayer * 33263670Snsayer * to open tunnel. must be superuser 33363670Snsayer */ 33463670Snsayerstatic int 33583366Sjuliantapopen(dev, flag, mode, td) 33663670Snsayer dev_t dev; 33763670Snsayer int flag; 33863670Snsayer int mode; 33983366Sjulian struct thread *td; 34063670Snsayer{ 34163670Snsayer struct tap_softc *tp = NULL; 342126796Sphk int error; 34363670Snsayer 34493593Sjhb if ((error = suser(td)) != 0) 34563670Snsayer return (error); 34663670Snsayer 347126796Sphk if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT) 348126796Sphk return (ENXIO); 34983043Sbrooks 350127165Srwatson /* 351127165Srwatson * XXXRW: Non-atomic test-and-set of si_drv1. Currently protected 352127165Srwatson * by Giant, but the race actually exists under memory pressure as 353127165Srwatson * well even when running with Giant, as malloc() may sleep. 354127165Srwatson */ 35563670Snsayer tp = dev->si_drv1; 35663670Snsayer if (tp == NULL) { 35763670Snsayer tapcreate(dev); 35863670Snsayer tp = dev->si_drv1; 35963670Snsayer } 36063670Snsayer 361127165Srwatson mtx_lock(&tp->tap_mtx); 362127165Srwatson if (tp->tap_flags & TAP_OPEN) { 363127165Srwatson mtx_unlock(&tp->tap_mtx); 364127165Srwatson return (EBUSY); 365127165Srwatson } 36663670Snsayer 36763861Snsayer bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 36883366Sjulian tp->tap_pid = td->td_proc->p_pid; 36963670Snsayer tp->tap_flags |= TAP_OPEN; 370127098Srwatson mtx_unlock(&tp->tap_mtx); 37163670Snsayer 372121816Sbrooks TAPDEBUG("%s is open. minor = %#x\n", 373121816Sbrooks tp->tap_if.if_xname, minor(dev)); 37463670Snsayer 37563670Snsayer return (0); 37663670Snsayer} /* tapopen */ 37763670Snsayer 37863670Snsayer 37963670Snsayer/* 38063670Snsayer * tapclose 38163670Snsayer * 38263670Snsayer * close the device - mark i/f down & delete routing info 38363670Snsayer */ 38463670Snsayerstatic int 38583366Sjuliantapclose(dev, foo, bar, td) 38663670Snsayer dev_t dev; 38763670Snsayer int foo; 38863670Snsayer int bar; 38983366Sjulian struct thread *td; 39063670Snsayer{ 39163670Snsayer struct tap_softc *tp = dev->si_drv1; 39263670Snsayer struct ifnet *ifp = &tp->tap_if; 393126077Sphk int s; 39463670Snsayer 39563670Snsayer /* junk all pending output */ 39683043Sbrooks IF_DRAIN(&ifp->if_snd); 39763670Snsayer 39863803Snsayer /* 39963803Snsayer * do not bring the interface down, and do not anything with 40063803Snsayer * interface, if we are in VMnet mode. just close the device. 40163803Snsayer */ 40263803Snsayer 403127098Srwatson mtx_lock(&tp->tap_mtx); 40463803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 405127098Srwatson mtx_unlock(&tp->tap_mtx); 40663670Snsayer s = splimp(); 40763670Snsayer if_down(ifp); 40863670Snsayer if (ifp->if_flags & IFF_RUNNING) { 40963670Snsayer /* find internet addresses and delete routes */ 41063670Snsayer struct ifaddr *ifa = NULL; 41163670Snsayer 412127098Srwatson /* In desparate need of ifaddr locking. */ 41363803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 41463670Snsayer if (ifa->ifa_addr->sa_family == AF_INET) { 41563670Snsayer rtinit(ifa, (int)RTM_DELETE, 0); 41663670Snsayer 41763670Snsayer /* remove address from interface */ 418111742Sdes bzero(ifa->ifa_addr, 41963670Snsayer sizeof(*(ifa->ifa_addr))); 420111742Sdes bzero(ifa->ifa_dstaddr, 42163670Snsayer sizeof(*(ifa->ifa_dstaddr))); 422111742Sdes bzero(ifa->ifa_netmask, 42363670Snsayer sizeof(*(ifa->ifa_netmask))); 42463670Snsayer } 42563670Snsayer } 42663670Snsayer 42763670Snsayer ifp->if_flags &= ~IFF_RUNNING; 42863670Snsayer } 42963670Snsayer splx(s); 430127098Srwatson } else 431127098Srwatson mtx_unlock(&tp->tap_mtx); 43263670Snsayer 43396122Salfred funsetown(&tp->tap_sigio); 434122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 43563670Snsayer 436127098Srwatson mtx_lock(&tp->tap_mtx); 43763670Snsayer tp->tap_flags &= ~TAP_OPEN; 43863670Snsayer tp->tap_pid = 0; 439127098Srwatson mtx_unlock(&tp->tap_mtx); 44063670Snsayer 441121816Sbrooks TAPDEBUG("%s is closed. minor = %#x\n", 442121816Sbrooks ifp->if_xname, minor(dev)); 44363670Snsayer 44463670Snsayer return (0); 44563670Snsayer} /* tapclose */ 44663670Snsayer 44763670Snsayer 44863670Snsayer/* 44963670Snsayer * tapifinit 45063670Snsayer * 45163670Snsayer * network interface initialization function 45263670Snsayer */ 45363670Snsayerstatic void 45463670Snsayertapifinit(xtp) 45563670Snsayer void *xtp; 45663670Snsayer{ 45763670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 45863670Snsayer struct ifnet *ifp = &tp->tap_if; 45963670Snsayer 460121816Sbrooks TAPDEBUG("initializing %s\n", ifp->if_xname); 46163670Snsayer 46263670Snsayer ifp->if_flags |= IFF_RUNNING; 46363670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 46463670Snsayer 46563670Snsayer /* attempt to start output */ 46663670Snsayer tapifstart(ifp); 46763670Snsayer} /* tapifinit */ 46863670Snsayer 46963670Snsayer 47063670Snsayer/* 47163670Snsayer * tapifioctl 47263670Snsayer * 47363670Snsayer * Process an ioctl request on network interface 47463670Snsayer */ 475105228Sphkstatic int 47663670Snsayertapifioctl(ifp, cmd, data) 47763670Snsayer struct ifnet *ifp; 47863670Snsayer u_long cmd; 47963670Snsayer caddr_t data; 48063670Snsayer{ 481111742Sdes struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 48263670Snsayer struct ifstat *ifs = NULL; 48363670Snsayer int s, dummy; 48463670Snsayer 48563670Snsayer switch (cmd) { 48663670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 48763670Snsayer case SIOCADDMULTI: 48863670Snsayer case SIOCDELMULTI: 48983043Sbrooks break; 49063670Snsayer 49163670Snsayer case SIOCGIFSTATUS: 49263670Snsayer s = splimp(); 49363670Snsayer ifs = (struct ifstat *)data; 49463670Snsayer dummy = strlen(ifs->ascii); 495127098Srwatson mtx_lock(&tp->tap_mtx); 49663670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 49763670Snsayer snprintf(ifs->ascii + dummy, 49863670Snsayer sizeof(ifs->ascii) - dummy, 49963670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 500127098Srwatson mtx_unlock(&tp->tap_mtx); 50163670Snsayer splx(s); 50283043Sbrooks break; 50363670Snsayer 50463670Snsayer default: 505106939Ssam s = splimp(); 506106939Ssam dummy = ether_ioctl(ifp, cmd, data); 507106939Ssam splx(s); 508106939Ssam return (dummy); 50963670Snsayer } 51063670Snsayer 51163670Snsayer return (0); 51263670Snsayer} /* tapifioctl */ 51363670Snsayer 51463670Snsayer 51563670Snsayer/* 516111742Sdes * tapifstart 517111742Sdes * 51863670Snsayer * queue packets from higher level ready to put out 51963670Snsayer */ 52063670Snsayerstatic void 52163670Snsayertapifstart(ifp) 52263670Snsayer struct ifnet *ifp; 52363670Snsayer{ 52463670Snsayer struct tap_softc *tp = ifp->if_softc; 52563670Snsayer int s; 52663670Snsayer 527121816Sbrooks TAPDEBUG("%s starting\n", ifp->if_xname); 52863670Snsayer 52963803Snsayer /* 53063803Snsayer * do not junk pending output if we are in VMnet mode. 53163803Snsayer * XXX: can this do any harm because of queue overflow? 53263803Snsayer */ 53363803Snsayer 534127098Srwatson mtx_lock(&tp->tap_mtx); 535111742Sdes if (((tp->tap_flags & TAP_VMNET) == 0) && 53663803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 53763670Snsayer struct mbuf *m = NULL; 53863670Snsayer 539127098Srwatson mtx_unlock(&tp->tap_mtx); 540127098Srwatson 541127098Srwatson /* Unlocked read. */ 542121816Sbrooks TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 543121816Sbrooks tp->tap_flags); 54463670Snsayer 54563670Snsayer s = splimp(); 54663670Snsayer do { 54763670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 54863670Snsayer if (m != NULL) 54963670Snsayer m_freem(m); 55063670Snsayer ifp->if_oerrors ++; 55163670Snsayer } while (m != NULL); 55263670Snsayer splx(s); 55363670Snsayer 55463670Snsayer return; 55563670Snsayer } 556127098Srwatson mtx_unlock(&tp->tap_mtx); 55763670Snsayer 55863670Snsayer s = splimp(); 55963670Snsayer ifp->if_flags |= IFF_OACTIVE; 56063670Snsayer 56163670Snsayer if (ifp->if_snd.ifq_len != 0) { 562127098Srwatson mtx_lock(&tp->tap_mtx); 56363670Snsayer if (tp->tap_flags & TAP_RWAIT) { 56463670Snsayer tp->tap_flags &= ~TAP_RWAIT; 565111748Sdes wakeup(tp); 56663670Snsayer } 56763670Snsayer 568127098Srwatson if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) { 569127098Srwatson mtx_unlock(&tp->tap_mtx); 57095883Salfred pgsigio(&tp->tap_sigio, SIGIO, 0); 571127098Srwatson } else 572127098Srwatson mtx_unlock(&tp->tap_mtx); 57363670Snsayer 574122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 57563670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 57663670Snsayer } 57763670Snsayer 57863670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 57963670Snsayer splx(s); 58063670Snsayer} /* tapifstart */ 58163670Snsayer 58263670Snsayer 58363670Snsayer/* 58463670Snsayer * tapioctl 58563670Snsayer * 58663670Snsayer * the cdevsw interface is now pretty minimal 58763670Snsayer */ 58863670Snsayerstatic int 58983366Sjuliantapioctl(dev, cmd, data, flag, td) 59063670Snsayer dev_t dev; 59163670Snsayer u_long cmd; 59263670Snsayer caddr_t data; 59363670Snsayer int flag; 59483366Sjulian struct thread *td; 59563670Snsayer{ 59663670Snsayer struct tap_softc *tp = dev->si_drv1; 59763670Snsayer struct ifnet *ifp = &tp->tap_if; 598111742Sdes struct tapinfo *tapp = NULL; 59963670Snsayer int s; 600102052Ssobomax int f; 60163670Snsayer 60263670Snsayer switch (cmd) { 603111742Sdes case TAPSIFINFO: 60463670Snsayer s = splimp(); 605111742Sdes tapp = (struct tapinfo *)data; 606111742Sdes ifp->if_mtu = tapp->mtu; 607111742Sdes ifp->if_type = tapp->type; 608111742Sdes ifp->if_baudrate = tapp->baudrate; 60963670Snsayer splx(s); 610111742Sdes break; 61163670Snsayer 612111742Sdes case TAPGIFINFO: 613111742Sdes tapp = (struct tapinfo *)data; 614111742Sdes tapp->mtu = ifp->if_mtu; 615111742Sdes tapp->type = ifp->if_type; 616111742Sdes tapp->baudrate = ifp->if_baudrate; 617111742Sdes break; 61863670Snsayer 61963670Snsayer case TAPSDEBUG: 62063670Snsayer tapdebug = *(int *)data; 62183043Sbrooks break; 62263670Snsayer 62363670Snsayer case TAPGDEBUG: 62463670Snsayer *(int *)data = tapdebug; 62583043Sbrooks break; 62663670Snsayer 62763670Snsayer case FIONBIO: 62883043Sbrooks break; 62963670Snsayer 63063670Snsayer case FIOASYNC: 63163803Snsayer s = splimp(); 632127098Srwatson mtx_lock(&tp->tap_mtx); 63363670Snsayer if (*(int *)data) 63463670Snsayer tp->tap_flags |= TAP_ASYNC; 63563670Snsayer else 63663670Snsayer tp->tap_flags &= ~TAP_ASYNC; 637127098Srwatson mtx_unlock(&tp->tap_mtx); 63863803Snsayer splx(s); 63983043Sbrooks break; 64063670Snsayer 64163670Snsayer case FIONREAD: 64263670Snsayer s = splimp(); 64363670Snsayer if (ifp->if_snd.ifq_head) { 64463670Snsayer struct mbuf *mb = ifp->if_snd.ifq_head; 64563670Snsayer 64663803Snsayer for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 64763670Snsayer *(int *)data += mb->m_len; 64883043Sbrooks } else 64963670Snsayer *(int *)data = 0; 65063670Snsayer splx(s); 65183043Sbrooks break; 65263670Snsayer 65363670Snsayer case FIOSETOWN: 65463670Snsayer return (fsetown(*(int *)data, &tp->tap_sigio)); 65563670Snsayer 65663670Snsayer case FIOGETOWN: 657104393Struckman *(int *)data = fgetown(&tp->tap_sigio); 65863670Snsayer return (0); 65963670Snsayer 66063670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 66163670Snsayer case TIOCSPGRP: 66263670Snsayer return (fsetown(-(*(int *)data), &tp->tap_sigio)); 66363670Snsayer 66463670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 66563670Snsayer case TIOCGPGRP: 666104393Struckman *(int *)data = -fgetown(&tp->tap_sigio); 66763670Snsayer return (0); 66863670Snsayer 66963670Snsayer /* VMware/VMnet port ioctl's */ 67063670Snsayer 67163670Snsayer case SIOCGIFFLAGS: /* get ifnet flags */ 67263670Snsayer bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 67383043Sbrooks break; 67463670Snsayer 67583043Sbrooks case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 676102052Ssobomax f = *(int *)data; 67763670Snsayer f &= 0x0fff; 67863670Snsayer f &= ~IFF_CANTCHANGE; 67963670Snsayer f |= IFF_UP; 68063670Snsayer 68163670Snsayer s = splimp(); 68263670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 68363670Snsayer splx(s); 68483043Sbrooks break; 68563670Snsayer 68663861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 68763670Snsayer case SIOCGIFADDR: 688127165Srwatson mtx_lock(&tp->tap_mtx); 68963861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 690127165Srwatson mtx_unlock(&tp->tap_mtx); 69183043Sbrooks break; 69263670Snsayer 69363861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 694127165Srwatson mtx_lock(&tp->tap_mtx); 69563861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 696127165Srwatson mtx_unlock(&tp->tap_mtx); 69783043Sbrooks break; 69863670Snsayer 69963670Snsayer default: 70063670Snsayer return (ENOTTY); 70163670Snsayer } 70263670Snsayer return (0); 70363670Snsayer} /* tapioctl */ 70463670Snsayer 70563670Snsayer 70663670Snsayer/* 70763670Snsayer * tapread 70863670Snsayer * 70963670Snsayer * the cdevsw read interface - reads a packet at a time, or at 71063670Snsayer * least as much of a packet as can be read 71163670Snsayer */ 71263670Snsayerstatic int 71363670Snsayertapread(dev, uio, flag) 71463670Snsayer dev_t dev; 71563670Snsayer struct uio *uio; 71663670Snsayer int flag; 71763670Snsayer{ 71863670Snsayer struct tap_softc *tp = dev->si_drv1; 71963670Snsayer struct ifnet *ifp = &tp->tap_if; 72090227Sdillon struct mbuf *m = NULL; 72163670Snsayer int error = 0, len, s; 72263670Snsayer 723121816Sbrooks TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev)); 72463670Snsayer 725127098Srwatson mtx_lock(&tp->tap_mtx); 72663670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 727127098Srwatson mtx_unlock(&tp->tap_mtx); 728127098Srwatson 729127098Srwatson /* Unlocked read. */ 730121816Sbrooks TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 731121816Sbrooks ifp->if_xname, minor(dev), tp->tap_flags); 73263803Snsayer 73363670Snsayer return (EHOSTDOWN); 73463670Snsayer } 73563670Snsayer 73663670Snsayer tp->tap_flags &= ~TAP_RWAIT; 737127098Srwatson mtx_unlock(&tp->tap_mtx); 73863670Snsayer 73963670Snsayer /* sleep until we get a packet */ 74063670Snsayer do { 74163670Snsayer s = splimp(); 74290227Sdillon IF_DEQUEUE(&ifp->if_snd, m); 74363670Snsayer splx(s); 74463670Snsayer 74590227Sdillon if (m == NULL) { 74663670Snsayer if (flag & IO_NDELAY) 74763670Snsayer return (EWOULDBLOCK); 748111742Sdes 749127098Srwatson mtx_lock(&tp->tap_mtx); 75063670Snsayer tp->tap_flags |= TAP_RWAIT; 751127098Srwatson mtx_unlock(&tp->tap_mtx); 752111748Sdes error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); 75363670Snsayer if (error) 75463670Snsayer return (error); 75563670Snsayer } 75690227Sdillon } while (m == NULL); 75763670Snsayer 75863670Snsayer /* feed packet to bpf */ 759106939Ssam BPF_MTAP(ifp, m); 76063670Snsayer 76163670Snsayer /* xfer packet to user space */ 76290227Sdillon while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 76390227Sdillon len = min(uio->uio_resid, m->m_len); 76463670Snsayer if (len == 0) 76563670Snsayer break; 76663670Snsayer 767111741Sdes error = uiomove(mtod(m, void *), len, uio); 76890227Sdillon m = m_free(m); 76963670Snsayer } 77063670Snsayer 77190227Sdillon if (m != NULL) { 772121816Sbrooks TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 773121816Sbrooks minor(dev)); 77490227Sdillon m_freem(m); 77563670Snsayer } 77663670Snsayer 77763670Snsayer return (error); 77863670Snsayer} /* tapread */ 77963670Snsayer 78063670Snsayer 78163670Snsayer/* 78263670Snsayer * tapwrite 78363670Snsayer * 78463670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 78563670Snsayer */ 78663670Snsayerstatic int 78763670Snsayertapwrite(dev, uio, flag) 78863670Snsayer dev_t dev; 78963670Snsayer struct uio *uio; 79063670Snsayer int flag; 79163670Snsayer{ 79263670Snsayer struct tap_softc *tp = dev->si_drv1; 79363670Snsayer struct ifnet *ifp = &tp->tap_if; 79463670Snsayer struct mbuf *top = NULL, **mp = NULL, *m = NULL; 795111742Sdes int error = 0, tlen, mlen; 79663670Snsayer 797121816Sbrooks TAPDEBUG("%s writting, minor = %#x\n", 798121816Sbrooks ifp->if_xname, minor(dev)); 79963670Snsayer 80063670Snsayer if (uio->uio_resid == 0) 80163670Snsayer return (0); 80263670Snsayer 80363670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 804121816Sbrooks TAPDEBUG("%s invalid packet len = %d, minor = %#x\n", 805121816Sbrooks ifp->if_xname, uio->uio_resid, minor(dev)); 80663803Snsayer 80763670Snsayer return (EIO); 80863670Snsayer } 80963670Snsayer tlen = uio->uio_resid; 81063670Snsayer 81163670Snsayer /* get a header mbuf */ 812111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 81363670Snsayer if (m == NULL) 81463670Snsayer return (ENOBUFS); 81563670Snsayer mlen = MHLEN; 81663670Snsayer 81763670Snsayer top = 0; 81863670Snsayer mp = ⊤ 81963670Snsayer while ((error == 0) && (uio->uio_resid > 0)) { 82063670Snsayer m->m_len = min(mlen, uio->uio_resid); 821111741Sdes error = uiomove(mtod(m, void *), m->m_len, uio); 82263670Snsayer *mp = m; 82363670Snsayer mp = &m->m_next; 82463670Snsayer if (uio->uio_resid > 0) { 825111119Simp MGET(m, M_DONTWAIT, MT_DATA); 82663803Snsayer if (m == NULL) { 82763670Snsayer error = ENOBUFS; 82863670Snsayer break; 82963670Snsayer } 83063670Snsayer mlen = MLEN; 83163670Snsayer } 83263670Snsayer } 83363670Snsayer if (error) { 83463670Snsayer ifp->if_ierrors ++; 83563670Snsayer if (top) 83663670Snsayer m_freem(top); 83763670Snsayer return (error); 83863670Snsayer } 83963670Snsayer 84063670Snsayer top->m_pkthdr.len = tlen; 84163670Snsayer top->m_pkthdr.rcvif = ifp; 842111742Sdes 843106939Ssam /* Pass packet up to parent. */ 844106939Ssam (*ifp->if_input)(ifp, top); 845106939Ssam ifp->if_ipackets ++; /* ibytes are counted in parent */ 84663670Snsayer 84763670Snsayer return (0); 84863670Snsayer} /* tapwrite */ 84963670Snsayer 85063670Snsayer 85163670Snsayer/* 85263670Snsayer * tappoll 85363670Snsayer * 85463670Snsayer * the poll interface, this is only useful on reads 85563670Snsayer * really. the write detect always returns true, write never blocks 85663670Snsayer * anyway, it either accepts the packet or drops it 85763670Snsayer */ 85863670Snsayerstatic int 85983366Sjuliantappoll(dev, events, td) 86063670Snsayer dev_t dev; 86163670Snsayer int events; 86283366Sjulian struct thread *td; 86363670Snsayer{ 86463670Snsayer struct tap_softc *tp = dev->si_drv1; 86563670Snsayer struct ifnet *ifp = &tp->tap_if; 866111742Sdes int s, revents = 0; 86763670Snsayer 868121816Sbrooks TAPDEBUG("%s polling, minor = %#x\n", 869121816Sbrooks ifp->if_xname, minor(dev)); 87063670Snsayer 87163670Snsayer s = splimp(); 87263670Snsayer if (events & (POLLIN | POLLRDNORM)) { 87363670Snsayer if (ifp->if_snd.ifq_len > 0) { 874121816Sbrooks TAPDEBUG("%s have data in queue. len = %d, " \ 875121816Sbrooks "minor = %#x\n", ifp->if_xname, 87683043Sbrooks ifp->if_snd.ifq_len, minor(dev)); 87763803Snsayer 87863670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 87983043Sbrooks } else { 880121816Sbrooks TAPDEBUG("%s waiting for data, minor = %#x\n", 881121816Sbrooks ifp->if_xname, minor(dev)); 88263803Snsayer 88383805Sjhb selrecord(td, &tp->tap_rsel); 88463670Snsayer } 88563670Snsayer } 88663670Snsayer 88763670Snsayer if (events & (POLLOUT | POLLWRNORM)) 88863670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 88963670Snsayer 89063670Snsayer splx(s); 89163670Snsayer return (revents); 89263670Snsayer} /* tappoll */ 893