if_tap.c revision 227459
1139823Simp/*- 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 227459 2011-11-11 22:57:52Z brooks $ 3563803Snsayer * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ 3663670Snsayer */ 3763670Snsayer 38162711Sru#include "opt_compat.h" 3963670Snsayer#include "opt_inet.h" 4063670Snsayer 4163670Snsayer#include <sys/param.h> 4263670Snsayer#include <sys/conf.h> 43139207Sphk#include <sys/fcntl.h> 4463670Snsayer#include <sys/filio.h> 4563670Snsayer#include <sys/kernel.h> 4663670Snsayer#include <sys/malloc.h> 4763670Snsayer#include <sys/mbuf.h> 48129880Sphk#include <sys/module.h> 4963670Snsayer#include <sys/poll.h> 50164033Srwatson#include <sys/priv.h> 5163670Snsayer#include <sys/proc.h> 52139207Sphk#include <sys/selinfo.h> 5363670Snsayer#include <sys/signalvar.h> 5463670Snsayer#include <sys/socket.h> 5563670Snsayer#include <sys/sockio.h> 5663670Snsayer#include <sys/sysctl.h> 5763670Snsayer#include <sys/systm.h> 5863670Snsayer#include <sys/ttycom.h> 5963670Snsayer#include <sys/uio.h> 6083043Sbrooks#include <sys/queue.h> 6163670Snsayer 6263670Snsayer#include <net/bpf.h> 6363670Snsayer#include <net/ethernet.h> 6463670Snsayer#include <net/if.h> 65166497Sbms#include <net/if_clone.h> 66152315Sru#include <net/if_dl.h> 6763670Snsayer#include <net/route.h> 68147256Sbrooks#include <net/if_types.h> 6963670Snsayer 7063670Snsayer#include <netinet/in.h> 7163670Snsayer 7263670Snsayer#include <net/if_tapvar.h> 7363670Snsayer#include <net/if_tap.h> 7463670Snsayer 7563670Snsayer 7663670Snsayer#define CDEV_NAME "tap" 7763670Snsayer#define TAPDEBUG if (tapdebug) printf 7863670Snsayer 7963670Snsayer#define TAP "tap" 8063670Snsayer#define VMNET "vmnet" 8183043Sbrooks#define TAPMAXUNIT 0x7fff 82126077Sphk#define VMNET_DEV_MASK CLONE_FLAG0 8363670Snsayer 8463670Snsayer/* module */ 85111742Sdesstatic int tapmodevent(module_t, int, void *); 8663670Snsayer 8763670Snsayer/* device */ 88148868Srwatsonstatic void tapclone(void *, struct ucred *, char *, int, 89148868Srwatson struct cdev **); 90130585Sphkstatic void tapcreate(struct cdev *); 9163670Snsayer 9263670Snsayer/* network interface */ 9393084Sbdestatic void tapifstart(struct ifnet *); 9493084Sbdestatic int tapifioctl(struct ifnet *, u_long, caddr_t); 9593084Sbdestatic void tapifinit(void *); 9663670Snsayer 97166497Sbmsstatic int tap_clone_create(struct if_clone *, int, caddr_t); 98166497Sbmsstatic void tap_clone_destroy(struct ifnet *); 99166497Sbmsstatic int vmnet_clone_create(struct if_clone *, int, caddr_t); 100166497Sbmsstatic void vmnet_clone_destroy(struct ifnet *); 101166497Sbms 102166497SbmsIFC_SIMPLE_DECLARE(tap, 0); 103166497SbmsIFC_SIMPLE_DECLARE(vmnet, 0); 104166497Sbms 10563670Snsayer/* character device */ 10663670Snsayerstatic d_open_t tapopen; 10763670Snsayerstatic d_close_t tapclose; 10863670Snsayerstatic d_read_t tapread; 10963670Snsayerstatic d_write_t tapwrite; 11063670Snsayerstatic d_ioctl_t tapioctl; 11163670Snsayerstatic d_poll_t tappoll; 112156783Semaxstatic d_kqfilter_t tapkqfilter; 11363670Snsayer 114156783Semax/* kqueue(2) */ 115156783Semaxstatic int tapkqread(struct knote *, long); 116156783Semaxstatic int tapkqwrite(struct knote *, long); 117156783Semaxstatic void tapkqdetach(struct knote *); 118156783Semax 119156783Semaxstatic struct filterops tap_read_filterops = { 120156783Semax .f_isfd = 1, 121156783Semax .f_attach = NULL, 122156783Semax .f_detach = tapkqdetach, 123156783Semax .f_event = tapkqread, 124156783Semax}; 125156783Semax 126156783Semaxstatic struct filterops tap_write_filterops = { 127156783Semax .f_isfd = 1, 128156783Semax .f_attach = NULL, 129156783Semax .f_detach = tapkqdetach, 130156783Semax .f_event = tapkqwrite, 131156783Semax}; 132156783Semax 13363670Snsayerstatic struct cdevsw tap_cdevsw = { 134126080Sphk .d_version = D_VERSION, 135226500Sed .d_flags = D_NEEDMINOR, 136111815Sphk .d_open = tapopen, 137111815Sphk .d_close = tapclose, 138111815Sphk .d_read = tapread, 139111815Sphk .d_write = tapwrite, 140111815Sphk .d_ioctl = tapioctl, 141111815Sphk .d_poll = tappoll, 142111815Sphk .d_name = CDEV_NAME, 143156783Semax .d_kqfilter = tapkqfilter, 14463670Snsayer}; 14563670Snsayer 146127003Srwatson/* 147127003Srwatson * All global variables in if_tap.c are locked with tapmtx, with the 148127003Srwatson * exception of tapdebug, which is accessed unlocked; tapclones is 149127003Srwatson * static at runtime. 150127003Srwatson */ 151127003Srwatsonstatic struct mtx tapmtx; 15283043Sbrooksstatic int tapdebug = 0; /* debug flag */ 153167713Sbmsstatic int tapuopen = 0; /* allow user open() */ 154167713Sbmsstatic int tapuponopen = 0; /* IFF_UP on open() */ 155166497Sbmsstatic int tapdclone = 1; /* enable devfs cloning */ 15683043Sbrooksstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 157126077Sphkstatic struct clonedevs *tapclones; 15863670Snsayer 15963670SnsayerMALLOC_DECLARE(M_TAP); 16063670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 16163670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 162144979Smdodd 163144979SmdoddSYSCTL_DECL(_net_link); 164227309Sedstatic SYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0, 165144979Smdodd "Ethernet tunnel software network interface"); 166144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0, 167144979Smdodd "Allow user to open /dev/tap (based on node permissions)"); 168167713SbmsSYSCTL_INT(_net_link_tap, OID_AUTO, up_on_open, CTLFLAG_RW, &tapuponopen, 0, 169167713Sbms "Bring interface up when /dev/tap is opened"); 170166497SbmsSYSCTL_INT(_net_link_tap, OID_AUTO, devfs_cloning, CTLFLAG_RW, &tapdclone, 0, 171166497Sbms "Enably legacy devfs interface creation"); 172144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, ""); 173144979Smdodd 174166497SbmsTUNABLE_INT("net.link.tap.devfs_cloning", &tapdclone); 175166497Sbms 17663670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL); 17763670Snsayer 178166497Sbmsstatic int 179166497Sbmstap_clone_create(struct if_clone *ifc, int unit, caddr_t params) 180166497Sbms{ 181166497Sbms struct cdev *dev; 182166497Sbms int i; 183166497Sbms int extra; 184166497Sbms 185166497Sbms if (strcmp(ifc->ifc_name, VMNET) == 0) 186166497Sbms extra = VMNET_DEV_MASK; 187166497Sbms else 188166497Sbms extra = 0; 189166497Sbms 190166497Sbms /* find any existing device, or allocate new unit number */ 191166497Sbms i = clone_create(&tapclones, &tap_cdevsw, &unit, &dev, extra); 192166497Sbms if (i) { 193183381Sed dev = make_dev(&tap_cdevsw, unit | extra, 194166497Sbms UID_ROOT, GID_WHEEL, 0600, "%s%d", ifc->ifc_name, unit); 195166497Sbms } 196166497Sbms 197166497Sbms tapcreate(dev); 198166497Sbms return (0); 199166497Sbms} 200166497Sbms 201166497Sbms/* vmnet devices are tap devices in disguise */ 202166497Sbmsstatic int 203166497Sbmsvmnet_clone_create(struct if_clone *ifc, int unit, caddr_t params) 204166497Sbms{ 205166497Sbms return tap_clone_create(ifc, unit, params); 206166497Sbms} 207166497Sbms 208166497Sbmsstatic void 209166497Sbmstap_destroy(struct tap_softc *tp) 210166497Sbms{ 211166497Sbms struct ifnet *ifp = tp->tap_ifp; 212166497Sbms 213166497Sbms /* Unlocked read. */ 214166497Sbms KASSERT(!(tp->tap_flags & TAP_OPEN), 215166497Sbms ("%s flags is out of sync", ifp->if_xname)); 216166497Sbms 217225177Sattilio seldrain(&tp->tap_rsel); 218166497Sbms knlist_destroy(&tp->tap_rsel.si_note); 219166497Sbms destroy_dev(tp->tap_dev); 220166497Sbms ether_ifdetach(ifp); 221227459Sbrooks if_free(ifp); 222166497Sbms 223166497Sbms mtx_destroy(&tp->tap_mtx); 224166497Sbms free(tp, M_TAP); 225166497Sbms} 226166497Sbms 227166497Sbmsstatic void 228166497Sbmstap_clone_destroy(struct ifnet *ifp) 229166497Sbms{ 230166497Sbms struct tap_softc *tp = ifp->if_softc; 231166497Sbms 232166497Sbms mtx_lock(&tapmtx); 233166497Sbms SLIST_REMOVE(&taphead, tp, tap_softc, tap_next); 234166497Sbms mtx_unlock(&tapmtx); 235166497Sbms tap_destroy(tp); 236166497Sbms} 237166497Sbms 238166497Sbms/* vmnet devices are tap devices in disguise */ 239166497Sbmsstatic void 240166497Sbmsvmnet_clone_destroy(struct ifnet *ifp) 241166497Sbms{ 242166497Sbms tap_clone_destroy(ifp); 243166497Sbms} 244166497Sbms 24563670Snsayer/* 24663670Snsayer * tapmodevent 24763670Snsayer * 24863670Snsayer * module event handler 24963670Snsayer */ 25063670Snsayerstatic int 251156783Semaxtapmodevent(module_t mod, int type, void *data) 25263670Snsayer{ 25383043Sbrooks static eventhandler_tag eh_tag = NULL; 25483043Sbrooks struct tap_softc *tp = NULL; 25583043Sbrooks struct ifnet *ifp = NULL; 25663670Snsayer 25763670Snsayer switch (type) { 25863670Snsayer case MOD_LOAD: 25963670Snsayer 26083043Sbrooks /* intitialize device */ 26183043Sbrooks 262127003Srwatson mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF); 26383043Sbrooks SLIST_INIT(&taphead); 26483043Sbrooks 265126845Sphk clone_setup(&tapclones); 26671602Sphk eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 267127003Srwatson if (eh_tag == NULL) { 268127170Srwatson clone_cleanup(&tapclones); 269127003Srwatson mtx_destroy(&tapmtx); 270126077Sphk return (ENOMEM); 271127003Srwatson } 272166497Sbms if_clone_attach(&tap_cloner); 273166497Sbms if_clone_attach(&vmnet_cloner); 27483043Sbrooks return (0); 27563670Snsayer 27683043Sbrooks case MOD_UNLOAD: 277127003Srwatson /* 278127003Srwatson * The EBUSY algorithm here can't quite atomically 279127003Srwatson * guarantee that this is race-free since we have to 280127003Srwatson * release the tap mtx to deregister the clone handler. 281127003Srwatson */ 282127003Srwatson mtx_lock(&tapmtx); 283127003Srwatson SLIST_FOREACH(tp, &taphead, tap_next) { 284127098Srwatson mtx_lock(&tp->tap_mtx); 285127003Srwatson if (tp->tap_flags & TAP_OPEN) { 286127098Srwatson mtx_unlock(&tp->tap_mtx); 287127003Srwatson mtx_unlock(&tapmtx); 28883043Sbrooks return (EBUSY); 289127003Srwatson } 290127098Srwatson mtx_unlock(&tp->tap_mtx); 291127003Srwatson } 292127003Srwatson mtx_unlock(&tapmtx); 29383043Sbrooks 29471602Sphk EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 295166497Sbms if_clone_detach(&tap_cloner); 296166497Sbms if_clone_detach(&vmnet_cloner); 297204464Skib drain_dev_clone_events(); 29863670Snsayer 299127003Srwatson mtx_lock(&tapmtx); 30083043Sbrooks while ((tp = SLIST_FIRST(&taphead)) != NULL) { 30183043Sbrooks SLIST_REMOVE_HEAD(&taphead, tap_next); 302127003Srwatson mtx_unlock(&tapmtx); 30383043Sbrooks 304147256Sbrooks ifp = tp->tap_ifp; 30583043Sbrooks 306121816Sbrooks TAPDEBUG("detaching %s\n", ifp->if_xname); 30783043Sbrooks 308166497Sbms tap_destroy(tp); 309127003Srwatson mtx_lock(&tapmtx); 31083043Sbrooks } 311127003Srwatson mtx_unlock(&tapmtx); 312126077Sphk clone_cleanup(&tapclones); 31363670Snsayer 314135354Srwatson mtx_destroy(&tapmtx); 315135354Srwatson 31683043Sbrooks break; 31763670Snsayer 31863670Snsayer default: 31963670Snsayer return (EOPNOTSUPP); 32063670Snsayer } 32163670Snsayer 32263670Snsayer return (0); 32363670Snsayer} /* tapmodevent */ 32463670Snsayer 32563670Snsayer 32663670Snsayer/* 32771602Sphk * DEVFS handler 32871602Sphk * 32971602Sphk * We need to support two kind of devices - tap and vmnet 33071602Sphk */ 33171602Sphkstatic void 332156783Semaxtapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev) 33371602Sphk{ 334166497Sbms char devname[SPECNAMELEN + 1]; 335166497Sbms int i, unit, append_unit; 336166438Sbms int extra; 33771602Sphk 338130640Sphk if (*dev != NULL) 33971602Sphk return; 34071602Sphk 341166514Sbms if (!tapdclone || 342166514Sbms (!tapuopen && priv_check_cred(cred, PRIV_NET_IFCREATE, 0) != 0)) 343166497Sbms return; 344166497Sbms 345166497Sbms unit = 0; 346166497Sbms append_unit = 0; 347126077Sphk extra = 0; 348166497Sbms 349166497Sbms /* We're interested in only tap/vmnet devices. */ 350126077Sphk if (strcmp(name, TAP) == 0) { 351126077Sphk unit = -1; 352126077Sphk } else if (strcmp(name, VMNET) == 0) { 353126077Sphk unit = -1; 354126077Sphk extra = VMNET_DEV_MASK; 355166497Sbms } else if (dev_stdclone(name, NULL, TAP, &unit) != 1) { 356166497Sbms if (dev_stdclone(name, NULL, VMNET, &unit) != 1) { 357126077Sphk return; 358166497Sbms } else { 359166497Sbms extra = VMNET_DEV_MASK; 360166497Sbms } 36183043Sbrooks } 36271602Sphk 363166497Sbms if (unit == -1) 364166497Sbms append_unit = 1; 365166497Sbms 366126077Sphk /* find any existing device, or allocate new unit number */ 367126077Sphk i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra); 368126077Sphk if (i) { 369166497Sbms if (append_unit) { 370166497Sbms /* 371166497Sbms * We were passed 'tun' or 'tap', with no unit specified 372166497Sbms * so we'll need to append it now. 373166497Sbms */ 374166497Sbms namelen = snprintf(devname, sizeof(devname), "%s%d", name, 375166497Sbms unit); 376166497Sbms name = devname; 377166497Sbms } 378166497Sbms 379204464Skib *dev = make_dev_credf(MAKEDEV_REF, &tap_cdevsw, unit | extra, 380204464Skib cred, UID_ROOT, GID_WHEEL, 0600, "%s", name); 38171602Sphk } 382166497Sbms 383166497Sbms if_clone_create(name, namelen, NULL); 38471602Sphk} /* tapclone */ 38571602Sphk 38671602Sphk 38771602Sphk/* 38863670Snsayer * tapcreate 38963670Snsayer * 39063670Snsayer * to create interface 39163670Snsayer */ 39263670Snsayerstatic void 393156783Semaxtapcreate(struct cdev *dev) 39463670Snsayer{ 39563670Snsayer struct ifnet *ifp = NULL; 39663670Snsayer struct tap_softc *tp = NULL; 39763670Snsayer unsigned short macaddr_hi; 398178221Semax uint32_t macaddr_mid; 399213028Sjhb int unit; 40063670Snsayer char *name = NULL; 401147256Sbrooks u_char eaddr[6]; 40263670Snsayer 403126077Sphk dev->si_flags &= ~SI_CHEAPCLONE; 404126077Sphk 40563670Snsayer /* allocate driver storage and create device */ 406184205Sdes tp = malloc(sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 407127098Srwatson mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF); 408127003Srwatson mtx_lock(&tapmtx); 40983043Sbrooks SLIST_INSERT_HEAD(&taphead, tp, tap_next); 410127003Srwatson mtx_unlock(&tapmtx); 41163670Snsayer 412126796Sphk unit = dev2unit(dev); 41383043Sbrooks 41463670Snsayer /* select device: tap or vmnet */ 415126796Sphk if (unit & VMNET_DEV_MASK) { 41663670Snsayer name = VMNET; 41763803Snsayer tp->tap_flags |= TAP_VMNET; 41883043Sbrooks } else 41963670Snsayer name = TAP; 42063670Snsayer 421126796Sphk unit &= TAPMAXUNIT; 422126796Sphk 423183397Sed TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, dev2unit(dev)); 42483043Sbrooks 42563670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 42663670Snsayer macaddr_hi = htons(0x00bd); 427178221Semax macaddr_mid = (uint32_t) ticks; 428147256Sbrooks bcopy(&macaddr_hi, eaddr, sizeof(short)); 429178221Semax bcopy(&macaddr_mid, &eaddr[2], sizeof(uint32_t)); 430147256Sbrooks eaddr[5] = (u_char)unit; 43163670Snsayer 432111742Sdes /* fill the rest and attach interface */ 433147256Sbrooks ifp = tp->tap_ifp = if_alloc(IFT_ETHER); 434147256Sbrooks if (ifp == NULL) 435147256Sbrooks panic("%s%d: can not if_alloc()", name, unit); 43663670Snsayer ifp->if_softc = tp; 437121816Sbrooks if_initname(ifp, name, unit); 43863670Snsayer ifp->if_init = tapifinit; 43963670Snsayer ifp->if_start = tapifstart; 44063670Snsayer ifp->if_ioctl = tapifioctl; 44163670Snsayer ifp->if_mtu = ETHERMTU; 44263670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 443213028Sjhb IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 444205222Sqingli ifp->if_capabilities |= IFCAP_LINKSTATE; 445205222Sqingli ifp->if_capenable |= IFCAP_LINKSTATE; 44663670Snsayer 44783043Sbrooks dev->si_drv1 = tp; 448126077Sphk tp->tap_dev = dev; 44983043Sbrooks 450147256Sbrooks ether_ifattach(ifp, eaddr); 45163670Snsayer 452127098Srwatson mtx_lock(&tp->tap_mtx); 45363803Snsayer tp->tap_flags |= TAP_INITED; 454127098Srwatson mtx_unlock(&tp->tap_mtx); 45563803Snsayer 456213028Sjhb knlist_init_mtx(&tp->tap_rsel.si_note, &tp->tap_mtx); 457158697Semax 458121816Sbrooks TAPDEBUG("interface %s is created. minor = %#x\n", 459183397Sed ifp->if_xname, dev2unit(dev)); 46063670Snsayer} /* tapcreate */ 46163670Snsayer 46263670Snsayer 46363670Snsayer/* 464111742Sdes * tapopen 46563670Snsayer * 46663670Snsayer * to open tunnel. must be superuser 46763670Snsayer */ 46863670Snsayerstatic int 469156783Semaxtapopen(struct cdev *dev, int flag, int mode, struct thread *td) 47063670Snsayer{ 47163670Snsayer struct tap_softc *tp = NULL; 472133460Semax struct ifnet *ifp = NULL; 473213028Sjhb int error; 47463670Snsayer 475164033Srwatson if (tapuopen == 0) { 476164033Srwatson error = priv_check(td, PRIV_NET_TAP); 477164033Srwatson if (error) 478164033Srwatson return (error); 479164033Srwatson } 48063670Snsayer 481126796Sphk if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT) 482126796Sphk return (ENXIO); 48383043Sbrooks 48463670Snsayer tp = dev->si_drv1; 48563670Snsayer 486127165Srwatson mtx_lock(&tp->tap_mtx); 487127165Srwatson if (tp->tap_flags & TAP_OPEN) { 488127165Srwatson mtx_unlock(&tp->tap_mtx); 489127165Srwatson return (EBUSY); 490127165Srwatson } 49163670Snsayer 492152315Sru bcopy(IF_LLADDR(tp->tap_ifp), tp->ether_addr, sizeof(tp->ether_addr)); 49383366Sjulian tp->tap_pid = td->td_proc->p_pid; 49463670Snsayer tp->tap_flags |= TAP_OPEN; 495147256Sbrooks ifp = tp->tap_ifp; 49663670Snsayer 497148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 498148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 499167713Sbms if (tapuponopen) 500167713Sbms ifp->if_flags |= IFF_UP; 501205024Sqingli if_link_state_change(ifp, LINK_STATE_UP); 502213028Sjhb mtx_unlock(&tp->tap_mtx); 50363670Snsayer 504183397Sed TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, dev2unit(dev)); 505133460Semax 50663670Snsayer return (0); 50763670Snsayer} /* tapopen */ 50863670Snsayer 50963670Snsayer 51063670Snsayer/* 51163670Snsayer * tapclose 51263670Snsayer * 51363670Snsayer * close the device - mark i/f down & delete routing info 51463670Snsayer */ 51563670Snsayerstatic int 516156783Semaxtapclose(struct cdev *dev, int foo, int bar, struct thread *td) 51763670Snsayer{ 518156783Semax struct ifaddr *ifa; 51963670Snsayer struct tap_softc *tp = dev->si_drv1; 520147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 52163670Snsayer 52263670Snsayer /* junk all pending output */ 523213028Sjhb mtx_lock(&tp->tap_mtx); 52483043Sbrooks IF_DRAIN(&ifp->if_snd); 52563670Snsayer 52663803Snsayer /* 52763803Snsayer * do not bring the interface down, and do not anything with 52863803Snsayer * interface, if we are in VMnet mode. just close the device. 52963803Snsayer */ 53063803Snsayer 53163803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 532127098Srwatson mtx_unlock(&tp->tap_mtx); 53363670Snsayer if_down(ifp); 534213028Sjhb mtx_lock(&tp->tap_mtx); 535148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 536213028Sjhb ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 537213028Sjhb mtx_unlock(&tp->tap_mtx); 53863803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 539146620Speadar rtinit(ifa, (int)RTM_DELETE, 0); 54063670Snsayer } 541146620Speadar if_purgeaddrs(ifp); 542213028Sjhb mtx_lock(&tp->tap_mtx); 54363670Snsayer } 544213028Sjhb } 54563670Snsayer 546205024Sqingli if_link_state_change(ifp, LINK_STATE_DOWN); 54796122Salfred funsetown(&tp->tap_sigio); 548122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 549213028Sjhb KNOTE_LOCKED(&tp->tap_rsel.si_note, 0); 55063670Snsayer 55163670Snsayer tp->tap_flags &= ~TAP_OPEN; 55263670Snsayer tp->tap_pid = 0; 553127098Srwatson mtx_unlock(&tp->tap_mtx); 55463670Snsayer 555121816Sbrooks TAPDEBUG("%s is closed. minor = %#x\n", 556183397Sed ifp->if_xname, dev2unit(dev)); 55763670Snsayer 55863670Snsayer return (0); 55963670Snsayer} /* tapclose */ 56063670Snsayer 56163670Snsayer 56263670Snsayer/* 56363670Snsayer * tapifinit 56463670Snsayer * 56563670Snsayer * network interface initialization function 56663670Snsayer */ 56763670Snsayerstatic void 568156783Semaxtapifinit(void *xtp) 56963670Snsayer{ 57063670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 571147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 57263670Snsayer 573121816Sbrooks TAPDEBUG("initializing %s\n", ifp->if_xname); 57463670Snsayer 575213028Sjhb mtx_lock(&tp->tap_mtx); 576148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 577148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 578213028Sjhb mtx_unlock(&tp->tap_mtx); 57963670Snsayer 58063670Snsayer /* attempt to start output */ 58163670Snsayer tapifstart(ifp); 58263670Snsayer} /* tapifinit */ 58363670Snsayer 58463670Snsayer 58563670Snsayer/* 58663670Snsayer * tapifioctl 58763670Snsayer * 58863670Snsayer * Process an ioctl request on network interface 58963670Snsayer */ 590105228Sphkstatic int 591156783Semaxtapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 59263670Snsayer{ 593160376Sbrooks struct tap_softc *tp = ifp->if_softc; 594189866Sscf struct ifreq *ifr = (struct ifreq *)data; 59563670Snsayer struct ifstat *ifs = NULL; 596213028Sjhb int dummy; 59763670Snsayer 59863670Snsayer switch (cmd) { 59963670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 60063670Snsayer case SIOCADDMULTI: 60163670Snsayer case SIOCDELMULTI: 60283043Sbrooks break; 60363670Snsayer 604189866Sscf case SIOCSIFMTU: 605189866Sscf ifp->if_mtu = ifr->ifr_mtu; 606189866Sscf break; 607189866Sscf 60863670Snsayer case SIOCGIFSTATUS: 60963670Snsayer ifs = (struct ifstat *)data; 61063670Snsayer dummy = strlen(ifs->ascii); 611127098Srwatson mtx_lock(&tp->tap_mtx); 61263670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 61363670Snsayer snprintf(ifs->ascii + dummy, 61463670Snsayer sizeof(ifs->ascii) - dummy, 61563670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 616127098Srwatson mtx_unlock(&tp->tap_mtx); 61783043Sbrooks break; 61863670Snsayer 61963670Snsayer default: 620213028Sjhb return (ether_ioctl(ifp, cmd, data)); 621156783Semax /* NOT REACHED */ 62263670Snsayer } 62363670Snsayer 62463670Snsayer return (0); 62563670Snsayer} /* tapifioctl */ 62663670Snsayer 62763670Snsayer 62863670Snsayer/* 629111742Sdes * tapifstart 630111742Sdes * 63163670Snsayer * queue packets from higher level ready to put out 63263670Snsayer */ 63363670Snsayerstatic void 634156783Semaxtapifstart(struct ifnet *ifp) 63563670Snsayer{ 63663670Snsayer struct tap_softc *tp = ifp->if_softc; 63763670Snsayer 638121816Sbrooks TAPDEBUG("%s starting\n", ifp->if_xname); 63963670Snsayer 64063803Snsayer /* 64163803Snsayer * do not junk pending output if we are in VMnet mode. 64263803Snsayer * XXX: can this do any harm because of queue overflow? 64363803Snsayer */ 64463803Snsayer 645127098Srwatson mtx_lock(&tp->tap_mtx); 646111742Sdes if (((tp->tap_flags & TAP_VMNET) == 0) && 64763803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 648213028Sjhb struct mbuf *m; 64963670Snsayer 650127098Srwatson /* Unlocked read. */ 651121816Sbrooks TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 652121816Sbrooks tp->tap_flags); 65363670Snsayer 654213028Sjhb for (;;) { 65563670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 656213028Sjhb if (m != NULL) { 65763670Snsayer m_freem(m); 658213028Sjhb ifp->if_oerrors++; 659213028Sjhb } else 660213028Sjhb break; 661213028Sjhb } 662213028Sjhb mtx_unlock(&tp->tap_mtx); 66363670Snsayer 66463670Snsayer return; 66563670Snsayer } 66663670Snsayer 667148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 66863670Snsayer 669213028Sjhb if (!IFQ_IS_EMPTY(&ifp->if_snd)) { 67063670Snsayer if (tp->tap_flags & TAP_RWAIT) { 67163670Snsayer tp->tap_flags &= ~TAP_RWAIT; 672111748Sdes wakeup(tp); 67363670Snsayer } 67463670Snsayer 675127098Srwatson if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) { 676127098Srwatson mtx_unlock(&tp->tap_mtx); 67795883Salfred pgsigio(&tp->tap_sigio, SIGIO, 0); 678213028Sjhb mtx_lock(&tp->tap_mtx); 679213028Sjhb } 68063670Snsayer 681122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 682213028Sjhb KNOTE_LOCKED(&tp->tap_rsel.si_note, 0); 68363670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 68463670Snsayer } 68563670Snsayer 686148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 687213028Sjhb mtx_unlock(&tp->tap_mtx); 68863670Snsayer} /* tapifstart */ 68963670Snsayer 69063670Snsayer 69163670Snsayer/* 69263670Snsayer * tapioctl 69363670Snsayer * 69463670Snsayer * the cdevsw interface is now pretty minimal 69563670Snsayer */ 69663670Snsayerstatic int 697156783Semaxtapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 69863670Snsayer{ 69963670Snsayer struct tap_softc *tp = dev->si_drv1; 700147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 701111742Sdes struct tapinfo *tapp = NULL; 702102052Ssobomax int f; 703162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 704162711Sru defined(COMPAT_FREEBSD4) 705162711Sru int ival; 706162711Sru#endif 70763670Snsayer 70863670Snsayer switch (cmd) { 709111742Sdes case TAPSIFINFO: 710111742Sdes tapp = (struct tapinfo *)data; 711213028Sjhb mtx_lock(&tp->tap_mtx); 712111742Sdes ifp->if_mtu = tapp->mtu; 713111742Sdes ifp->if_type = tapp->type; 714111742Sdes ifp->if_baudrate = tapp->baudrate; 715213028Sjhb mtx_unlock(&tp->tap_mtx); 716111742Sdes break; 71763670Snsayer 718111742Sdes case TAPGIFINFO: 719111742Sdes tapp = (struct tapinfo *)data; 720213028Sjhb mtx_lock(&tp->tap_mtx); 721111742Sdes tapp->mtu = ifp->if_mtu; 722111742Sdes tapp->type = ifp->if_type; 723111742Sdes tapp->baudrate = ifp->if_baudrate; 724213028Sjhb mtx_unlock(&tp->tap_mtx); 725111742Sdes break; 72663670Snsayer 72763670Snsayer case TAPSDEBUG: 728159079Smarius tapdebug = *(int *)data; 72983043Sbrooks break; 73063670Snsayer 73163670Snsayer case TAPGDEBUG: 732159079Smarius *(int *)data = tapdebug; 73383043Sbrooks break; 73463670Snsayer 735182880Semax case TAPGIFNAME: { 736182880Semax struct ifreq *ifr = (struct ifreq *) data; 737182880Semax 738182880Semax strlcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ); 739182880Semax } break; 740182880Semax 74163670Snsayer case FIONBIO: 74283043Sbrooks break; 74363670Snsayer 74463670Snsayer case FIOASYNC: 745127098Srwatson mtx_lock(&tp->tap_mtx); 746159079Smarius if (*(int *)data) 74763670Snsayer tp->tap_flags |= TAP_ASYNC; 74863670Snsayer else 74963670Snsayer tp->tap_flags &= ~TAP_ASYNC; 750127098Srwatson mtx_unlock(&tp->tap_mtx); 75183043Sbrooks break; 75263670Snsayer 75363670Snsayer case FIONREAD: 754213028Sjhb if (!IFQ_IS_EMPTY(&ifp->if_snd)) { 755213028Sjhb struct mbuf *mb; 75663670Snsayer 757213028Sjhb IFQ_LOCK(&ifp->if_snd); 758213028Sjhb IFQ_POLL_NOLOCK(&ifp->if_snd, mb); 759213028Sjhb for (*(int *)data = 0; mb != NULL; 760213028Sjhb mb = mb->m_next) 761159079Smarius *(int *)data += mb->m_len; 762213028Sjhb IFQ_UNLOCK(&ifp->if_snd); 76383043Sbrooks } else 764159079Smarius *(int *)data = 0; 76583043Sbrooks break; 76663670Snsayer 76763670Snsayer case FIOSETOWN: 768159079Smarius return (fsetown(*(int *)data, &tp->tap_sigio)); 76963670Snsayer 77063670Snsayer case FIOGETOWN: 771159079Smarius *(int *)data = fgetown(&tp->tap_sigio); 77263670Snsayer return (0); 77363670Snsayer 77463670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 77563670Snsayer case TIOCSPGRP: 776159079Smarius return (fsetown(-(*(int *)data), &tp->tap_sigio)); 77763670Snsayer 77863670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 77963670Snsayer case TIOCGPGRP: 780159079Smarius *(int *)data = -fgetown(&tp->tap_sigio); 78163670Snsayer return (0); 78263670Snsayer 78363670Snsayer /* VMware/VMnet port ioctl's */ 78463670Snsayer 785162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 786162711Sru defined(COMPAT_FREEBSD4) 787162711Sru case _IO('V', 0): 788162711Sru ival = IOCPARM_IVAL(data); 789162711Sru data = (caddr_t)&ival; 790162711Sru /* FALLTHROUGH */ 791162711Sru#endif 79283043Sbrooks case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 793162711Sru f = *(int *)data; 79463670Snsayer f &= 0x0fff; 79563670Snsayer f &= ~IFF_CANTCHANGE; 79663670Snsayer f |= IFF_UP; 79763670Snsayer 798213028Sjhb mtx_lock(&tp->tap_mtx); 79963670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 800213028Sjhb mtx_unlock(&tp->tap_mtx); 80183043Sbrooks break; 80263670Snsayer 80363861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 80463670Snsayer case SIOCGIFADDR: 805127165Srwatson mtx_lock(&tp->tap_mtx); 80663861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 807127165Srwatson mtx_unlock(&tp->tap_mtx); 80883043Sbrooks break; 80963670Snsayer 81063861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 811127165Srwatson mtx_lock(&tp->tap_mtx); 81263861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 813127165Srwatson mtx_unlock(&tp->tap_mtx); 81483043Sbrooks break; 81563670Snsayer 81663670Snsayer default: 81763670Snsayer return (ENOTTY); 81863670Snsayer } 81963670Snsayer return (0); 82063670Snsayer} /* tapioctl */ 82163670Snsayer 82263670Snsayer 82363670Snsayer/* 82463670Snsayer * tapread 82563670Snsayer * 82663670Snsayer * the cdevsw read interface - reads a packet at a time, or at 82763670Snsayer * least as much of a packet as can be read 82863670Snsayer */ 82963670Snsayerstatic int 830156783Semaxtapread(struct cdev *dev, struct uio *uio, int flag) 83163670Snsayer{ 83263670Snsayer struct tap_softc *tp = dev->si_drv1; 833147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 83490227Sdillon struct mbuf *m = NULL; 835213028Sjhb int error = 0, len; 83663670Snsayer 837183397Sed TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, dev2unit(dev)); 83863670Snsayer 839127098Srwatson mtx_lock(&tp->tap_mtx); 84063670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 841127098Srwatson mtx_unlock(&tp->tap_mtx); 842127098Srwatson 843127098Srwatson /* Unlocked read. */ 844121816Sbrooks TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 845183397Sed ifp->if_xname, dev2unit(dev), tp->tap_flags); 84663803Snsayer 84763670Snsayer return (EHOSTDOWN); 84863670Snsayer } 84963670Snsayer 85063670Snsayer tp->tap_flags &= ~TAP_RWAIT; 85163670Snsayer 85263670Snsayer /* sleep until we get a packet */ 85363670Snsayer do { 85490227Sdillon IF_DEQUEUE(&ifp->if_snd, m); 85563670Snsayer 85690227Sdillon if (m == NULL) { 857213028Sjhb if (flag & O_NONBLOCK) { 858213028Sjhb mtx_unlock(&tp->tap_mtx); 85963670Snsayer return (EWOULDBLOCK); 860213028Sjhb } 861111742Sdes 86263670Snsayer tp->tap_flags |= TAP_RWAIT; 863213028Sjhb error = mtx_sleep(tp, &tp->tap_mtx, PCATCH | (PZERO + 1), 864213028Sjhb "taprd", 0); 865213028Sjhb if (error) { 866213028Sjhb mtx_unlock(&tp->tap_mtx); 86763670Snsayer return (error); 868213028Sjhb } 86963670Snsayer } 87090227Sdillon } while (m == NULL); 871213028Sjhb mtx_unlock(&tp->tap_mtx); 87263670Snsayer 87363670Snsayer /* feed packet to bpf */ 874106939Ssam BPF_MTAP(ifp, m); 87563670Snsayer 87663670Snsayer /* xfer packet to user space */ 87790227Sdillon while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 87890227Sdillon len = min(uio->uio_resid, m->m_len); 87963670Snsayer if (len == 0) 88063670Snsayer break; 88163670Snsayer 882111741Sdes error = uiomove(mtod(m, void *), len, uio); 88390227Sdillon m = m_free(m); 88463670Snsayer } 88563670Snsayer 88690227Sdillon if (m != NULL) { 887121816Sbrooks TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 888183397Sed dev2unit(dev)); 88990227Sdillon m_freem(m); 89063670Snsayer } 89163670Snsayer 89263670Snsayer return (error); 89363670Snsayer} /* tapread */ 89463670Snsayer 89563670Snsayer 89663670Snsayer/* 89763670Snsayer * tapwrite 89863670Snsayer * 89963670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 90063670Snsayer */ 90163670Snsayerstatic int 902156783Semaxtapwrite(struct cdev *dev, struct uio *uio, int flag) 90363670Snsayer{ 904166443Sbms struct ether_header *eh; 90563670Snsayer struct tap_softc *tp = dev->si_drv1; 906147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 907137101Sglebius struct mbuf *m; 90863670Snsayer 909121816Sbrooks TAPDEBUG("%s writting, minor = %#x\n", 910183397Sed ifp->if_xname, dev2unit(dev)); 91163670Snsayer 91263670Snsayer if (uio->uio_resid == 0) 91363670Snsayer return (0); 91463670Snsayer 91563670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 916194990Skib TAPDEBUG("%s invalid packet len = %zd, minor = %#x\n", 917183397Sed ifp->if_xname, uio->uio_resid, dev2unit(dev)); 91863803Snsayer 91963670Snsayer return (EIO); 92063670Snsayer } 92163670Snsayer 922163915Sandre if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, ETHER_ALIGN, 923163915Sandre M_PKTHDR)) == NULL) { 92463670Snsayer ifp->if_ierrors ++; 925163986Scsjp return (ENOBUFS); 92663670Snsayer } 92763670Snsayer 928137101Sglebius m->m_pkthdr.rcvif = ifp; 929111742Sdes 930166443Sbms /* 931166443Sbms * Only pass a unicast frame to ether_input(), if it would actually 932166443Sbms * have been received by non-virtual hardware. 933166443Sbms */ 934166443Sbms if (m->m_len < sizeof(struct ether_header)) { 935166443Sbms m_freem(m); 936166443Sbms return (0); 937166443Sbms } 938166443Sbms eh = mtod(m, struct ether_header *); 939166443Sbms 940166443Sbms if (eh && (ifp->if_flags & IFF_PROMISC) == 0 && 941166443Sbms !ETHER_IS_MULTICAST(eh->ether_dhost) && 942166443Sbms bcmp(eh->ether_dhost, IF_LLADDR(ifp), ETHER_ADDR_LEN) != 0) { 943166443Sbms m_freem(m); 944166443Sbms return (0); 945166443Sbms } 946166443Sbms 947106939Ssam /* Pass packet up to parent. */ 948137101Sglebius (*ifp->if_input)(ifp, m); 949106939Ssam ifp->if_ipackets ++; /* ibytes are counted in parent */ 95063670Snsayer 95163670Snsayer return (0); 95263670Snsayer} /* tapwrite */ 95363670Snsayer 95463670Snsayer 95563670Snsayer/* 95663670Snsayer * tappoll 95763670Snsayer * 95863670Snsayer * the poll interface, this is only useful on reads 95963670Snsayer * really. the write detect always returns true, write never blocks 96063670Snsayer * anyway, it either accepts the packet or drops it 96163670Snsayer */ 96263670Snsayerstatic int 963156783Semaxtappoll(struct cdev *dev, int events, struct thread *td) 96463670Snsayer{ 96563670Snsayer struct tap_softc *tp = dev->si_drv1; 966147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 967213028Sjhb int revents = 0; 96863670Snsayer 969121816Sbrooks TAPDEBUG("%s polling, minor = %#x\n", 970183397Sed ifp->if_xname, dev2unit(dev)); 97163670Snsayer 97263670Snsayer if (events & (POLLIN | POLLRDNORM)) { 973213028Sjhb IFQ_LOCK(&ifp->if_snd); 974213028Sjhb if (!IFQ_IS_EMPTY(&ifp->if_snd)) { 975121816Sbrooks TAPDEBUG("%s have data in queue. len = %d, " \ 976121816Sbrooks "minor = %#x\n", ifp->if_xname, 977183397Sed ifp->if_snd.ifq_len, dev2unit(dev)); 97863803Snsayer 97963670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 98083043Sbrooks } else { 981121816Sbrooks TAPDEBUG("%s waiting for data, minor = %#x\n", 982183397Sed ifp->if_xname, dev2unit(dev)); 98363803Snsayer 98483805Sjhb selrecord(td, &tp->tap_rsel); 98563670Snsayer } 986213028Sjhb IFQ_UNLOCK(&ifp->if_snd); 98763670Snsayer } 98863670Snsayer 98963670Snsayer if (events & (POLLOUT | POLLWRNORM)) 99063670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 99163670Snsayer 99263670Snsayer return (revents); 99363670Snsayer} /* tappoll */ 994156783Semax 995156783Semax 996156783Semax/* 997156783Semax * tap_kqfilter 998156783Semax * 999156783Semax * support for kevent() system call 1000156783Semax */ 1001156783Semaxstatic int 1002156783Semaxtapkqfilter(struct cdev *dev, struct knote *kn) 1003156783Semax{ 1004156783Semax struct tap_softc *tp = dev->si_drv1; 1005156783Semax struct ifnet *ifp = tp->tap_ifp; 1006156783Semax 1007156783Semax switch (kn->kn_filter) { 1008156783Semax case EVFILT_READ: 1009156783Semax TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n", 1010183397Sed ifp->if_xname, dev2unit(dev)); 1011156783Semax kn->kn_fop = &tap_read_filterops; 1012156783Semax break; 1013156783Semax 1014156783Semax case EVFILT_WRITE: 1015156783Semax TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n", 1016183397Sed ifp->if_xname, dev2unit(dev)); 1017156783Semax kn->kn_fop = &tap_write_filterops; 1018156783Semax break; 1019156783Semax 1020156783Semax default: 1021156783Semax TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n", 1022183397Sed ifp->if_xname, dev2unit(dev)); 1023156783Semax return (EINVAL); 1024156783Semax /* NOT REACHED */ 1025156783Semax } 1026156783Semax 1027213028Sjhb kn->kn_hook = tp; 1028156783Semax knlist_add(&tp->tap_rsel.si_note, kn, 0); 1029156783Semax 1030156783Semax return (0); 1031156783Semax} /* tapkqfilter */ 1032156783Semax 1033156783Semax 1034156783Semax/* 1035156783Semax * tap_kqread 1036156783Semax * 1037156783Semax * Return true if there is data in the interface queue 1038156783Semax */ 1039156783Semaxstatic int 1040156783Semaxtapkqread(struct knote *kn, long hint) 1041156783Semax{ 1042213028Sjhb int ret; 1043213028Sjhb struct tap_softc *tp = kn->kn_hook; 1044213028Sjhb struct cdev *dev = tp->tap_dev; 1045156783Semax struct ifnet *ifp = tp->tap_ifp; 1046156783Semax 1047156783Semax if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) { 1048156783Semax TAPDEBUG("%s have data in queue. len = %d, minor = %#x\n", 1049183397Sed ifp->if_xname, ifp->if_snd.ifq_len, dev2unit(dev)); 1050156783Semax ret = 1; 1051156783Semax } else { 1052156783Semax TAPDEBUG("%s waiting for data, minor = %#x\n", 1053183397Sed ifp->if_xname, dev2unit(dev)); 1054156783Semax ret = 0; 1055156783Semax } 1056156783Semax 1057156783Semax return (ret); 1058156783Semax} /* tapkqread */ 1059156783Semax 1060156783Semax 1061156783Semax/* 1062156783Semax * tap_kqwrite 1063156783Semax * 1064156783Semax * Always can write. Return the MTU in kn->data 1065156783Semax */ 1066156783Semaxstatic int 1067156783Semaxtapkqwrite(struct knote *kn, long hint) 1068156783Semax{ 1069213028Sjhb struct tap_softc *tp = kn->kn_hook; 1070156783Semax struct ifnet *ifp = tp->tap_ifp; 1071156783Semax 1072156783Semax kn->kn_data = ifp->if_mtu; 1073156783Semax 1074156783Semax return (1); 1075156783Semax} /* tapkqwrite */ 1076156783Semax 1077156783Semax 1078156783Semaxstatic void 1079156783Semaxtapkqdetach(struct knote *kn) 1080156783Semax{ 1081213028Sjhb struct tap_softc *tp = kn->kn_hook; 1082156783Semax 1083156783Semax knlist_remove(&tp->tap_rsel.si_note, kn, 0); 1084156783Semax} /* tapkqdetach */ 1085156783Semax 1086