if_tap.c revision 236725
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 236725 2012-06-07 19:48:45Z trociny $ 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> 45236724Strociny#include <sys/jail.h> 4663670Snsayer#include <sys/kernel.h> 4763670Snsayer#include <sys/malloc.h> 4863670Snsayer#include <sys/mbuf.h> 49129880Sphk#include <sys/module.h> 5063670Snsayer#include <sys/poll.h> 51164033Srwatson#include <sys/priv.h> 5263670Snsayer#include <sys/proc.h> 53139207Sphk#include <sys/selinfo.h> 5463670Snsayer#include <sys/signalvar.h> 5563670Snsayer#include <sys/socket.h> 5663670Snsayer#include <sys/sockio.h> 5763670Snsayer#include <sys/sysctl.h> 5863670Snsayer#include <sys/systm.h> 5963670Snsayer#include <sys/ttycom.h> 6063670Snsayer#include <sys/uio.h> 6183043Sbrooks#include <sys/queue.h> 6263670Snsayer 6363670Snsayer#include <net/bpf.h> 6463670Snsayer#include <net/ethernet.h> 6563670Snsayer#include <net/if.h> 66166497Sbms#include <net/if_clone.h> 67152315Sru#include <net/if_dl.h> 68236725Strociny#include <net/if_types.h> 6963670Snsayer#include <net/route.h> 70236724Strociny#include <net/vnet.h> 7163670Snsayer 7263670Snsayer#include <netinet/in.h> 7363670Snsayer 7463670Snsayer#include <net/if_tapvar.h> 7563670Snsayer#include <net/if_tap.h> 7663670Snsayer 7763670Snsayer 7863670Snsayer#define CDEV_NAME "tap" 7963670Snsayer#define TAPDEBUG if (tapdebug) printf 8063670Snsayer 8163670Snsayer#define TAP "tap" 8263670Snsayer#define VMNET "vmnet" 8383043Sbrooks#define TAPMAXUNIT 0x7fff 84126077Sphk#define VMNET_DEV_MASK CLONE_FLAG0 8563670Snsayer 8663670Snsayer/* module */ 87111742Sdesstatic int tapmodevent(module_t, int, void *); 8863670Snsayer 8963670Snsayer/* device */ 90148868Srwatsonstatic void tapclone(void *, struct ucred *, char *, int, 91148868Srwatson struct cdev **); 92130585Sphkstatic void tapcreate(struct cdev *); 9363670Snsayer 9463670Snsayer/* network interface */ 9593084Sbdestatic void tapifstart(struct ifnet *); 9693084Sbdestatic int tapifioctl(struct ifnet *, u_long, caddr_t); 9793084Sbdestatic void tapifinit(void *); 9863670Snsayer 99166497Sbmsstatic int tap_clone_create(struct if_clone *, int, caddr_t); 100166497Sbmsstatic void tap_clone_destroy(struct ifnet *); 101166497Sbmsstatic int vmnet_clone_create(struct if_clone *, int, caddr_t); 102166497Sbmsstatic void vmnet_clone_destroy(struct ifnet *); 103166497Sbms 104166497SbmsIFC_SIMPLE_DECLARE(tap, 0); 105166497SbmsIFC_SIMPLE_DECLARE(vmnet, 0); 106166497Sbms 10763670Snsayer/* character device */ 10863670Snsayerstatic d_open_t tapopen; 10963670Snsayerstatic d_close_t tapclose; 11063670Snsayerstatic d_read_t tapread; 11163670Snsayerstatic d_write_t tapwrite; 11263670Snsayerstatic d_ioctl_t tapioctl; 11363670Snsayerstatic d_poll_t tappoll; 114156783Semaxstatic d_kqfilter_t tapkqfilter; 11563670Snsayer 116156783Semax/* kqueue(2) */ 117156783Semaxstatic int tapkqread(struct knote *, long); 118156783Semaxstatic int tapkqwrite(struct knote *, long); 119156783Semaxstatic void tapkqdetach(struct knote *); 120156783Semax 121156783Semaxstatic struct filterops tap_read_filterops = { 122156783Semax .f_isfd = 1, 123156783Semax .f_attach = NULL, 124156783Semax .f_detach = tapkqdetach, 125156783Semax .f_event = tapkqread, 126156783Semax}; 127156783Semax 128156783Semaxstatic struct filterops tap_write_filterops = { 129156783Semax .f_isfd = 1, 130156783Semax .f_attach = NULL, 131156783Semax .f_detach = tapkqdetach, 132156783Semax .f_event = tapkqwrite, 133156783Semax}; 134156783Semax 13563670Snsayerstatic struct cdevsw tap_cdevsw = { 136126080Sphk .d_version = D_VERSION, 137226500Sed .d_flags = D_NEEDMINOR, 138111815Sphk .d_open = tapopen, 139111815Sphk .d_close = tapclose, 140111815Sphk .d_read = tapread, 141111815Sphk .d_write = tapwrite, 142111815Sphk .d_ioctl = tapioctl, 143111815Sphk .d_poll = tappoll, 144111815Sphk .d_name = CDEV_NAME, 145156783Semax .d_kqfilter = tapkqfilter, 14663670Snsayer}; 14763670Snsayer 148127003Srwatson/* 149127003Srwatson * All global variables in if_tap.c are locked with tapmtx, with the 150127003Srwatson * exception of tapdebug, which is accessed unlocked; tapclones is 151127003Srwatson * static at runtime. 152127003Srwatson */ 153127003Srwatsonstatic struct mtx tapmtx; 15483043Sbrooksstatic int tapdebug = 0; /* debug flag */ 155167713Sbmsstatic int tapuopen = 0; /* allow user open() */ 156167713Sbmsstatic int tapuponopen = 0; /* IFF_UP on open() */ 157166497Sbmsstatic int tapdclone = 1; /* enable devfs cloning */ 15883043Sbrooksstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 159126077Sphkstatic struct clonedevs *tapclones; 16063670Snsayer 16163670SnsayerMALLOC_DECLARE(M_TAP); 16263670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 16363670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 164144979Smdodd 165144979SmdoddSYSCTL_DECL(_net_link); 166227309Sedstatic SYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0, 167144979Smdodd "Ethernet tunnel software network interface"); 168144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0, 169144979Smdodd "Allow user to open /dev/tap (based on node permissions)"); 170167713SbmsSYSCTL_INT(_net_link_tap, OID_AUTO, up_on_open, CTLFLAG_RW, &tapuponopen, 0, 171167713Sbms "Bring interface up when /dev/tap is opened"); 172166497SbmsSYSCTL_INT(_net_link_tap, OID_AUTO, devfs_cloning, CTLFLAG_RW, &tapdclone, 0, 173166497Sbms "Enably legacy devfs interface creation"); 174144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, ""); 175144979Smdodd 176166497SbmsTUNABLE_INT("net.link.tap.devfs_cloning", &tapdclone); 177166497Sbms 17863670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL); 17963670Snsayer 180166497Sbmsstatic int 181166497Sbmstap_clone_create(struct if_clone *ifc, int unit, caddr_t params) 182166497Sbms{ 183166497Sbms struct cdev *dev; 184166497Sbms int i; 185166497Sbms int extra; 186166497Sbms 187166497Sbms if (strcmp(ifc->ifc_name, VMNET) == 0) 188166497Sbms extra = VMNET_DEV_MASK; 189166497Sbms else 190166497Sbms extra = 0; 191166497Sbms 192166497Sbms /* find any existing device, or allocate new unit number */ 193166497Sbms i = clone_create(&tapclones, &tap_cdevsw, &unit, &dev, extra); 194166497Sbms if (i) { 195183381Sed dev = make_dev(&tap_cdevsw, unit | extra, 196166497Sbms UID_ROOT, GID_WHEEL, 0600, "%s%d", ifc->ifc_name, unit); 197166497Sbms } 198166497Sbms 199166497Sbms tapcreate(dev); 200166497Sbms return (0); 201166497Sbms} 202166497Sbms 203166497Sbms/* vmnet devices are tap devices in disguise */ 204166497Sbmsstatic int 205166497Sbmsvmnet_clone_create(struct if_clone *ifc, int unit, caddr_t params) 206166497Sbms{ 207166497Sbms return tap_clone_create(ifc, unit, params); 208166497Sbms} 209166497Sbms 210166497Sbmsstatic void 211166497Sbmstap_destroy(struct tap_softc *tp) 212166497Sbms{ 213166497Sbms struct ifnet *ifp = tp->tap_ifp; 214166497Sbms 215166497Sbms /* Unlocked read. */ 216166497Sbms KASSERT(!(tp->tap_flags & TAP_OPEN), 217166497Sbms ("%s flags is out of sync", ifp->if_xname)); 218166497Sbms 219236724Strociny CURVNET_SET(ifp->if_vnet); 220225177Sattilio seldrain(&tp->tap_rsel); 221166497Sbms knlist_destroy(&tp->tap_rsel.si_note); 222166497Sbms destroy_dev(tp->tap_dev); 223166497Sbms ether_ifdetach(ifp); 224227459Sbrooks if_free(ifp); 225166497Sbms 226166497Sbms mtx_destroy(&tp->tap_mtx); 227166497Sbms free(tp, M_TAP); 228236724Strociny CURVNET_RESTORE(); 229166497Sbms} 230166497Sbms 231166497Sbmsstatic void 232166497Sbmstap_clone_destroy(struct ifnet *ifp) 233166497Sbms{ 234166497Sbms struct tap_softc *tp = ifp->if_softc; 235166497Sbms 236166497Sbms mtx_lock(&tapmtx); 237166497Sbms SLIST_REMOVE(&taphead, tp, tap_softc, tap_next); 238166497Sbms mtx_unlock(&tapmtx); 239166497Sbms tap_destroy(tp); 240166497Sbms} 241166497Sbms 242166497Sbms/* vmnet devices are tap devices in disguise */ 243166497Sbmsstatic void 244166497Sbmsvmnet_clone_destroy(struct ifnet *ifp) 245166497Sbms{ 246166497Sbms tap_clone_destroy(ifp); 247166497Sbms} 248166497Sbms 24963670Snsayer/* 25063670Snsayer * tapmodevent 25163670Snsayer * 25263670Snsayer * module event handler 25363670Snsayer */ 25463670Snsayerstatic int 255156783Semaxtapmodevent(module_t mod, int type, void *data) 25663670Snsayer{ 25783043Sbrooks static eventhandler_tag eh_tag = NULL; 25883043Sbrooks struct tap_softc *tp = NULL; 25983043Sbrooks struct ifnet *ifp = NULL; 26063670Snsayer 26163670Snsayer switch (type) { 26263670Snsayer case MOD_LOAD: 26363670Snsayer 26483043Sbrooks /* intitialize device */ 26583043Sbrooks 266127003Srwatson mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF); 26783043Sbrooks SLIST_INIT(&taphead); 26883043Sbrooks 269126845Sphk clone_setup(&tapclones); 27071602Sphk eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 271127003Srwatson if (eh_tag == NULL) { 272127170Srwatson clone_cleanup(&tapclones); 273127003Srwatson mtx_destroy(&tapmtx); 274126077Sphk return (ENOMEM); 275127003Srwatson } 276166497Sbms if_clone_attach(&tap_cloner); 277166497Sbms if_clone_attach(&vmnet_cloner); 27883043Sbrooks return (0); 27963670Snsayer 28083043Sbrooks case MOD_UNLOAD: 281127003Srwatson /* 282127003Srwatson * The EBUSY algorithm here can't quite atomically 283127003Srwatson * guarantee that this is race-free since we have to 284127003Srwatson * release the tap mtx to deregister the clone handler. 285127003Srwatson */ 286127003Srwatson mtx_lock(&tapmtx); 287127003Srwatson SLIST_FOREACH(tp, &taphead, tap_next) { 288127098Srwatson mtx_lock(&tp->tap_mtx); 289127003Srwatson if (tp->tap_flags & TAP_OPEN) { 290127098Srwatson mtx_unlock(&tp->tap_mtx); 291127003Srwatson mtx_unlock(&tapmtx); 29283043Sbrooks return (EBUSY); 293127003Srwatson } 294127098Srwatson mtx_unlock(&tp->tap_mtx); 295127003Srwatson } 296127003Srwatson mtx_unlock(&tapmtx); 29783043Sbrooks 29871602Sphk EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 299166497Sbms if_clone_detach(&tap_cloner); 300166497Sbms if_clone_detach(&vmnet_cloner); 301204464Skib drain_dev_clone_events(); 30263670Snsayer 303127003Srwatson mtx_lock(&tapmtx); 30483043Sbrooks while ((tp = SLIST_FIRST(&taphead)) != NULL) { 30583043Sbrooks SLIST_REMOVE_HEAD(&taphead, tap_next); 306127003Srwatson mtx_unlock(&tapmtx); 30783043Sbrooks 308147256Sbrooks ifp = tp->tap_ifp; 30983043Sbrooks 310121816Sbrooks TAPDEBUG("detaching %s\n", ifp->if_xname); 31183043Sbrooks 312166497Sbms tap_destroy(tp); 313127003Srwatson mtx_lock(&tapmtx); 31483043Sbrooks } 315127003Srwatson mtx_unlock(&tapmtx); 316126077Sphk clone_cleanup(&tapclones); 31763670Snsayer 318135354Srwatson mtx_destroy(&tapmtx); 319135354Srwatson 32083043Sbrooks break; 32163670Snsayer 32263670Snsayer default: 32363670Snsayer return (EOPNOTSUPP); 32463670Snsayer } 32563670Snsayer 32663670Snsayer return (0); 32763670Snsayer} /* tapmodevent */ 32863670Snsayer 32963670Snsayer 33063670Snsayer/* 33171602Sphk * DEVFS handler 33271602Sphk * 33371602Sphk * We need to support two kind of devices - tap and vmnet 33471602Sphk */ 33571602Sphkstatic void 336156783Semaxtapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev) 33771602Sphk{ 338166497Sbms char devname[SPECNAMELEN + 1]; 339166497Sbms int i, unit, append_unit; 340166438Sbms int extra; 34171602Sphk 342130640Sphk if (*dev != NULL) 34371602Sphk return; 34471602Sphk 345166514Sbms if (!tapdclone || 346166514Sbms (!tapuopen && priv_check_cred(cred, PRIV_NET_IFCREATE, 0) != 0)) 347166497Sbms return; 348166497Sbms 349166497Sbms unit = 0; 350166497Sbms append_unit = 0; 351126077Sphk extra = 0; 352166497Sbms 353166497Sbms /* We're interested in only tap/vmnet devices. */ 354126077Sphk if (strcmp(name, TAP) == 0) { 355126077Sphk unit = -1; 356126077Sphk } else if (strcmp(name, VMNET) == 0) { 357126077Sphk unit = -1; 358126077Sphk extra = VMNET_DEV_MASK; 359166497Sbms } else if (dev_stdclone(name, NULL, TAP, &unit) != 1) { 360166497Sbms if (dev_stdclone(name, NULL, VMNET, &unit) != 1) { 361126077Sphk return; 362166497Sbms } else { 363166497Sbms extra = VMNET_DEV_MASK; 364166497Sbms } 36583043Sbrooks } 36671602Sphk 367166497Sbms if (unit == -1) 368166497Sbms append_unit = 1; 369166497Sbms 370236724Strociny CURVNET_SET(CRED_TO_VNET(cred)); 371126077Sphk /* find any existing device, or allocate new unit number */ 372126077Sphk i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra); 373126077Sphk if (i) { 374166497Sbms if (append_unit) { 375166497Sbms /* 376166497Sbms * We were passed 'tun' or 'tap', with no unit specified 377166497Sbms * so we'll need to append it now. 378166497Sbms */ 379166497Sbms namelen = snprintf(devname, sizeof(devname), "%s%d", name, 380166497Sbms unit); 381166497Sbms name = devname; 382166497Sbms } 383166497Sbms 384204464Skib *dev = make_dev_credf(MAKEDEV_REF, &tap_cdevsw, unit | extra, 385204464Skib cred, UID_ROOT, GID_WHEEL, 0600, "%s", name); 38671602Sphk } 387166497Sbms 388166497Sbms if_clone_create(name, namelen, NULL); 389236724Strociny CURVNET_RESTORE(); 39071602Sphk} /* tapclone */ 39171602Sphk 39271602Sphk 39371602Sphk/* 39463670Snsayer * tapcreate 39563670Snsayer * 39663670Snsayer * to create interface 39763670Snsayer */ 39863670Snsayerstatic void 399156783Semaxtapcreate(struct cdev *dev) 40063670Snsayer{ 40163670Snsayer struct ifnet *ifp = NULL; 40263670Snsayer struct tap_softc *tp = NULL; 40363670Snsayer unsigned short macaddr_hi; 404178221Semax uint32_t macaddr_mid; 405213028Sjhb int unit; 40663670Snsayer char *name = NULL; 407147256Sbrooks u_char eaddr[6]; 40863670Snsayer 409126077Sphk dev->si_flags &= ~SI_CHEAPCLONE; 410126077Sphk 41163670Snsayer /* allocate driver storage and create device */ 412184205Sdes tp = malloc(sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 413127098Srwatson mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF); 414127003Srwatson mtx_lock(&tapmtx); 41583043Sbrooks SLIST_INSERT_HEAD(&taphead, tp, tap_next); 416127003Srwatson mtx_unlock(&tapmtx); 41763670Snsayer 418126796Sphk unit = dev2unit(dev); 41983043Sbrooks 42063670Snsayer /* select device: tap or vmnet */ 421126796Sphk if (unit & VMNET_DEV_MASK) { 42263670Snsayer name = VMNET; 42363803Snsayer tp->tap_flags |= TAP_VMNET; 42483043Sbrooks } else 42563670Snsayer name = TAP; 42663670Snsayer 427126796Sphk unit &= TAPMAXUNIT; 428126796Sphk 429183397Sed TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, dev2unit(dev)); 43083043Sbrooks 43163670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 43263670Snsayer macaddr_hi = htons(0x00bd); 433178221Semax macaddr_mid = (uint32_t) ticks; 434147256Sbrooks bcopy(&macaddr_hi, eaddr, sizeof(short)); 435178221Semax bcopy(&macaddr_mid, &eaddr[2], sizeof(uint32_t)); 436147256Sbrooks eaddr[5] = (u_char)unit; 43763670Snsayer 438111742Sdes /* fill the rest and attach interface */ 439147256Sbrooks ifp = tp->tap_ifp = if_alloc(IFT_ETHER); 440147256Sbrooks if (ifp == NULL) 441147256Sbrooks panic("%s%d: can not if_alloc()", name, unit); 44263670Snsayer ifp->if_softc = tp; 443121816Sbrooks if_initname(ifp, name, unit); 44463670Snsayer ifp->if_init = tapifinit; 44563670Snsayer ifp->if_start = tapifstart; 44663670Snsayer ifp->if_ioctl = tapifioctl; 44763670Snsayer ifp->if_mtu = ETHERMTU; 44863670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 449213028Sjhb IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 450205222Sqingli ifp->if_capabilities |= IFCAP_LINKSTATE; 451205222Sqingli ifp->if_capenable |= IFCAP_LINKSTATE; 45263670Snsayer 45383043Sbrooks dev->si_drv1 = tp; 454126077Sphk tp->tap_dev = dev; 45583043Sbrooks 456147256Sbrooks ether_ifattach(ifp, eaddr); 45763670Snsayer 458127098Srwatson mtx_lock(&tp->tap_mtx); 45963803Snsayer tp->tap_flags |= TAP_INITED; 460127098Srwatson mtx_unlock(&tp->tap_mtx); 46163803Snsayer 462213028Sjhb knlist_init_mtx(&tp->tap_rsel.si_note, &tp->tap_mtx); 463158697Semax 464121816Sbrooks TAPDEBUG("interface %s is created. minor = %#x\n", 465183397Sed ifp->if_xname, dev2unit(dev)); 46663670Snsayer} /* tapcreate */ 46763670Snsayer 46863670Snsayer 46963670Snsayer/* 470111742Sdes * tapopen 47163670Snsayer * 47263670Snsayer * to open tunnel. must be superuser 47363670Snsayer */ 47463670Snsayerstatic int 475156783Semaxtapopen(struct cdev *dev, int flag, int mode, struct thread *td) 47663670Snsayer{ 47763670Snsayer struct tap_softc *tp = NULL; 478133460Semax struct ifnet *ifp = NULL; 479213028Sjhb int error; 48063670Snsayer 481164033Srwatson if (tapuopen == 0) { 482164033Srwatson error = priv_check(td, PRIV_NET_TAP); 483164033Srwatson if (error) 484164033Srwatson return (error); 485164033Srwatson } 48663670Snsayer 487126796Sphk if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT) 488126796Sphk return (ENXIO); 48983043Sbrooks 49063670Snsayer tp = dev->si_drv1; 49163670Snsayer 492127165Srwatson mtx_lock(&tp->tap_mtx); 493127165Srwatson if (tp->tap_flags & TAP_OPEN) { 494127165Srwatson mtx_unlock(&tp->tap_mtx); 495127165Srwatson return (EBUSY); 496127165Srwatson } 49763670Snsayer 498152315Sru bcopy(IF_LLADDR(tp->tap_ifp), tp->ether_addr, sizeof(tp->ether_addr)); 49983366Sjulian tp->tap_pid = td->td_proc->p_pid; 50063670Snsayer tp->tap_flags |= TAP_OPEN; 501147256Sbrooks ifp = tp->tap_ifp; 50263670Snsayer 503148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 504148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 505167713Sbms if (tapuponopen) 506167713Sbms ifp->if_flags |= IFF_UP; 507205024Sqingli if_link_state_change(ifp, LINK_STATE_UP); 508213028Sjhb mtx_unlock(&tp->tap_mtx); 50963670Snsayer 510183397Sed TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, dev2unit(dev)); 511133460Semax 51263670Snsayer return (0); 51363670Snsayer} /* tapopen */ 51463670Snsayer 51563670Snsayer 51663670Snsayer/* 51763670Snsayer * tapclose 51863670Snsayer * 51963670Snsayer * close the device - mark i/f down & delete routing info 52063670Snsayer */ 52163670Snsayerstatic int 522156783Semaxtapclose(struct cdev *dev, int foo, int bar, struct thread *td) 52363670Snsayer{ 524156783Semax struct ifaddr *ifa; 52563670Snsayer struct tap_softc *tp = dev->si_drv1; 526147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 52763670Snsayer 52863670Snsayer /* junk all pending output */ 529213028Sjhb mtx_lock(&tp->tap_mtx); 530236724Strociny CURVNET_SET(ifp->if_vnet); 53183043Sbrooks IF_DRAIN(&ifp->if_snd); 53263670Snsayer 53363803Snsayer /* 53463803Snsayer * do not bring the interface down, and do not anything with 53563803Snsayer * interface, if we are in VMnet mode. just close the device. 53663803Snsayer */ 53763803Snsayer 53863803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 539127098Srwatson mtx_unlock(&tp->tap_mtx); 54063670Snsayer if_down(ifp); 541213028Sjhb mtx_lock(&tp->tap_mtx); 542148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 543213028Sjhb ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 544213028Sjhb mtx_unlock(&tp->tap_mtx); 54563803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 546146620Speadar rtinit(ifa, (int)RTM_DELETE, 0); 54763670Snsayer } 548146620Speadar if_purgeaddrs(ifp); 549213028Sjhb mtx_lock(&tp->tap_mtx); 55063670Snsayer } 551213028Sjhb } 55263670Snsayer 553205024Sqingli if_link_state_change(ifp, LINK_STATE_DOWN); 554236724Strociny CURVNET_RESTORE(); 555236724Strociny 55696122Salfred funsetown(&tp->tap_sigio); 557122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 558213028Sjhb KNOTE_LOCKED(&tp->tap_rsel.si_note, 0); 55963670Snsayer 56063670Snsayer tp->tap_flags &= ~TAP_OPEN; 56163670Snsayer tp->tap_pid = 0; 562127098Srwatson mtx_unlock(&tp->tap_mtx); 56363670Snsayer 564121816Sbrooks TAPDEBUG("%s is closed. minor = %#x\n", 565183397Sed ifp->if_xname, dev2unit(dev)); 56663670Snsayer 56763670Snsayer return (0); 56863670Snsayer} /* tapclose */ 56963670Snsayer 57063670Snsayer 57163670Snsayer/* 57263670Snsayer * tapifinit 57363670Snsayer * 57463670Snsayer * network interface initialization function 57563670Snsayer */ 57663670Snsayerstatic void 577156783Semaxtapifinit(void *xtp) 57863670Snsayer{ 57963670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 580147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 58163670Snsayer 582121816Sbrooks TAPDEBUG("initializing %s\n", ifp->if_xname); 58363670Snsayer 584213028Sjhb mtx_lock(&tp->tap_mtx); 585148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 586148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 587213028Sjhb mtx_unlock(&tp->tap_mtx); 58863670Snsayer 58963670Snsayer /* attempt to start output */ 59063670Snsayer tapifstart(ifp); 59163670Snsayer} /* tapifinit */ 59263670Snsayer 59363670Snsayer 59463670Snsayer/* 59563670Snsayer * tapifioctl 59663670Snsayer * 59763670Snsayer * Process an ioctl request on network interface 59863670Snsayer */ 599105228Sphkstatic int 600156783Semaxtapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 60163670Snsayer{ 602160376Sbrooks struct tap_softc *tp = ifp->if_softc; 603189866Sscf struct ifreq *ifr = (struct ifreq *)data; 60463670Snsayer struct ifstat *ifs = NULL; 605213028Sjhb int dummy; 60663670Snsayer 60763670Snsayer switch (cmd) { 60863670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 60963670Snsayer case SIOCADDMULTI: 61063670Snsayer case SIOCDELMULTI: 61183043Sbrooks break; 61263670Snsayer 613189866Sscf case SIOCSIFMTU: 614189866Sscf ifp->if_mtu = ifr->ifr_mtu; 615189866Sscf break; 616189866Sscf 61763670Snsayer case SIOCGIFSTATUS: 61863670Snsayer ifs = (struct ifstat *)data; 61963670Snsayer dummy = strlen(ifs->ascii); 620127098Srwatson mtx_lock(&tp->tap_mtx); 62163670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 62263670Snsayer snprintf(ifs->ascii + dummy, 62363670Snsayer sizeof(ifs->ascii) - dummy, 62463670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 625127098Srwatson mtx_unlock(&tp->tap_mtx); 62683043Sbrooks break; 62763670Snsayer 62863670Snsayer default: 629213028Sjhb return (ether_ioctl(ifp, cmd, data)); 630156783Semax /* NOT REACHED */ 63163670Snsayer } 63263670Snsayer 63363670Snsayer return (0); 63463670Snsayer} /* tapifioctl */ 63563670Snsayer 63663670Snsayer 63763670Snsayer/* 638111742Sdes * tapifstart 639111742Sdes * 64063670Snsayer * queue packets from higher level ready to put out 64163670Snsayer */ 64263670Snsayerstatic void 643156783Semaxtapifstart(struct ifnet *ifp) 64463670Snsayer{ 64563670Snsayer struct tap_softc *tp = ifp->if_softc; 64663670Snsayer 647121816Sbrooks TAPDEBUG("%s starting\n", ifp->if_xname); 64863670Snsayer 64963803Snsayer /* 65063803Snsayer * do not junk pending output if we are in VMnet mode. 65163803Snsayer * XXX: can this do any harm because of queue overflow? 65263803Snsayer */ 65363803Snsayer 654127098Srwatson mtx_lock(&tp->tap_mtx); 655111742Sdes if (((tp->tap_flags & TAP_VMNET) == 0) && 65663803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 657213028Sjhb struct mbuf *m; 65863670Snsayer 659127098Srwatson /* Unlocked read. */ 660121816Sbrooks TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 661121816Sbrooks tp->tap_flags); 66263670Snsayer 663213028Sjhb for (;;) { 66463670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 665213028Sjhb if (m != NULL) { 66663670Snsayer m_freem(m); 667213028Sjhb ifp->if_oerrors++; 668213028Sjhb } else 669213028Sjhb break; 670213028Sjhb } 671213028Sjhb mtx_unlock(&tp->tap_mtx); 67263670Snsayer 67363670Snsayer return; 67463670Snsayer } 67563670Snsayer 676148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 67763670Snsayer 678213028Sjhb if (!IFQ_IS_EMPTY(&ifp->if_snd)) { 67963670Snsayer if (tp->tap_flags & TAP_RWAIT) { 68063670Snsayer tp->tap_flags &= ~TAP_RWAIT; 681111748Sdes wakeup(tp); 68263670Snsayer } 68363670Snsayer 684127098Srwatson if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) { 685127098Srwatson mtx_unlock(&tp->tap_mtx); 68695883Salfred pgsigio(&tp->tap_sigio, SIGIO, 0); 687213028Sjhb mtx_lock(&tp->tap_mtx); 688213028Sjhb } 68963670Snsayer 690122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 691213028Sjhb KNOTE_LOCKED(&tp->tap_rsel.si_note, 0); 69263670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 69363670Snsayer } 69463670Snsayer 695148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 696213028Sjhb mtx_unlock(&tp->tap_mtx); 69763670Snsayer} /* tapifstart */ 69863670Snsayer 69963670Snsayer 70063670Snsayer/* 70163670Snsayer * tapioctl 70263670Snsayer * 70363670Snsayer * the cdevsw interface is now pretty minimal 70463670Snsayer */ 70563670Snsayerstatic int 706156783Semaxtapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 70763670Snsayer{ 70863670Snsayer struct tap_softc *tp = dev->si_drv1; 709147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 710111742Sdes struct tapinfo *tapp = NULL; 711102052Ssobomax int f; 712162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 713162711Sru defined(COMPAT_FREEBSD4) 714162711Sru int ival; 715162711Sru#endif 71663670Snsayer 71763670Snsayer switch (cmd) { 718111742Sdes case TAPSIFINFO: 719111742Sdes tapp = (struct tapinfo *)data; 720213028Sjhb mtx_lock(&tp->tap_mtx); 721111742Sdes ifp->if_mtu = tapp->mtu; 722111742Sdes ifp->if_type = tapp->type; 723111742Sdes ifp->if_baudrate = tapp->baudrate; 724213028Sjhb mtx_unlock(&tp->tap_mtx); 725111742Sdes break; 72663670Snsayer 727111742Sdes case TAPGIFINFO: 728111742Sdes tapp = (struct tapinfo *)data; 729213028Sjhb mtx_lock(&tp->tap_mtx); 730111742Sdes tapp->mtu = ifp->if_mtu; 731111742Sdes tapp->type = ifp->if_type; 732111742Sdes tapp->baudrate = ifp->if_baudrate; 733213028Sjhb mtx_unlock(&tp->tap_mtx); 734111742Sdes break; 73563670Snsayer 73663670Snsayer case TAPSDEBUG: 737159079Smarius tapdebug = *(int *)data; 73883043Sbrooks break; 73963670Snsayer 74063670Snsayer case TAPGDEBUG: 741159079Smarius *(int *)data = tapdebug; 74283043Sbrooks break; 74363670Snsayer 744182880Semax case TAPGIFNAME: { 745182880Semax struct ifreq *ifr = (struct ifreq *) data; 746182880Semax 747182880Semax strlcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ); 748182880Semax } break; 749182880Semax 75063670Snsayer case FIONBIO: 75183043Sbrooks break; 75263670Snsayer 75363670Snsayer case FIOASYNC: 754127098Srwatson mtx_lock(&tp->tap_mtx); 755159079Smarius if (*(int *)data) 75663670Snsayer tp->tap_flags |= TAP_ASYNC; 75763670Snsayer else 75863670Snsayer tp->tap_flags &= ~TAP_ASYNC; 759127098Srwatson mtx_unlock(&tp->tap_mtx); 76083043Sbrooks break; 76163670Snsayer 76263670Snsayer case FIONREAD: 763213028Sjhb if (!IFQ_IS_EMPTY(&ifp->if_snd)) { 764213028Sjhb struct mbuf *mb; 76563670Snsayer 766213028Sjhb IFQ_LOCK(&ifp->if_snd); 767213028Sjhb IFQ_POLL_NOLOCK(&ifp->if_snd, mb); 768213028Sjhb for (*(int *)data = 0; mb != NULL; 769213028Sjhb mb = mb->m_next) 770159079Smarius *(int *)data += mb->m_len; 771213028Sjhb IFQ_UNLOCK(&ifp->if_snd); 77283043Sbrooks } else 773159079Smarius *(int *)data = 0; 77483043Sbrooks break; 77563670Snsayer 77663670Snsayer case FIOSETOWN: 777159079Smarius return (fsetown(*(int *)data, &tp->tap_sigio)); 77863670Snsayer 77963670Snsayer case FIOGETOWN: 780159079Smarius *(int *)data = fgetown(&tp->tap_sigio); 78163670Snsayer return (0); 78263670Snsayer 78363670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 78463670Snsayer case TIOCSPGRP: 785159079Smarius return (fsetown(-(*(int *)data), &tp->tap_sigio)); 78663670Snsayer 78763670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 78863670Snsayer case TIOCGPGRP: 789159079Smarius *(int *)data = -fgetown(&tp->tap_sigio); 79063670Snsayer return (0); 79163670Snsayer 79263670Snsayer /* VMware/VMnet port ioctl's */ 79363670Snsayer 794162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 795162711Sru defined(COMPAT_FREEBSD4) 796162711Sru case _IO('V', 0): 797162711Sru ival = IOCPARM_IVAL(data); 798162711Sru data = (caddr_t)&ival; 799162711Sru /* FALLTHROUGH */ 800162711Sru#endif 80183043Sbrooks case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 802162711Sru f = *(int *)data; 80363670Snsayer f &= 0x0fff; 80463670Snsayer f &= ~IFF_CANTCHANGE; 80563670Snsayer f |= IFF_UP; 80663670Snsayer 807213028Sjhb mtx_lock(&tp->tap_mtx); 80863670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 809213028Sjhb mtx_unlock(&tp->tap_mtx); 81083043Sbrooks break; 81163670Snsayer 81263861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 81363670Snsayer case SIOCGIFADDR: 814127165Srwatson mtx_lock(&tp->tap_mtx); 81563861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 816127165Srwatson mtx_unlock(&tp->tap_mtx); 81783043Sbrooks break; 81863670Snsayer 81963861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 820127165Srwatson mtx_lock(&tp->tap_mtx); 82163861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 822127165Srwatson mtx_unlock(&tp->tap_mtx); 82383043Sbrooks break; 82463670Snsayer 82563670Snsayer default: 82663670Snsayer return (ENOTTY); 82763670Snsayer } 82863670Snsayer return (0); 82963670Snsayer} /* tapioctl */ 83063670Snsayer 83163670Snsayer 83263670Snsayer/* 83363670Snsayer * tapread 83463670Snsayer * 83563670Snsayer * the cdevsw read interface - reads a packet at a time, or at 83663670Snsayer * least as much of a packet as can be read 83763670Snsayer */ 83863670Snsayerstatic int 839156783Semaxtapread(struct cdev *dev, struct uio *uio, int flag) 84063670Snsayer{ 84163670Snsayer struct tap_softc *tp = dev->si_drv1; 842147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 84390227Sdillon struct mbuf *m = NULL; 844213028Sjhb int error = 0, len; 84563670Snsayer 846183397Sed TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, dev2unit(dev)); 84763670Snsayer 848127098Srwatson mtx_lock(&tp->tap_mtx); 84963670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 850127098Srwatson mtx_unlock(&tp->tap_mtx); 851127098Srwatson 852127098Srwatson /* Unlocked read. */ 853121816Sbrooks TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 854183397Sed ifp->if_xname, dev2unit(dev), tp->tap_flags); 85563803Snsayer 85663670Snsayer return (EHOSTDOWN); 85763670Snsayer } 85863670Snsayer 85963670Snsayer tp->tap_flags &= ~TAP_RWAIT; 86063670Snsayer 86163670Snsayer /* sleep until we get a packet */ 86263670Snsayer do { 86390227Sdillon IF_DEQUEUE(&ifp->if_snd, m); 86463670Snsayer 86590227Sdillon if (m == NULL) { 866213028Sjhb if (flag & O_NONBLOCK) { 867213028Sjhb mtx_unlock(&tp->tap_mtx); 86863670Snsayer return (EWOULDBLOCK); 869213028Sjhb } 870111742Sdes 87163670Snsayer tp->tap_flags |= TAP_RWAIT; 872213028Sjhb error = mtx_sleep(tp, &tp->tap_mtx, PCATCH | (PZERO + 1), 873213028Sjhb "taprd", 0); 874213028Sjhb if (error) { 875213028Sjhb mtx_unlock(&tp->tap_mtx); 87663670Snsayer return (error); 877213028Sjhb } 87863670Snsayer } 87990227Sdillon } while (m == NULL); 880213028Sjhb mtx_unlock(&tp->tap_mtx); 88163670Snsayer 88263670Snsayer /* feed packet to bpf */ 883106939Ssam BPF_MTAP(ifp, m); 88463670Snsayer 88563670Snsayer /* xfer packet to user space */ 88690227Sdillon while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 88790227Sdillon len = min(uio->uio_resid, m->m_len); 88863670Snsayer if (len == 0) 88963670Snsayer break; 89063670Snsayer 891111741Sdes error = uiomove(mtod(m, void *), len, uio); 89290227Sdillon m = m_free(m); 89363670Snsayer } 89463670Snsayer 89590227Sdillon if (m != NULL) { 896121816Sbrooks TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 897183397Sed dev2unit(dev)); 89890227Sdillon m_freem(m); 89963670Snsayer } 90063670Snsayer 90163670Snsayer return (error); 90263670Snsayer} /* tapread */ 90363670Snsayer 90463670Snsayer 90563670Snsayer/* 90663670Snsayer * tapwrite 90763670Snsayer * 90863670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 90963670Snsayer */ 91063670Snsayerstatic int 911156783Semaxtapwrite(struct cdev *dev, struct uio *uio, int flag) 91263670Snsayer{ 913166443Sbms struct ether_header *eh; 91463670Snsayer struct tap_softc *tp = dev->si_drv1; 915147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 916137101Sglebius struct mbuf *m; 91763670Snsayer 918121816Sbrooks TAPDEBUG("%s writting, minor = %#x\n", 919183397Sed ifp->if_xname, dev2unit(dev)); 92063670Snsayer 92163670Snsayer if (uio->uio_resid == 0) 92263670Snsayer return (0); 92363670Snsayer 92463670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 925194990Skib TAPDEBUG("%s invalid packet len = %zd, minor = %#x\n", 926183397Sed ifp->if_xname, uio->uio_resid, dev2unit(dev)); 92763803Snsayer 92863670Snsayer return (EIO); 92963670Snsayer } 93063670Snsayer 931163915Sandre if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, ETHER_ALIGN, 932163915Sandre M_PKTHDR)) == NULL) { 93363670Snsayer ifp->if_ierrors ++; 934163986Scsjp return (ENOBUFS); 93563670Snsayer } 93663670Snsayer 937137101Sglebius m->m_pkthdr.rcvif = ifp; 938111742Sdes 939166443Sbms /* 940166443Sbms * Only pass a unicast frame to ether_input(), if it would actually 941166443Sbms * have been received by non-virtual hardware. 942166443Sbms */ 943166443Sbms if (m->m_len < sizeof(struct ether_header)) { 944166443Sbms m_freem(m); 945166443Sbms return (0); 946166443Sbms } 947166443Sbms eh = mtod(m, struct ether_header *); 948166443Sbms 949166443Sbms if (eh && (ifp->if_flags & IFF_PROMISC) == 0 && 950166443Sbms !ETHER_IS_MULTICAST(eh->ether_dhost) && 951166443Sbms bcmp(eh->ether_dhost, IF_LLADDR(ifp), ETHER_ADDR_LEN) != 0) { 952166443Sbms m_freem(m); 953166443Sbms return (0); 954166443Sbms } 955166443Sbms 956106939Ssam /* Pass packet up to parent. */ 957236724Strociny CURVNET_SET(ifp->if_vnet); 958137101Sglebius (*ifp->if_input)(ifp, m); 959236724Strociny CURVNET_RESTORE(); 960106939Ssam ifp->if_ipackets ++; /* ibytes are counted in parent */ 96163670Snsayer 96263670Snsayer return (0); 96363670Snsayer} /* tapwrite */ 96463670Snsayer 96563670Snsayer 96663670Snsayer/* 96763670Snsayer * tappoll 96863670Snsayer * 96963670Snsayer * the poll interface, this is only useful on reads 97063670Snsayer * really. the write detect always returns true, write never blocks 97163670Snsayer * anyway, it either accepts the packet or drops it 97263670Snsayer */ 97363670Snsayerstatic int 974156783Semaxtappoll(struct cdev *dev, int events, struct thread *td) 97563670Snsayer{ 97663670Snsayer struct tap_softc *tp = dev->si_drv1; 977147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 978213028Sjhb int revents = 0; 97963670Snsayer 980121816Sbrooks TAPDEBUG("%s polling, minor = %#x\n", 981183397Sed ifp->if_xname, dev2unit(dev)); 98263670Snsayer 98363670Snsayer if (events & (POLLIN | POLLRDNORM)) { 984213028Sjhb IFQ_LOCK(&ifp->if_snd); 985213028Sjhb if (!IFQ_IS_EMPTY(&ifp->if_snd)) { 986121816Sbrooks TAPDEBUG("%s have data in queue. len = %d, " \ 987121816Sbrooks "minor = %#x\n", ifp->if_xname, 988183397Sed ifp->if_snd.ifq_len, dev2unit(dev)); 98963803Snsayer 99063670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 99183043Sbrooks } else { 992121816Sbrooks TAPDEBUG("%s waiting for data, minor = %#x\n", 993183397Sed ifp->if_xname, dev2unit(dev)); 99463803Snsayer 99583805Sjhb selrecord(td, &tp->tap_rsel); 99663670Snsayer } 997213028Sjhb IFQ_UNLOCK(&ifp->if_snd); 99863670Snsayer } 99963670Snsayer 100063670Snsayer if (events & (POLLOUT | POLLWRNORM)) 100163670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 100263670Snsayer 100363670Snsayer return (revents); 100463670Snsayer} /* tappoll */ 1005156783Semax 1006156783Semax 1007156783Semax/* 1008156783Semax * tap_kqfilter 1009156783Semax * 1010156783Semax * support for kevent() system call 1011156783Semax */ 1012156783Semaxstatic int 1013156783Semaxtapkqfilter(struct cdev *dev, struct knote *kn) 1014156783Semax{ 1015156783Semax struct tap_softc *tp = dev->si_drv1; 1016156783Semax struct ifnet *ifp = tp->tap_ifp; 1017156783Semax 1018156783Semax switch (kn->kn_filter) { 1019156783Semax case EVFILT_READ: 1020156783Semax TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n", 1021183397Sed ifp->if_xname, dev2unit(dev)); 1022156783Semax kn->kn_fop = &tap_read_filterops; 1023156783Semax break; 1024156783Semax 1025156783Semax case EVFILT_WRITE: 1026156783Semax TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n", 1027183397Sed ifp->if_xname, dev2unit(dev)); 1028156783Semax kn->kn_fop = &tap_write_filterops; 1029156783Semax break; 1030156783Semax 1031156783Semax default: 1032156783Semax TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n", 1033183397Sed ifp->if_xname, dev2unit(dev)); 1034156783Semax return (EINVAL); 1035156783Semax /* NOT REACHED */ 1036156783Semax } 1037156783Semax 1038213028Sjhb kn->kn_hook = tp; 1039156783Semax knlist_add(&tp->tap_rsel.si_note, kn, 0); 1040156783Semax 1041156783Semax return (0); 1042156783Semax} /* tapkqfilter */ 1043156783Semax 1044156783Semax 1045156783Semax/* 1046156783Semax * tap_kqread 1047156783Semax * 1048156783Semax * Return true if there is data in the interface queue 1049156783Semax */ 1050156783Semaxstatic int 1051156783Semaxtapkqread(struct knote *kn, long hint) 1052156783Semax{ 1053213028Sjhb int ret; 1054213028Sjhb struct tap_softc *tp = kn->kn_hook; 1055213028Sjhb struct cdev *dev = tp->tap_dev; 1056156783Semax struct ifnet *ifp = tp->tap_ifp; 1057156783Semax 1058156783Semax if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) { 1059156783Semax TAPDEBUG("%s have data in queue. len = %d, minor = %#x\n", 1060183397Sed ifp->if_xname, ifp->if_snd.ifq_len, dev2unit(dev)); 1061156783Semax ret = 1; 1062156783Semax } else { 1063156783Semax TAPDEBUG("%s waiting for data, minor = %#x\n", 1064183397Sed ifp->if_xname, dev2unit(dev)); 1065156783Semax ret = 0; 1066156783Semax } 1067156783Semax 1068156783Semax return (ret); 1069156783Semax} /* tapkqread */ 1070156783Semax 1071156783Semax 1072156783Semax/* 1073156783Semax * tap_kqwrite 1074156783Semax * 1075156783Semax * Always can write. Return the MTU in kn->data 1076156783Semax */ 1077156783Semaxstatic int 1078156783Semaxtapkqwrite(struct knote *kn, long hint) 1079156783Semax{ 1080213028Sjhb struct tap_softc *tp = kn->kn_hook; 1081156783Semax struct ifnet *ifp = tp->tap_ifp; 1082156783Semax 1083156783Semax kn->kn_data = ifp->if_mtu; 1084156783Semax 1085156783Semax return (1); 1086156783Semax} /* tapkqwrite */ 1087156783Semax 1088156783Semax 1089156783Semaxstatic void 1090156783Semaxtapkqdetach(struct knote *kn) 1091156783Semax{ 1092213028Sjhb struct tap_softc *tp = kn->kn_hook; 1093156783Semax 1094156783Semax knlist_remove(&tp->tap_rsel.si_note, kn, 0); 1095156783Semax} /* tapkqdetach */ 1096156783Semax 1097