if_tap.c revision 139207
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 139207 2004-12-22 17:38:43Z phk $ 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> 42139207Sphk#include <sys/fcntl.h> 4363670Snsayer#include <sys/filio.h> 4463670Snsayer#include <sys/kernel.h> 4563670Snsayer#include <sys/malloc.h> 4663670Snsayer#include <sys/mbuf.h> 47129880Sphk#include <sys/module.h> 4863670Snsayer#include <sys/poll.h> 4963670Snsayer#include <sys/proc.h> 50139207Sphk#include <sys/selinfo.h> 5163670Snsayer#include <sys/signalvar.h> 5263670Snsayer#include <sys/socket.h> 5363670Snsayer#include <sys/sockio.h> 5463670Snsayer#include <sys/sysctl.h> 5563670Snsayer#include <sys/systm.h> 5663670Snsayer#include <sys/ttycom.h> 5763670Snsayer#include <sys/uio.h> 5883043Sbrooks#include <sys/queue.h> 5963670Snsayer 6063670Snsayer#include <net/bpf.h> 6163670Snsayer#include <net/ethernet.h> 6263670Snsayer#include <net/if.h> 6363670Snsayer#include <net/if_arp.h> 6463670Snsayer#include <net/route.h> 6563670Snsayer 6663670Snsayer#include <netinet/in.h> 6763670Snsayer 6863670Snsayer#include <net/if_tapvar.h> 6963670Snsayer#include <net/if_tap.h> 7063670Snsayer 7163670Snsayer 7263670Snsayer#define CDEV_NAME "tap" 7363670Snsayer#define TAPDEBUG if (tapdebug) printf 7463670Snsayer 7563670Snsayer#define TAP "tap" 7663670Snsayer#define VMNET "vmnet" 7783043Sbrooks#define TAPMAXUNIT 0x7fff 78126077Sphk#define VMNET_DEV_MASK CLONE_FLAG0 7963670Snsayer 8063670Snsayer/* module */ 81111742Sdesstatic int tapmodevent(module_t, int, void *); 8263670Snsayer 8363670Snsayer/* device */ 84130585Sphkstatic void tapclone(void *, char *, int, struct cdev **); 85130585Sphkstatic void tapcreate(struct cdev *); 8663670Snsayer 8763670Snsayer/* network interface */ 8893084Sbdestatic void tapifstart(struct ifnet *); 8993084Sbdestatic int tapifioctl(struct ifnet *, u_long, caddr_t); 9093084Sbdestatic void tapifinit(void *); 9163670Snsayer 9263670Snsayer/* character device */ 9363670Snsayerstatic d_open_t tapopen; 9463670Snsayerstatic d_close_t tapclose; 9563670Snsayerstatic d_read_t tapread; 9663670Snsayerstatic d_write_t tapwrite; 9763670Snsayerstatic d_ioctl_t tapioctl; 9863670Snsayerstatic d_poll_t tappoll; 9963670Snsayer 10063670Snsayerstatic struct cdevsw tap_cdevsw = { 101126080Sphk .d_version = D_VERSION, 102126188Sbde .d_flags = D_PSEUDO | D_NEEDGIANT, 103111815Sphk .d_open = tapopen, 104111815Sphk .d_close = tapclose, 105111815Sphk .d_read = tapread, 106111815Sphk .d_write = tapwrite, 107111815Sphk .d_ioctl = tapioctl, 108111815Sphk .d_poll = tappoll, 109111815Sphk .d_name = CDEV_NAME, 11063670Snsayer}; 11163670Snsayer 112127003Srwatson/* 113127003Srwatson * All global variables in if_tap.c are locked with tapmtx, with the 114127003Srwatson * exception of tapdebug, which is accessed unlocked; tapclones is 115127003Srwatson * static at runtime. 116127003Srwatson */ 117127003Srwatsonstatic struct mtx tapmtx; 11883043Sbrooksstatic int tapdebug = 0; /* debug flag */ 11983043Sbrooksstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 120126077Sphkstatic struct clonedevs *tapclones; 12163670Snsayer 12263670SnsayerMALLOC_DECLARE(M_TAP); 12363670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 12463670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 12563670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL); 12663670Snsayer 12763670Snsayer/* 12863670Snsayer * tapmodevent 12963670Snsayer * 13063670Snsayer * module event handler 13163670Snsayer */ 13263670Snsayerstatic int 13363670Snsayertapmodevent(mod, type, data) 13463670Snsayer module_t mod; 13563670Snsayer int type; 13663670Snsayer void *data; 13763670Snsayer{ 13883043Sbrooks static eventhandler_tag eh_tag = NULL; 13983043Sbrooks struct tap_softc *tp = NULL; 14083043Sbrooks struct ifnet *ifp = NULL; 141126077Sphk int s; 14263670Snsayer 14363670Snsayer switch (type) { 14463670Snsayer case MOD_LOAD: 14563670Snsayer 14683043Sbrooks /* intitialize device */ 14783043Sbrooks 148127003Srwatson mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF); 14983043Sbrooks SLIST_INIT(&taphead); 15083043Sbrooks 151126845Sphk clone_setup(&tapclones); 15271602Sphk eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 153127003Srwatson if (eh_tag == NULL) { 154127170Srwatson clone_cleanup(&tapclones); 155127003Srwatson mtx_destroy(&tapmtx); 156126077Sphk return (ENOMEM); 157127003Srwatson } 15883043Sbrooks return (0); 15963670Snsayer 16083043Sbrooks case MOD_UNLOAD: 161127003Srwatson /* 162127003Srwatson * The EBUSY algorithm here can't quite atomically 163127003Srwatson * guarantee that this is race-free since we have to 164127003Srwatson * release the tap mtx to deregister the clone handler. 165127003Srwatson */ 166127003Srwatson mtx_lock(&tapmtx); 167127003Srwatson SLIST_FOREACH(tp, &taphead, tap_next) { 168127098Srwatson mtx_lock(&tp->tap_mtx); 169127003Srwatson if (tp->tap_flags & TAP_OPEN) { 170127098Srwatson mtx_unlock(&tp->tap_mtx); 171127003Srwatson mtx_unlock(&tapmtx); 17283043Sbrooks return (EBUSY); 173127003Srwatson } 174127098Srwatson mtx_unlock(&tp->tap_mtx); 175127003Srwatson } 176127003Srwatson mtx_unlock(&tapmtx); 17783043Sbrooks 17871602Sphk EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 17963670Snsayer 180127003Srwatson mtx_lock(&tapmtx); 18183043Sbrooks while ((tp = SLIST_FIRST(&taphead)) != NULL) { 18283043Sbrooks SLIST_REMOVE_HEAD(&taphead, tap_next); 183127003Srwatson mtx_unlock(&tapmtx); 18483043Sbrooks 18583043Sbrooks ifp = &tp->tap_if; 18683043Sbrooks 187121816Sbrooks TAPDEBUG("detaching %s\n", ifp->if_xname); 18883043Sbrooks 189127098Srwatson /* Unlocked read. */ 190121816Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 191121816Sbrooks ("%s flags is out of sync", ifp->if_xname)); 19283043Sbrooks 193126077Sphk destroy_dev(tp->tap_dev); 19463670Snsayer s = splimp(); 195106939Ssam ether_ifdetach(ifp); 19663670Snsayer splx(s); 19763670Snsayer 198127098Srwatson mtx_destroy(&tp->tap_mtx); 19993752Sluigi free(tp, M_TAP); 200127003Srwatson mtx_lock(&tapmtx); 20183043Sbrooks } 202127003Srwatson mtx_unlock(&tapmtx); 203126077Sphk clone_cleanup(&tapclones); 20463670Snsayer 205135354Srwatson mtx_destroy(&tapmtx); 206135354Srwatson 20783043Sbrooks break; 20863670Snsayer 20963670Snsayer default: 21063670Snsayer return (EOPNOTSUPP); 21163670Snsayer } 21263670Snsayer 21363670Snsayer return (0); 21463670Snsayer} /* tapmodevent */ 21563670Snsayer 21663670Snsayer 21763670Snsayer/* 21871602Sphk * DEVFS handler 21971602Sphk * 22071602Sphk * We need to support two kind of devices - tap and vmnet 22171602Sphk */ 22271602Sphkstatic void 22371602Sphktapclone(arg, name, namelen, dev) 22471602Sphk void *arg; 22571602Sphk char *name; 22671602Sphk int namelen; 227130585Sphk struct cdev **dev; 22871602Sphk{ 229126077Sphk u_int extra; 230126077Sphk int i, unit; 23183043Sbrooks char *device_name = name; 23271602Sphk 233130640Sphk if (*dev != NULL) 23471602Sphk return; 23571602Sphk 236126077Sphk device_name = TAP; 237126077Sphk extra = 0; 238126077Sphk if (strcmp(name, TAP) == 0) { 239126077Sphk unit = -1; 240126077Sphk } else if (strcmp(name, VMNET) == 0) { 241126077Sphk device_name = VMNET; 242126077Sphk extra = VMNET_DEV_MASK; 243126077Sphk unit = -1; 244126077Sphk } else if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 245126077Sphk device_name = VMNET; 246126077Sphk extra = VMNET_DEV_MASK; 247126077Sphk if (dev_stdclone(name, NULL, device_name, &unit) != 1) 248126077Sphk return; 24983043Sbrooks } 25071602Sphk 251126077Sphk /* find any existing device, or allocate new unit number */ 252126077Sphk i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra); 253126077Sphk if (i) { 254126796Sphk *dev = make_dev(&tap_cdevsw, unit2minor(unit | extra), 255126077Sphk UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit); 256126077Sphk if (*dev != NULL) 257126077Sphk (*dev)->si_flags |= SI_CHEAPCLONE; 25871602Sphk } 25971602Sphk} /* tapclone */ 26071602Sphk 26171602Sphk 26271602Sphk/* 26363670Snsayer * tapcreate 26463670Snsayer * 26563670Snsayer * to create interface 26663670Snsayer */ 26763670Snsayerstatic void 26863670Snsayertapcreate(dev) 269130585Sphk struct cdev *dev; 27063670Snsayer{ 27163670Snsayer struct ifnet *ifp = NULL; 27263670Snsayer struct tap_softc *tp = NULL; 27363670Snsayer unsigned short macaddr_hi; 27463803Snsayer int unit, s; 27563670Snsayer char *name = NULL; 27663670Snsayer 277126077Sphk dev->si_flags &= ~SI_CHEAPCLONE; 278126077Sphk 27963670Snsayer /* allocate driver storage and create device */ 280111119Simp MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 281127098Srwatson mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF); 282127003Srwatson mtx_lock(&tapmtx); 28383043Sbrooks SLIST_INSERT_HEAD(&taphead, tp, tap_next); 284127003Srwatson mtx_unlock(&tapmtx); 28563670Snsayer 286126796Sphk unit = dev2unit(dev); 28783043Sbrooks 28863670Snsayer /* select device: tap or vmnet */ 289126796Sphk if (unit & VMNET_DEV_MASK) { 29063670Snsayer name = VMNET; 29163803Snsayer tp->tap_flags |= TAP_VMNET; 29283043Sbrooks } else 29363670Snsayer name = TAP; 29463670Snsayer 295126796Sphk unit &= TAPMAXUNIT; 296126796Sphk 29783043Sbrooks TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 29883043Sbrooks 29963670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 30063670Snsayer macaddr_hi = htons(0x00bd); 30163670Snsayer bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 30263670Snsayer bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 30363670Snsayer tp->arpcom.ac_enaddr[5] = (u_char)unit; 30463670Snsayer 305111742Sdes /* fill the rest and attach interface */ 30663670Snsayer ifp = &tp->tap_if; 30763670Snsayer ifp->if_softc = tp; 308121816Sbrooks if_initname(ifp, name, unit); 30963670Snsayer ifp->if_init = tapifinit; 31063670Snsayer ifp->if_start = tapifstart; 31163670Snsayer ifp->if_ioctl = tapifioctl; 31263670Snsayer ifp->if_mtu = ETHERMTU; 31363670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 31463670Snsayer ifp->if_snd.ifq_maxlen = ifqmaxlen; 31563670Snsayer 31683043Sbrooks dev->si_drv1 = tp; 317126077Sphk tp->tap_dev = dev; 31883043Sbrooks 31963803Snsayer s = splimp(); 320106939Ssam ether_ifattach(ifp, tp->arpcom.ac_enaddr); 32163803Snsayer splx(s); 32263670Snsayer 323127098Srwatson mtx_lock(&tp->tap_mtx); 32463803Snsayer tp->tap_flags |= TAP_INITED; 325127098Srwatson mtx_unlock(&tp->tap_mtx); 32663803Snsayer 327121816Sbrooks TAPDEBUG("interface %s is created. minor = %#x\n", 328121816Sbrooks ifp->if_xname, minor(dev)); 32963670Snsayer} /* tapcreate */ 33063670Snsayer 33163670Snsayer 33263670Snsayer/* 333111742Sdes * tapopen 33463670Snsayer * 33563670Snsayer * to open tunnel. must be superuser 33663670Snsayer */ 33763670Snsayerstatic int 33883366Sjuliantapopen(dev, flag, mode, td) 339130585Sphk struct cdev *dev; 34063670Snsayer int flag; 34163670Snsayer int mode; 34283366Sjulian struct thread *td; 34363670Snsayer{ 34463670Snsayer struct tap_softc *tp = NULL; 345133460Semax struct ifnet *ifp = NULL; 346133460Semax int error, s; 34763670Snsayer 34893593Sjhb if ((error = suser(td)) != 0) 34963670Snsayer return (error); 35063670Snsayer 351126796Sphk if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT) 352126796Sphk return (ENXIO); 35383043Sbrooks 354127165Srwatson /* 355127165Srwatson * XXXRW: Non-atomic test-and-set of si_drv1. Currently protected 356127165Srwatson * by Giant, but the race actually exists under memory pressure as 357127165Srwatson * well even when running with Giant, as malloc() may sleep. 358127165Srwatson */ 35963670Snsayer tp = dev->si_drv1; 36063670Snsayer if (tp == NULL) { 36163670Snsayer tapcreate(dev); 36263670Snsayer tp = dev->si_drv1; 36363670Snsayer } 36463670Snsayer 365127165Srwatson mtx_lock(&tp->tap_mtx); 366127165Srwatson if (tp->tap_flags & TAP_OPEN) { 367127165Srwatson mtx_unlock(&tp->tap_mtx); 368127165Srwatson return (EBUSY); 369127165Srwatson } 37063670Snsayer 37163861Snsayer bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 37283366Sjulian tp->tap_pid = td->td_proc->p_pid; 37363670Snsayer tp->tap_flags |= TAP_OPEN; 374133460Semax ifp = &tp->tap_if; 375127098Srwatson mtx_unlock(&tp->tap_mtx); 37663670Snsayer 377133460Semax s = splimp(); 378133460Semax ifp->if_flags |= IFF_RUNNING; 379133460Semax ifp->if_flags &= ~IFF_OACTIVE; 380133460Semax splx(s); 38163670Snsayer 382133460Semax TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev)); 383133460Semax 38463670Snsayer return (0); 38563670Snsayer} /* tapopen */ 38663670Snsayer 38763670Snsayer 38863670Snsayer/* 38963670Snsayer * tapclose 39063670Snsayer * 39163670Snsayer * close the device - mark i/f down & delete routing info 39263670Snsayer */ 39363670Snsayerstatic int 39483366Sjuliantapclose(dev, foo, bar, td) 395130585Sphk struct cdev *dev; 39663670Snsayer int foo; 39763670Snsayer int bar; 39883366Sjulian struct thread *td; 39963670Snsayer{ 40063670Snsayer struct tap_softc *tp = dev->si_drv1; 40163670Snsayer struct ifnet *ifp = &tp->tap_if; 402126077Sphk int s; 40363670Snsayer 40463670Snsayer /* junk all pending output */ 40583043Sbrooks IF_DRAIN(&ifp->if_snd); 40663670Snsayer 40763803Snsayer /* 40863803Snsayer * do not bring the interface down, and do not anything with 40963803Snsayer * interface, if we are in VMnet mode. just close the device. 41063803Snsayer */ 41163803Snsayer 412127098Srwatson mtx_lock(&tp->tap_mtx); 41363803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 414127098Srwatson mtx_unlock(&tp->tap_mtx); 41563670Snsayer s = splimp(); 41663670Snsayer if_down(ifp); 41763670Snsayer if (ifp->if_flags & IFF_RUNNING) { 41863670Snsayer /* find internet addresses and delete routes */ 41963670Snsayer struct ifaddr *ifa = NULL; 42063670Snsayer 421127098Srwatson /* In desparate need of ifaddr locking. */ 42263803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 42363670Snsayer if (ifa->ifa_addr->sa_family == AF_INET) { 42463670Snsayer rtinit(ifa, (int)RTM_DELETE, 0); 42563670Snsayer 42663670Snsayer /* remove address from interface */ 427111742Sdes bzero(ifa->ifa_addr, 42863670Snsayer sizeof(*(ifa->ifa_addr))); 429111742Sdes bzero(ifa->ifa_dstaddr, 43063670Snsayer sizeof(*(ifa->ifa_dstaddr))); 431111742Sdes bzero(ifa->ifa_netmask, 43263670Snsayer sizeof(*(ifa->ifa_netmask))); 43363670Snsayer } 43463670Snsayer } 43563670Snsayer 43663670Snsayer ifp->if_flags &= ~IFF_RUNNING; 43763670Snsayer } 43863670Snsayer splx(s); 439127098Srwatson } else 440127098Srwatson mtx_unlock(&tp->tap_mtx); 44163670Snsayer 44296122Salfred funsetown(&tp->tap_sigio); 443122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 44463670Snsayer 445127098Srwatson mtx_lock(&tp->tap_mtx); 44663670Snsayer tp->tap_flags &= ~TAP_OPEN; 44763670Snsayer tp->tap_pid = 0; 448127098Srwatson mtx_unlock(&tp->tap_mtx); 44963670Snsayer 450121816Sbrooks TAPDEBUG("%s is closed. minor = %#x\n", 451121816Sbrooks ifp->if_xname, minor(dev)); 45263670Snsayer 45363670Snsayer return (0); 45463670Snsayer} /* tapclose */ 45563670Snsayer 45663670Snsayer 45763670Snsayer/* 45863670Snsayer * tapifinit 45963670Snsayer * 46063670Snsayer * network interface initialization function 46163670Snsayer */ 46263670Snsayerstatic void 46363670Snsayertapifinit(xtp) 46463670Snsayer void *xtp; 46563670Snsayer{ 46663670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 46763670Snsayer struct ifnet *ifp = &tp->tap_if; 46863670Snsayer 469121816Sbrooks TAPDEBUG("initializing %s\n", ifp->if_xname); 47063670Snsayer 47163670Snsayer ifp->if_flags |= IFF_RUNNING; 47263670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 47363670Snsayer 47463670Snsayer /* attempt to start output */ 47563670Snsayer tapifstart(ifp); 47663670Snsayer} /* tapifinit */ 47763670Snsayer 47863670Snsayer 47963670Snsayer/* 48063670Snsayer * tapifioctl 48163670Snsayer * 48263670Snsayer * Process an ioctl request on network interface 48363670Snsayer */ 484105228Sphkstatic int 48563670Snsayertapifioctl(ifp, cmd, data) 48663670Snsayer struct ifnet *ifp; 48763670Snsayer u_long cmd; 48863670Snsayer caddr_t data; 48963670Snsayer{ 490111742Sdes struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 49163670Snsayer struct ifstat *ifs = NULL; 49263670Snsayer int s, dummy; 49363670Snsayer 49463670Snsayer switch (cmd) { 49563670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 49663670Snsayer case SIOCADDMULTI: 49763670Snsayer case SIOCDELMULTI: 49883043Sbrooks break; 49963670Snsayer 50063670Snsayer case SIOCGIFSTATUS: 50163670Snsayer s = splimp(); 50263670Snsayer ifs = (struct ifstat *)data; 50363670Snsayer dummy = strlen(ifs->ascii); 504127098Srwatson mtx_lock(&tp->tap_mtx); 50563670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 50663670Snsayer snprintf(ifs->ascii + dummy, 50763670Snsayer sizeof(ifs->ascii) - dummy, 50863670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 509127098Srwatson mtx_unlock(&tp->tap_mtx); 51063670Snsayer splx(s); 51183043Sbrooks break; 51263670Snsayer 51363670Snsayer default: 514106939Ssam s = splimp(); 515106939Ssam dummy = ether_ioctl(ifp, cmd, data); 516106939Ssam splx(s); 517106939Ssam return (dummy); 51863670Snsayer } 51963670Snsayer 52063670Snsayer return (0); 52163670Snsayer} /* tapifioctl */ 52263670Snsayer 52363670Snsayer 52463670Snsayer/* 525111742Sdes * tapifstart 526111742Sdes * 52763670Snsayer * queue packets from higher level ready to put out 52863670Snsayer */ 52963670Snsayerstatic void 53063670Snsayertapifstart(ifp) 53163670Snsayer struct ifnet *ifp; 53263670Snsayer{ 53363670Snsayer struct tap_softc *tp = ifp->if_softc; 53463670Snsayer int s; 53563670Snsayer 536121816Sbrooks TAPDEBUG("%s starting\n", ifp->if_xname); 53763670Snsayer 53863803Snsayer /* 53963803Snsayer * do not junk pending output if we are in VMnet mode. 54063803Snsayer * XXX: can this do any harm because of queue overflow? 54163803Snsayer */ 54263803Snsayer 543127098Srwatson mtx_lock(&tp->tap_mtx); 544111742Sdes if (((tp->tap_flags & TAP_VMNET) == 0) && 54563803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 54663670Snsayer struct mbuf *m = NULL; 54763670Snsayer 548127098Srwatson mtx_unlock(&tp->tap_mtx); 549127098Srwatson 550127098Srwatson /* Unlocked read. */ 551121816Sbrooks TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 552121816Sbrooks tp->tap_flags); 55363670Snsayer 55463670Snsayer s = splimp(); 55563670Snsayer do { 55663670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 55763670Snsayer if (m != NULL) 55863670Snsayer m_freem(m); 55963670Snsayer ifp->if_oerrors ++; 56063670Snsayer } while (m != NULL); 56163670Snsayer splx(s); 56263670Snsayer 56363670Snsayer return; 56463670Snsayer } 565127098Srwatson mtx_unlock(&tp->tap_mtx); 56663670Snsayer 56763670Snsayer s = splimp(); 56863670Snsayer ifp->if_flags |= IFF_OACTIVE; 56963670Snsayer 57063670Snsayer if (ifp->if_snd.ifq_len != 0) { 571127098Srwatson mtx_lock(&tp->tap_mtx); 57263670Snsayer if (tp->tap_flags & TAP_RWAIT) { 57363670Snsayer tp->tap_flags &= ~TAP_RWAIT; 574111748Sdes wakeup(tp); 57563670Snsayer } 57663670Snsayer 577127098Srwatson if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) { 578127098Srwatson mtx_unlock(&tp->tap_mtx); 57995883Salfred pgsigio(&tp->tap_sigio, SIGIO, 0); 580127098Srwatson } else 581127098Srwatson mtx_unlock(&tp->tap_mtx); 58263670Snsayer 583122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 58463670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 58563670Snsayer } 58663670Snsayer 58763670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 58863670Snsayer splx(s); 58963670Snsayer} /* tapifstart */ 59063670Snsayer 59163670Snsayer 59263670Snsayer/* 59363670Snsayer * tapioctl 59463670Snsayer * 59563670Snsayer * the cdevsw interface is now pretty minimal 59663670Snsayer */ 59763670Snsayerstatic int 59883366Sjuliantapioctl(dev, cmd, data, flag, td) 599130585Sphk struct cdev *dev; 60063670Snsayer u_long cmd; 60163670Snsayer caddr_t data; 60263670Snsayer int flag; 60383366Sjulian struct thread *td; 60463670Snsayer{ 60563670Snsayer struct tap_softc *tp = dev->si_drv1; 60663670Snsayer struct ifnet *ifp = &tp->tap_if; 607111742Sdes struct tapinfo *tapp = NULL; 60863670Snsayer int s; 609102052Ssobomax int f; 61063670Snsayer 61163670Snsayer switch (cmd) { 612111742Sdes case TAPSIFINFO: 61363670Snsayer s = splimp(); 614111742Sdes tapp = (struct tapinfo *)data; 615111742Sdes ifp->if_mtu = tapp->mtu; 616111742Sdes ifp->if_type = tapp->type; 617111742Sdes ifp->if_baudrate = tapp->baudrate; 61863670Snsayer splx(s); 619111742Sdes break; 62063670Snsayer 621111742Sdes case TAPGIFINFO: 622111742Sdes tapp = (struct tapinfo *)data; 623111742Sdes tapp->mtu = ifp->if_mtu; 624111742Sdes tapp->type = ifp->if_type; 625111742Sdes tapp->baudrate = ifp->if_baudrate; 626111742Sdes break; 62763670Snsayer 62863670Snsayer case TAPSDEBUG: 62963670Snsayer tapdebug = *(int *)data; 63083043Sbrooks break; 63163670Snsayer 63263670Snsayer case TAPGDEBUG: 63363670Snsayer *(int *)data = tapdebug; 63483043Sbrooks break; 63563670Snsayer 63663670Snsayer case FIONBIO: 63783043Sbrooks break; 63863670Snsayer 63963670Snsayer case FIOASYNC: 64063803Snsayer s = splimp(); 641127098Srwatson mtx_lock(&tp->tap_mtx); 64263670Snsayer if (*(int *)data) 64363670Snsayer tp->tap_flags |= TAP_ASYNC; 64463670Snsayer else 64563670Snsayer tp->tap_flags &= ~TAP_ASYNC; 646127098Srwatson mtx_unlock(&tp->tap_mtx); 64763803Snsayer splx(s); 64883043Sbrooks break; 64963670Snsayer 65063670Snsayer case FIONREAD: 65163670Snsayer s = splimp(); 65263670Snsayer if (ifp->if_snd.ifq_head) { 65363670Snsayer struct mbuf *mb = ifp->if_snd.ifq_head; 65463670Snsayer 65563803Snsayer for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 65663670Snsayer *(int *)data += mb->m_len; 65783043Sbrooks } else 65863670Snsayer *(int *)data = 0; 65963670Snsayer splx(s); 66083043Sbrooks break; 66163670Snsayer 66263670Snsayer case FIOSETOWN: 66363670Snsayer return (fsetown(*(int *)data, &tp->tap_sigio)); 66463670Snsayer 66563670Snsayer case FIOGETOWN: 666104393Struckman *(int *)data = fgetown(&tp->tap_sigio); 66763670Snsayer return (0); 66863670Snsayer 66963670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 67063670Snsayer case TIOCSPGRP: 67163670Snsayer return (fsetown(-(*(int *)data), &tp->tap_sigio)); 67263670Snsayer 67363670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 67463670Snsayer case TIOCGPGRP: 675104393Struckman *(int *)data = -fgetown(&tp->tap_sigio); 67663670Snsayer return (0); 67763670Snsayer 67863670Snsayer /* VMware/VMnet port ioctl's */ 67963670Snsayer 68063670Snsayer case SIOCGIFFLAGS: /* get ifnet flags */ 68163670Snsayer bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 68283043Sbrooks break; 68363670Snsayer 68483043Sbrooks case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 685102052Ssobomax f = *(int *)data; 68663670Snsayer f &= 0x0fff; 68763670Snsayer f &= ~IFF_CANTCHANGE; 68863670Snsayer f |= IFF_UP; 68963670Snsayer 69063670Snsayer s = splimp(); 69163670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 69263670Snsayer splx(s); 69383043Sbrooks break; 69463670Snsayer 69563861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 69663670Snsayer case SIOCGIFADDR: 697127165Srwatson mtx_lock(&tp->tap_mtx); 69863861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 699127165Srwatson mtx_unlock(&tp->tap_mtx); 70083043Sbrooks break; 70163670Snsayer 70263861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 703127165Srwatson mtx_lock(&tp->tap_mtx); 70463861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 705127165Srwatson mtx_unlock(&tp->tap_mtx); 70683043Sbrooks break; 70763670Snsayer 70863670Snsayer default: 70963670Snsayer return (ENOTTY); 71063670Snsayer } 71163670Snsayer return (0); 71263670Snsayer} /* tapioctl */ 71363670Snsayer 71463670Snsayer 71563670Snsayer/* 71663670Snsayer * tapread 71763670Snsayer * 71863670Snsayer * the cdevsw read interface - reads a packet at a time, or at 71963670Snsayer * least as much of a packet as can be read 72063670Snsayer */ 72163670Snsayerstatic int 72263670Snsayertapread(dev, uio, flag) 723130585Sphk struct cdev *dev; 72463670Snsayer struct uio *uio; 72563670Snsayer int flag; 72663670Snsayer{ 72763670Snsayer struct tap_softc *tp = dev->si_drv1; 72863670Snsayer struct ifnet *ifp = &tp->tap_if; 72990227Sdillon struct mbuf *m = NULL; 73063670Snsayer int error = 0, len, s; 73163670Snsayer 732121816Sbrooks TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev)); 73363670Snsayer 734127098Srwatson mtx_lock(&tp->tap_mtx); 73563670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 736127098Srwatson mtx_unlock(&tp->tap_mtx); 737127098Srwatson 738127098Srwatson /* Unlocked read. */ 739121816Sbrooks TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 740121816Sbrooks ifp->if_xname, minor(dev), tp->tap_flags); 74163803Snsayer 74263670Snsayer return (EHOSTDOWN); 74363670Snsayer } 74463670Snsayer 74563670Snsayer tp->tap_flags &= ~TAP_RWAIT; 746127098Srwatson mtx_unlock(&tp->tap_mtx); 74763670Snsayer 74863670Snsayer /* sleep until we get a packet */ 74963670Snsayer do { 75063670Snsayer s = splimp(); 75190227Sdillon IF_DEQUEUE(&ifp->if_snd, m); 75263670Snsayer splx(s); 75363670Snsayer 75490227Sdillon if (m == NULL) { 755139207Sphk if (flag & O_NONBLOCK) 75663670Snsayer return (EWOULDBLOCK); 757111742Sdes 758127098Srwatson mtx_lock(&tp->tap_mtx); 75963670Snsayer tp->tap_flags |= TAP_RWAIT; 760127098Srwatson mtx_unlock(&tp->tap_mtx); 761111748Sdes error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); 76263670Snsayer if (error) 76363670Snsayer return (error); 76463670Snsayer } 76590227Sdillon } while (m == NULL); 76663670Snsayer 76763670Snsayer /* feed packet to bpf */ 768106939Ssam BPF_MTAP(ifp, m); 76963670Snsayer 77063670Snsayer /* xfer packet to user space */ 77190227Sdillon while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 77290227Sdillon len = min(uio->uio_resid, m->m_len); 77363670Snsayer if (len == 0) 77463670Snsayer break; 77563670Snsayer 776111741Sdes error = uiomove(mtod(m, void *), len, uio); 77790227Sdillon m = m_free(m); 77863670Snsayer } 77963670Snsayer 78090227Sdillon if (m != NULL) { 781121816Sbrooks TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 782121816Sbrooks minor(dev)); 78390227Sdillon m_freem(m); 78463670Snsayer } 78563670Snsayer 78663670Snsayer return (error); 78763670Snsayer} /* tapread */ 78863670Snsayer 78963670Snsayer 79063670Snsayer/* 79163670Snsayer * tapwrite 79263670Snsayer * 79363670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 79463670Snsayer */ 79563670Snsayerstatic int 79663670Snsayertapwrite(dev, uio, flag) 797130585Sphk struct cdev *dev; 79863670Snsayer struct uio *uio; 79963670Snsayer int flag; 80063670Snsayer{ 80163670Snsayer struct tap_softc *tp = dev->si_drv1; 80263670Snsayer struct ifnet *ifp = &tp->tap_if; 803137101Sglebius struct mbuf *m; 804137101Sglebius int error = 0; 80563670Snsayer 806121816Sbrooks TAPDEBUG("%s writting, minor = %#x\n", 807121816Sbrooks ifp->if_xname, minor(dev)); 80863670Snsayer 80963670Snsayer if (uio->uio_resid == 0) 81063670Snsayer return (0); 81163670Snsayer 81263670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 813121816Sbrooks TAPDEBUG("%s invalid packet len = %d, minor = %#x\n", 814121816Sbrooks ifp->if_xname, uio->uio_resid, minor(dev)); 81563803Snsayer 81663670Snsayer return (EIO); 81763670Snsayer } 81863670Snsayer 819137101Sglebius if ((m = m_uiotombuf(uio, M_DONTWAIT, 0)) == NULL) { 82063670Snsayer ifp->if_ierrors ++; 82163670Snsayer return (error); 82263670Snsayer } 82363670Snsayer 824137101Sglebius m->m_pkthdr.rcvif = ifp; 825111742Sdes 826106939Ssam /* Pass packet up to parent. */ 827137101Sglebius (*ifp->if_input)(ifp, m); 828106939Ssam ifp->if_ipackets ++; /* ibytes are counted in parent */ 82963670Snsayer 83063670Snsayer return (0); 83163670Snsayer} /* tapwrite */ 83263670Snsayer 83363670Snsayer 83463670Snsayer/* 83563670Snsayer * tappoll 83663670Snsayer * 83763670Snsayer * the poll interface, this is only useful on reads 83863670Snsayer * really. the write detect always returns true, write never blocks 83963670Snsayer * anyway, it either accepts the packet or drops it 84063670Snsayer */ 84163670Snsayerstatic int 84283366Sjuliantappoll(dev, events, td) 843130585Sphk struct cdev *dev; 84463670Snsayer int events; 84583366Sjulian struct thread *td; 84663670Snsayer{ 84763670Snsayer struct tap_softc *tp = dev->si_drv1; 84863670Snsayer struct ifnet *ifp = &tp->tap_if; 849111742Sdes int s, revents = 0; 85063670Snsayer 851121816Sbrooks TAPDEBUG("%s polling, minor = %#x\n", 852121816Sbrooks ifp->if_xname, minor(dev)); 85363670Snsayer 85463670Snsayer s = splimp(); 85563670Snsayer if (events & (POLLIN | POLLRDNORM)) { 85663670Snsayer if (ifp->if_snd.ifq_len > 0) { 857121816Sbrooks TAPDEBUG("%s have data in queue. len = %d, " \ 858121816Sbrooks "minor = %#x\n", ifp->if_xname, 85983043Sbrooks ifp->if_snd.ifq_len, minor(dev)); 86063803Snsayer 86163670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 86283043Sbrooks } else { 863121816Sbrooks TAPDEBUG("%s waiting for data, minor = %#x\n", 864121816Sbrooks ifp->if_xname, minor(dev)); 86563803Snsayer 86683805Sjhb selrecord(td, &tp->tap_rsel); 86763670Snsayer } 86863670Snsayer } 86963670Snsayer 87063670Snsayer if (events & (POLLOUT | POLLWRNORM)) 87163670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 87263670Snsayer 87363670Snsayer splx(s); 87463670Snsayer return (revents); 87563670Snsayer} /* tappoll */ 876