if_tap.c revision 166497
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 166497 2007-02-04 16:32:46Z bms $ 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, 135126188Sbde .d_flags = D_PSEUDO | D_NEEDGIANT, 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 */ 153144979Smdoddstatic int tapuopen = 0; /* allow user open() */ 154166497Sbmsstatic int tapdclone = 1; /* enable devfs cloning */ 15583043Sbrooksstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 156126077Sphkstatic struct clonedevs *tapclones; 15763670Snsayer 15863670SnsayerMALLOC_DECLARE(M_TAP); 15963670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 16063670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 161144979Smdodd 162144979SmdoddSYSCTL_DECL(_net_link); 163144979SmdoddSYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0, 164144979Smdodd "Ethernet tunnel software network interface"); 165144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0, 166144979Smdodd "Allow user to open /dev/tap (based on node permissions)"); 167166497SbmsSYSCTL_INT(_net_link_tap, OID_AUTO, devfs_cloning, CTLFLAG_RW, &tapdclone, 0, 168166497Sbms "Enably legacy devfs interface creation"); 169144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, ""); 170144979Smdodd 171166497SbmsTUNABLE_INT("net.link.tap.devfs_cloning", &tapdclone); 172166497Sbms 17363670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL); 17463670Snsayer 175166497Sbmsstatic int 176166497Sbmstap_clone_create(struct if_clone *ifc, int unit, caddr_t params) 177166497Sbms{ 178166497Sbms struct cdev *dev; 179166497Sbms int i; 180166497Sbms int extra; 181166497Sbms 182166497Sbms if (strcmp(ifc->ifc_name, VMNET) == 0) 183166497Sbms extra = VMNET_DEV_MASK; 184166497Sbms else 185166497Sbms extra = 0; 186166497Sbms 187166497Sbms /* find any existing device, or allocate new unit number */ 188166497Sbms i = clone_create(&tapclones, &tap_cdevsw, &unit, &dev, extra); 189166497Sbms if (i) { 190166497Sbms dev = make_dev(&tap_cdevsw, unit2minor(unit | extra), 191166497Sbms UID_ROOT, GID_WHEEL, 0600, "%s%d", ifc->ifc_name, unit); 192166497Sbms if (dev != NULL) { 193166497Sbms dev_ref(dev); 194166497Sbms dev->si_flags |= SI_CHEAPCLONE; 195166497Sbms } 196166497Sbms } 197166497Sbms 198166497Sbms tapcreate(dev); 199166497Sbms return (0); 200166497Sbms} 201166497Sbms 202166497Sbms/* vmnet devices are tap devices in disguise */ 203166497Sbmsstatic int 204166497Sbmsvmnet_clone_create(struct if_clone *ifc, int unit, caddr_t params) 205166497Sbms{ 206166497Sbms return tap_clone_create(ifc, unit, params); 207166497Sbms} 208166497Sbms 209166497Sbmsstatic void 210166497Sbmstap_destroy(struct tap_softc *tp) 211166497Sbms{ 212166497Sbms struct ifnet *ifp = tp->tap_ifp; 213166497Sbms int s; 214166497Sbms 215166497Sbms /* Unlocked read. */ 216166497Sbms KASSERT(!(tp->tap_flags & TAP_OPEN), 217166497Sbms ("%s flags is out of sync", ifp->if_xname)); 218166497Sbms 219166497Sbms knlist_destroy(&tp->tap_rsel.si_note); 220166497Sbms destroy_dev(tp->tap_dev); 221166497Sbms s = splimp(); 222166497Sbms ether_ifdetach(ifp); 223166497Sbms if_free_type(ifp, IFT_ETHER); 224166497Sbms splx(s); 225166497Sbms 226166497Sbms mtx_destroy(&tp->tap_mtx); 227166497Sbms free(tp, M_TAP); 228166497Sbms} 229166497Sbms 230166497Sbmsstatic void 231166497Sbmstap_clone_destroy(struct ifnet *ifp) 232166497Sbms{ 233166497Sbms struct tap_softc *tp = ifp->if_softc; 234166497Sbms 235166497Sbms mtx_lock(&tapmtx); 236166497Sbms SLIST_REMOVE(&taphead, tp, tap_softc, tap_next); 237166497Sbms mtx_unlock(&tapmtx); 238166497Sbms tap_destroy(tp); 239166497Sbms} 240166497Sbms 241166497Sbms/* vmnet devices are tap devices in disguise */ 242166497Sbmsstatic void 243166497Sbmsvmnet_clone_destroy(struct ifnet *ifp) 244166497Sbms{ 245166497Sbms tap_clone_destroy(ifp); 246166497Sbms} 247166497Sbms 24863670Snsayer/* 24963670Snsayer * tapmodevent 25063670Snsayer * 25163670Snsayer * module event handler 25263670Snsayer */ 25363670Snsayerstatic int 254156783Semaxtapmodevent(module_t mod, int type, void *data) 25563670Snsayer{ 25683043Sbrooks static eventhandler_tag eh_tag = NULL; 25783043Sbrooks struct tap_softc *tp = NULL; 25883043Sbrooks struct ifnet *ifp = NULL; 25963670Snsayer 26063670Snsayer switch (type) { 26163670Snsayer case MOD_LOAD: 26263670Snsayer 26383043Sbrooks /* intitialize device */ 26483043Sbrooks 265127003Srwatson mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF); 26683043Sbrooks SLIST_INIT(&taphead); 26783043Sbrooks 268126845Sphk clone_setup(&tapclones); 26971602Sphk eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 270127003Srwatson if (eh_tag == NULL) { 271127170Srwatson clone_cleanup(&tapclones); 272127003Srwatson mtx_destroy(&tapmtx); 273126077Sphk return (ENOMEM); 274127003Srwatson } 275166497Sbms if_clone_attach(&tap_cloner); 276166497Sbms if_clone_attach(&vmnet_cloner); 27783043Sbrooks return (0); 27863670Snsayer 27983043Sbrooks case MOD_UNLOAD: 280127003Srwatson /* 281127003Srwatson * The EBUSY algorithm here can't quite atomically 282127003Srwatson * guarantee that this is race-free since we have to 283127003Srwatson * release the tap mtx to deregister the clone handler. 284127003Srwatson */ 285127003Srwatson mtx_lock(&tapmtx); 286127003Srwatson SLIST_FOREACH(tp, &taphead, tap_next) { 287127098Srwatson mtx_lock(&tp->tap_mtx); 288127003Srwatson if (tp->tap_flags & TAP_OPEN) { 289127098Srwatson mtx_unlock(&tp->tap_mtx); 290127003Srwatson mtx_unlock(&tapmtx); 29183043Sbrooks return (EBUSY); 292127003Srwatson } 293127098Srwatson mtx_unlock(&tp->tap_mtx); 294127003Srwatson } 295127003Srwatson mtx_unlock(&tapmtx); 29683043Sbrooks 29771602Sphk EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 298166497Sbms if_clone_detach(&tap_cloner); 299166497Sbms if_clone_detach(&vmnet_cloner); 30063670Snsayer 301127003Srwatson mtx_lock(&tapmtx); 30283043Sbrooks while ((tp = SLIST_FIRST(&taphead)) != NULL) { 30383043Sbrooks SLIST_REMOVE_HEAD(&taphead, tap_next); 304127003Srwatson mtx_unlock(&tapmtx); 30583043Sbrooks 306147256Sbrooks ifp = tp->tap_ifp; 30783043Sbrooks 308121816Sbrooks TAPDEBUG("detaching %s\n", ifp->if_xname); 30983043Sbrooks 310166497Sbms tap_destroy(tp); 311127003Srwatson mtx_lock(&tapmtx); 31283043Sbrooks } 313127003Srwatson mtx_unlock(&tapmtx); 314126077Sphk clone_cleanup(&tapclones); 31563670Snsayer 316135354Srwatson mtx_destroy(&tapmtx); 317135354Srwatson 31883043Sbrooks break; 31963670Snsayer 32063670Snsayer default: 32163670Snsayer return (EOPNOTSUPP); 32263670Snsayer } 32363670Snsayer 32463670Snsayer return (0); 32563670Snsayer} /* tapmodevent */ 32663670Snsayer 32763670Snsayer 32863670Snsayer/* 32971602Sphk * DEVFS handler 33071602Sphk * 33171602Sphk * We need to support two kind of devices - tap and vmnet 33271602Sphk */ 33371602Sphkstatic void 334156783Semaxtapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev) 33571602Sphk{ 336166497Sbms char devname[SPECNAMELEN + 1]; 337166497Sbms int i, unit, append_unit; 338166438Sbms int extra; 33971602Sphk 340130640Sphk if (*dev != NULL) 34171602Sphk return; 34271602Sphk 343166497Sbms /* 344166497Sbms * If tap cloning is enabled, only the superuser can create 345166497Sbms * an interface. 346166497Sbms */ 347166497Sbms if (!tapdclone || priv_check_cred(cred, PRIV_NET_IFCREATE, 0) != 0) 348166497Sbms return; 349166497Sbms 350166497Sbms unit = 0; 351166497Sbms append_unit = 0; 352126077Sphk extra = 0; 353166497Sbms 354166497Sbms /* We're interested in only tap/vmnet devices. */ 355126077Sphk if (strcmp(name, TAP) == 0) { 356126077Sphk unit = -1; 357126077Sphk } else if (strcmp(name, VMNET) == 0) { 358126077Sphk unit = -1; 359126077Sphk extra = VMNET_DEV_MASK; 360166497Sbms } else if (dev_stdclone(name, NULL, TAP, &unit) != 1) { 361166497Sbms if (dev_stdclone(name, NULL, VMNET, &unit) != 1) { 362126077Sphk return; 363166497Sbms } else { 364166497Sbms extra = VMNET_DEV_MASK; 365166497Sbms } 36683043Sbrooks } 36771602Sphk 368166497Sbms if (unit == -1) 369166497Sbms append_unit = 1; 370166497Sbms 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 384126796Sphk *dev = make_dev(&tap_cdevsw, unit2minor(unit | extra), 385166497Sbms UID_ROOT, GID_WHEEL, 0600, "%s", name); 386144389Sphk if (*dev != NULL) { 387144389Sphk dev_ref(*dev); 388126077Sphk (*dev)->si_flags |= SI_CHEAPCLONE; 389144389Sphk } 39071602Sphk } 391166497Sbms 392166497Sbms if_clone_create(name, namelen, NULL); 39371602Sphk} /* tapclone */ 39471602Sphk 39571602Sphk 39671602Sphk/* 39763670Snsayer * tapcreate 39863670Snsayer * 39963670Snsayer * to create interface 40063670Snsayer */ 40163670Snsayerstatic void 402156783Semaxtapcreate(struct cdev *dev) 40363670Snsayer{ 40463670Snsayer struct ifnet *ifp = NULL; 40563670Snsayer struct tap_softc *tp = NULL; 40663670Snsayer unsigned short macaddr_hi; 40763803Snsayer int unit, s; 40863670Snsayer char *name = NULL; 409147256Sbrooks u_char eaddr[6]; 41063670Snsayer 411126077Sphk dev->si_flags &= ~SI_CHEAPCLONE; 412126077Sphk 41363670Snsayer /* allocate driver storage and create device */ 414111119Simp MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 415127098Srwatson mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF); 416127003Srwatson mtx_lock(&tapmtx); 41783043Sbrooks SLIST_INSERT_HEAD(&taphead, tp, tap_next); 418127003Srwatson mtx_unlock(&tapmtx); 41963670Snsayer 420126796Sphk unit = dev2unit(dev); 42183043Sbrooks 42263670Snsayer /* select device: tap or vmnet */ 423126796Sphk if (unit & VMNET_DEV_MASK) { 42463670Snsayer name = VMNET; 42563803Snsayer tp->tap_flags |= TAP_VMNET; 42683043Sbrooks } else 42763670Snsayer name = TAP; 42863670Snsayer 429126796Sphk unit &= TAPMAXUNIT; 430126796Sphk 43183043Sbrooks TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 43283043Sbrooks 43363670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 43463670Snsayer macaddr_hi = htons(0x00bd); 435147256Sbrooks bcopy(&macaddr_hi, eaddr, sizeof(short)); 436147256Sbrooks bcopy(&ticks, &eaddr[2], sizeof(long)); 437147256Sbrooks eaddr[5] = (u_char)unit; 43863670Snsayer 439111742Sdes /* fill the rest and attach interface */ 440147256Sbrooks ifp = tp->tap_ifp = if_alloc(IFT_ETHER); 441147256Sbrooks if (ifp == NULL) 442147256Sbrooks panic("%s%d: can not if_alloc()", name, unit); 44363670Snsayer ifp->if_softc = tp; 444121816Sbrooks if_initname(ifp, name, unit); 44563670Snsayer ifp->if_init = tapifinit; 44663670Snsayer ifp->if_start = tapifstart; 44763670Snsayer ifp->if_ioctl = tapifioctl; 44863670Snsayer ifp->if_mtu = ETHERMTU; 44963670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 45063670Snsayer ifp->if_snd.ifq_maxlen = ifqmaxlen; 45163670Snsayer 45283043Sbrooks dev->si_drv1 = tp; 453126077Sphk tp->tap_dev = dev; 45483043Sbrooks 45563803Snsayer s = splimp(); 456147256Sbrooks ether_ifattach(ifp, eaddr); 45763803Snsayer splx(s); 45863670Snsayer 459127098Srwatson mtx_lock(&tp->tap_mtx); 46063803Snsayer tp->tap_flags |= TAP_INITED; 461127098Srwatson mtx_unlock(&tp->tap_mtx); 46263803Snsayer 463158697Semax knlist_init(&tp->tap_rsel.si_note, NULL, NULL, NULL, NULL); 464158697Semax 465121816Sbrooks TAPDEBUG("interface %s is created. minor = %#x\n", 466121816Sbrooks ifp->if_xname, minor(dev)); 46763670Snsayer} /* tapcreate */ 46863670Snsayer 46963670Snsayer 47063670Snsayer/* 471111742Sdes * tapopen 47263670Snsayer * 47363670Snsayer * to open tunnel. must be superuser 47463670Snsayer */ 47563670Snsayerstatic int 476156783Semaxtapopen(struct cdev *dev, int flag, int mode, struct thread *td) 47763670Snsayer{ 47863670Snsayer struct tap_softc *tp = NULL; 479133460Semax struct ifnet *ifp = NULL; 480164033Srwatson int error, s; 48163670Snsayer 482164033Srwatson if (tapuopen == 0) { 483164033Srwatson error = priv_check(td, PRIV_NET_TAP); 484164033Srwatson if (error) 485164033Srwatson return (error); 486164033Srwatson } 48763670Snsayer 488126796Sphk if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT) 489126796Sphk return (ENXIO); 49083043Sbrooks 49163670Snsayer tp = dev->si_drv1; 49263670Snsayer 493127165Srwatson mtx_lock(&tp->tap_mtx); 494127165Srwatson if (tp->tap_flags & TAP_OPEN) { 495127165Srwatson mtx_unlock(&tp->tap_mtx); 496127165Srwatson return (EBUSY); 497127165Srwatson } 49863670Snsayer 499152315Sru bcopy(IF_LLADDR(tp->tap_ifp), tp->ether_addr, sizeof(tp->ether_addr)); 50083366Sjulian tp->tap_pid = td->td_proc->p_pid; 50163670Snsayer tp->tap_flags |= TAP_OPEN; 502147256Sbrooks ifp = tp->tap_ifp; 503127098Srwatson mtx_unlock(&tp->tap_mtx); 50463670Snsayer 505133460Semax s = splimp(); 506148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 507148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 508133460Semax splx(s); 50963670Snsayer 510133460Semax TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(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; 527126077Sphk int s; 52863670Snsayer 52963670Snsayer /* junk all pending output */ 53083043Sbrooks IF_DRAIN(&ifp->if_snd); 53163670Snsayer 53263803Snsayer /* 53363803Snsayer * do not bring the interface down, and do not anything with 53463803Snsayer * interface, if we are in VMnet mode. just close the device. 53563803Snsayer */ 53663803Snsayer 537127098Srwatson mtx_lock(&tp->tap_mtx); 53863803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 539127098Srwatson mtx_unlock(&tp->tap_mtx); 54063670Snsayer s = splimp(); 54163670Snsayer if_down(ifp); 542148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 54363803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 544146620Speadar rtinit(ifa, (int)RTM_DELETE, 0); 54563670Snsayer } 546146620Speadar if_purgeaddrs(ifp); 547148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 54863670Snsayer } 54963670Snsayer splx(s); 550127098Srwatson } else 551127098Srwatson mtx_unlock(&tp->tap_mtx); 55263670Snsayer 55396122Salfred funsetown(&tp->tap_sigio); 554122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 555156783Semax KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0); 55663670Snsayer 557127098Srwatson mtx_lock(&tp->tap_mtx); 55863670Snsayer tp->tap_flags &= ~TAP_OPEN; 55963670Snsayer tp->tap_pid = 0; 560127098Srwatson mtx_unlock(&tp->tap_mtx); 56163670Snsayer 562121816Sbrooks TAPDEBUG("%s is closed. minor = %#x\n", 563121816Sbrooks ifp->if_xname, minor(dev)); 56463670Snsayer 56563670Snsayer return (0); 56663670Snsayer} /* tapclose */ 56763670Snsayer 56863670Snsayer 56963670Snsayer/* 57063670Snsayer * tapifinit 57163670Snsayer * 57263670Snsayer * network interface initialization function 57363670Snsayer */ 57463670Snsayerstatic void 575156783Semaxtapifinit(void *xtp) 57663670Snsayer{ 57763670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 578147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 57963670Snsayer 580121816Sbrooks TAPDEBUG("initializing %s\n", ifp->if_xname); 58163670Snsayer 582148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 583148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 58463670Snsayer 58563670Snsayer /* attempt to start output */ 58663670Snsayer tapifstart(ifp); 58763670Snsayer} /* tapifinit */ 58863670Snsayer 58963670Snsayer 59063670Snsayer/* 59163670Snsayer * tapifioctl 59263670Snsayer * 59363670Snsayer * Process an ioctl request on network interface 59463670Snsayer */ 595105228Sphkstatic int 596156783Semaxtapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 59763670Snsayer{ 598160376Sbrooks struct tap_softc *tp = ifp->if_softc; 59963670Snsayer struct ifstat *ifs = NULL; 60063670Snsayer int s, dummy; 60163670Snsayer 60263670Snsayer switch (cmd) { 60363670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 60463670Snsayer case SIOCADDMULTI: 60563670Snsayer case SIOCDELMULTI: 60683043Sbrooks break; 60763670Snsayer 60863670Snsayer case SIOCGIFSTATUS: 60963670Snsayer s = splimp(); 61063670Snsayer ifs = (struct ifstat *)data; 61163670Snsayer dummy = strlen(ifs->ascii); 612127098Srwatson mtx_lock(&tp->tap_mtx); 61363670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 61463670Snsayer snprintf(ifs->ascii + dummy, 61563670Snsayer sizeof(ifs->ascii) - dummy, 61663670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 617127098Srwatson mtx_unlock(&tp->tap_mtx); 61863670Snsayer splx(s); 61983043Sbrooks break; 62063670Snsayer 62163670Snsayer default: 622106939Ssam s = splimp(); 623106939Ssam dummy = ether_ioctl(ifp, cmd, data); 624106939Ssam splx(s); 625106939Ssam return (dummy); 626156783Semax /* NOT REACHED */ 62763670Snsayer } 62863670Snsayer 62963670Snsayer return (0); 63063670Snsayer} /* tapifioctl */ 63163670Snsayer 63263670Snsayer 63363670Snsayer/* 634111742Sdes * tapifstart 635111742Sdes * 63663670Snsayer * queue packets from higher level ready to put out 63763670Snsayer */ 63863670Snsayerstatic void 639156783Semaxtapifstart(struct ifnet *ifp) 64063670Snsayer{ 64163670Snsayer struct tap_softc *tp = ifp->if_softc; 64263670Snsayer int s; 64363670Snsayer 644121816Sbrooks TAPDEBUG("%s starting\n", ifp->if_xname); 64563670Snsayer 64663803Snsayer /* 64763803Snsayer * do not junk pending output if we are in VMnet mode. 64863803Snsayer * XXX: can this do any harm because of queue overflow? 64963803Snsayer */ 65063803Snsayer 651127098Srwatson mtx_lock(&tp->tap_mtx); 652111742Sdes if (((tp->tap_flags & TAP_VMNET) == 0) && 65363803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 65463670Snsayer struct mbuf *m = NULL; 65563670Snsayer 656127098Srwatson mtx_unlock(&tp->tap_mtx); 657127098Srwatson 658127098Srwatson /* Unlocked read. */ 659121816Sbrooks TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 660121816Sbrooks tp->tap_flags); 66163670Snsayer 66263670Snsayer s = splimp(); 66363670Snsayer do { 66463670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 66563670Snsayer if (m != NULL) 66663670Snsayer m_freem(m); 66763670Snsayer ifp->if_oerrors ++; 66863670Snsayer } while (m != NULL); 66963670Snsayer splx(s); 67063670Snsayer 67163670Snsayer return; 67263670Snsayer } 673127098Srwatson mtx_unlock(&tp->tap_mtx); 67463670Snsayer 67563670Snsayer s = splimp(); 676148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 67763670Snsayer 67863670Snsayer if (ifp->if_snd.ifq_len != 0) { 679127098Srwatson mtx_lock(&tp->tap_mtx); 68063670Snsayer if (tp->tap_flags & TAP_RWAIT) { 68163670Snsayer tp->tap_flags &= ~TAP_RWAIT; 682111748Sdes wakeup(tp); 68363670Snsayer } 68463670Snsayer 685127098Srwatson if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) { 686127098Srwatson mtx_unlock(&tp->tap_mtx); 68795883Salfred pgsigio(&tp->tap_sigio, SIGIO, 0); 688127098Srwatson } else 689127098Srwatson mtx_unlock(&tp->tap_mtx); 69063670Snsayer 691122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 692156783Semax KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0); 69363670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 69463670Snsayer } 69563670Snsayer 696148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 69763670Snsayer splx(s); 69863670Snsayer} /* tapifstart */ 69963670Snsayer 70063670Snsayer 70163670Snsayer/* 70263670Snsayer * tapioctl 70363670Snsayer * 70463670Snsayer * the cdevsw interface is now pretty minimal 70563670Snsayer */ 70663670Snsayerstatic int 707156783Semaxtapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 70863670Snsayer{ 70963670Snsayer struct tap_softc *tp = dev->si_drv1; 710147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 711111742Sdes struct tapinfo *tapp = NULL; 71263670Snsayer int s; 713102052Ssobomax int f; 714162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 715162711Sru defined(COMPAT_FREEBSD4) 716162711Sru int ival; 717162711Sru#endif 71863670Snsayer 71963670Snsayer switch (cmd) { 720111742Sdes case TAPSIFINFO: 72163670Snsayer s = splimp(); 722111742Sdes tapp = (struct tapinfo *)data; 723111742Sdes ifp->if_mtu = tapp->mtu; 724111742Sdes ifp->if_type = tapp->type; 725111742Sdes ifp->if_baudrate = tapp->baudrate; 72663670Snsayer splx(s); 727111742Sdes break; 72863670Snsayer 729111742Sdes case TAPGIFINFO: 730111742Sdes tapp = (struct tapinfo *)data; 731111742Sdes tapp->mtu = ifp->if_mtu; 732111742Sdes tapp->type = ifp->if_type; 733111742Sdes tapp->baudrate = ifp->if_baudrate; 734111742Sdes break; 73563670Snsayer 73663670Snsayer case TAPSDEBUG: 737159079Smarius tapdebug = *(int *)data; 73883043Sbrooks break; 73963670Snsayer 74063670Snsayer case TAPGDEBUG: 741159079Smarius *(int *)data = tapdebug; 74283043Sbrooks break; 74363670Snsayer 74463670Snsayer case FIONBIO: 74583043Sbrooks break; 74663670Snsayer 74763670Snsayer case FIOASYNC: 74863803Snsayer s = splimp(); 749127098Srwatson mtx_lock(&tp->tap_mtx); 750159079Smarius if (*(int *)data) 75163670Snsayer tp->tap_flags |= TAP_ASYNC; 75263670Snsayer else 75363670Snsayer tp->tap_flags &= ~TAP_ASYNC; 754127098Srwatson mtx_unlock(&tp->tap_mtx); 75563803Snsayer splx(s); 75683043Sbrooks break; 75763670Snsayer 75863670Snsayer case FIONREAD: 75963670Snsayer s = splimp(); 76063670Snsayer if (ifp->if_snd.ifq_head) { 76163670Snsayer struct mbuf *mb = ifp->if_snd.ifq_head; 76263670Snsayer 763159079Smarius for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 764159079Smarius *(int *)data += mb->m_len; 76583043Sbrooks } else 766159079Smarius *(int *)data = 0; 76763670Snsayer splx(s); 76883043Sbrooks break; 76963670Snsayer 77063670Snsayer case FIOSETOWN: 771159079Smarius return (fsetown(*(int *)data, &tp->tap_sigio)); 77263670Snsayer 77363670Snsayer case FIOGETOWN: 774159079Smarius *(int *)data = fgetown(&tp->tap_sigio); 77563670Snsayer return (0); 77663670Snsayer 77763670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 77863670Snsayer case TIOCSPGRP: 779159079Smarius return (fsetown(-(*(int *)data), &tp->tap_sigio)); 78063670Snsayer 78163670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 78263670Snsayer case TIOCGPGRP: 783159079Smarius *(int *)data = -fgetown(&tp->tap_sigio); 78463670Snsayer return (0); 78563670Snsayer 78663670Snsayer /* VMware/VMnet port ioctl's */ 78763670Snsayer 78863670Snsayer case SIOCGIFFLAGS: /* get ifnet flags */ 78963670Snsayer bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 79083043Sbrooks break; 79163670Snsayer 792162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 793162711Sru defined(COMPAT_FREEBSD4) 794162711Sru case _IO('V', 0): 795162711Sru ival = IOCPARM_IVAL(data); 796162711Sru data = (caddr_t)&ival; 797162711Sru /* FALLTHROUGH */ 798162711Sru#endif 79983043Sbrooks case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 800162711Sru f = *(int *)data; 80163670Snsayer f &= 0x0fff; 80263670Snsayer f &= ~IFF_CANTCHANGE; 80363670Snsayer f |= IFF_UP; 80463670Snsayer 80563670Snsayer s = splimp(); 80663670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 80763670Snsayer splx(s); 80883043Sbrooks break; 80963670Snsayer 81063861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 81163670Snsayer case SIOCGIFADDR: 812127165Srwatson mtx_lock(&tp->tap_mtx); 81363861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 814127165Srwatson mtx_unlock(&tp->tap_mtx); 81583043Sbrooks break; 81663670Snsayer 81763861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 818127165Srwatson mtx_lock(&tp->tap_mtx); 81963861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 820127165Srwatson mtx_unlock(&tp->tap_mtx); 82183043Sbrooks break; 82263670Snsayer 82363670Snsayer default: 82463670Snsayer return (ENOTTY); 82563670Snsayer } 82663670Snsayer return (0); 82763670Snsayer} /* tapioctl */ 82863670Snsayer 82963670Snsayer 83063670Snsayer/* 83163670Snsayer * tapread 83263670Snsayer * 83363670Snsayer * the cdevsw read interface - reads a packet at a time, or at 83463670Snsayer * least as much of a packet as can be read 83563670Snsayer */ 83663670Snsayerstatic int 837156783Semaxtapread(struct cdev *dev, struct uio *uio, int flag) 83863670Snsayer{ 83963670Snsayer struct tap_softc *tp = dev->si_drv1; 840147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 84190227Sdillon struct mbuf *m = NULL; 84263670Snsayer int error = 0, len, s; 84363670Snsayer 844121816Sbrooks TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev)); 84563670Snsayer 846127098Srwatson mtx_lock(&tp->tap_mtx); 84763670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 848127098Srwatson mtx_unlock(&tp->tap_mtx); 849127098Srwatson 850127098Srwatson /* Unlocked read. */ 851121816Sbrooks TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 852121816Sbrooks ifp->if_xname, minor(dev), tp->tap_flags); 85363803Snsayer 85463670Snsayer return (EHOSTDOWN); 85563670Snsayer } 85663670Snsayer 85763670Snsayer tp->tap_flags &= ~TAP_RWAIT; 858127098Srwatson mtx_unlock(&tp->tap_mtx); 85963670Snsayer 86063670Snsayer /* sleep until we get a packet */ 86163670Snsayer do { 86263670Snsayer s = splimp(); 86390227Sdillon IF_DEQUEUE(&ifp->if_snd, m); 86463670Snsayer splx(s); 86563670Snsayer 86690227Sdillon if (m == NULL) { 867139207Sphk if (flag & O_NONBLOCK) 86863670Snsayer return (EWOULDBLOCK); 869111742Sdes 870127098Srwatson mtx_lock(&tp->tap_mtx); 87163670Snsayer tp->tap_flags |= TAP_RWAIT; 872127098Srwatson mtx_unlock(&tp->tap_mtx); 873111748Sdes error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); 87463670Snsayer if (error) 87563670Snsayer return (error); 87663670Snsayer } 87790227Sdillon } while (m == NULL); 87863670Snsayer 87963670Snsayer /* feed packet to bpf */ 880106939Ssam BPF_MTAP(ifp, m); 88163670Snsayer 88263670Snsayer /* xfer packet to user space */ 88390227Sdillon while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 88490227Sdillon len = min(uio->uio_resid, m->m_len); 88563670Snsayer if (len == 0) 88663670Snsayer break; 88763670Snsayer 888111741Sdes error = uiomove(mtod(m, void *), len, uio); 88990227Sdillon m = m_free(m); 89063670Snsayer } 89163670Snsayer 89290227Sdillon if (m != NULL) { 893121816Sbrooks TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 894121816Sbrooks minor(dev)); 89590227Sdillon m_freem(m); 89663670Snsayer } 89763670Snsayer 89863670Snsayer return (error); 89963670Snsayer} /* tapread */ 90063670Snsayer 90163670Snsayer 90263670Snsayer/* 90363670Snsayer * tapwrite 90463670Snsayer * 90563670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 90663670Snsayer */ 90763670Snsayerstatic int 908156783Semaxtapwrite(struct cdev *dev, struct uio *uio, int flag) 90963670Snsayer{ 910166443Sbms struct ether_header *eh; 91163670Snsayer struct tap_softc *tp = dev->si_drv1; 912147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 913137101Sglebius struct mbuf *m; 91463670Snsayer 915121816Sbrooks TAPDEBUG("%s writting, minor = %#x\n", 916121816Sbrooks ifp->if_xname, minor(dev)); 91763670Snsayer 91863670Snsayer if (uio->uio_resid == 0) 91963670Snsayer return (0); 92063670Snsayer 92163670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 922121816Sbrooks TAPDEBUG("%s invalid packet len = %d, minor = %#x\n", 923121816Sbrooks ifp->if_xname, uio->uio_resid, minor(dev)); 92463803Snsayer 92563670Snsayer return (EIO); 92663670Snsayer } 92763670Snsayer 928163915Sandre if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, ETHER_ALIGN, 929163915Sandre M_PKTHDR)) == NULL) { 93063670Snsayer ifp->if_ierrors ++; 931163986Scsjp return (ENOBUFS); 93263670Snsayer } 93363670Snsayer 934137101Sglebius m->m_pkthdr.rcvif = ifp; 935111742Sdes 936166443Sbms /* 937166443Sbms * Only pass a unicast frame to ether_input(), if it would actually 938166443Sbms * have been received by non-virtual hardware. 939166443Sbms */ 940166443Sbms if (m->m_len < sizeof(struct ether_header)) { 941166443Sbms m_freem(m); 942166443Sbms return (0); 943166443Sbms } 944166443Sbms eh = mtod(m, struct ether_header *); 945166443Sbms 946166443Sbms if (eh && (ifp->if_flags & IFF_PROMISC) == 0 && 947166443Sbms !ETHER_IS_MULTICAST(eh->ether_dhost) && 948166443Sbms bcmp(eh->ether_dhost, IF_LLADDR(ifp), ETHER_ADDR_LEN) != 0) { 949166443Sbms m_freem(m); 950166443Sbms return (0); 951166443Sbms } 952166443Sbms 953106939Ssam /* Pass packet up to parent. */ 954137101Sglebius (*ifp->if_input)(ifp, m); 955106939Ssam ifp->if_ipackets ++; /* ibytes are counted in parent */ 95663670Snsayer 95763670Snsayer return (0); 95863670Snsayer} /* tapwrite */ 95963670Snsayer 96063670Snsayer 96163670Snsayer/* 96263670Snsayer * tappoll 96363670Snsayer * 96463670Snsayer * the poll interface, this is only useful on reads 96563670Snsayer * really. the write detect always returns true, write never blocks 96663670Snsayer * anyway, it either accepts the packet or drops it 96763670Snsayer */ 96863670Snsayerstatic int 969156783Semaxtappoll(struct cdev *dev, int events, struct thread *td) 97063670Snsayer{ 97163670Snsayer struct tap_softc *tp = dev->si_drv1; 972147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 973111742Sdes int s, revents = 0; 97463670Snsayer 975121816Sbrooks TAPDEBUG("%s polling, minor = %#x\n", 976121816Sbrooks ifp->if_xname, minor(dev)); 97763670Snsayer 97863670Snsayer s = splimp(); 97963670Snsayer if (events & (POLLIN | POLLRDNORM)) { 98063670Snsayer if (ifp->if_snd.ifq_len > 0) { 981121816Sbrooks TAPDEBUG("%s have data in queue. len = %d, " \ 982121816Sbrooks "minor = %#x\n", ifp->if_xname, 98383043Sbrooks ifp->if_snd.ifq_len, minor(dev)); 98463803Snsayer 98563670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 98683043Sbrooks } else { 987121816Sbrooks TAPDEBUG("%s waiting for data, minor = %#x\n", 988121816Sbrooks ifp->if_xname, minor(dev)); 98963803Snsayer 99083805Sjhb selrecord(td, &tp->tap_rsel); 99163670Snsayer } 99263670Snsayer } 99363670Snsayer 99463670Snsayer if (events & (POLLOUT | POLLWRNORM)) 99563670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 99663670Snsayer 99763670Snsayer splx(s); 99863670Snsayer return (revents); 99963670Snsayer} /* tappoll */ 1000156783Semax 1001156783Semax 1002156783Semax/* 1003156783Semax * tap_kqfilter 1004156783Semax * 1005156783Semax * support for kevent() system call 1006156783Semax */ 1007156783Semaxstatic int 1008156783Semaxtapkqfilter(struct cdev *dev, struct knote *kn) 1009156783Semax{ 1010156783Semax int s; 1011156783Semax struct tap_softc *tp = dev->si_drv1; 1012156783Semax struct ifnet *ifp = tp->tap_ifp; 1013156783Semax 1014156783Semax s = splimp(); 1015156783Semax switch (kn->kn_filter) { 1016156783Semax case EVFILT_READ: 1017156783Semax TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n", 1018156783Semax ifp->if_xname, minor(dev)); 1019156783Semax kn->kn_fop = &tap_read_filterops; 1020156783Semax break; 1021156783Semax 1022156783Semax case EVFILT_WRITE: 1023156783Semax TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n", 1024156783Semax ifp->if_xname, minor(dev)); 1025156783Semax kn->kn_fop = &tap_write_filterops; 1026156783Semax break; 1027156783Semax 1028156783Semax default: 1029156783Semax TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n", 1030156783Semax ifp->if_xname, minor(dev)); 1031156783Semax splx(s); 1032156783Semax return (EINVAL); 1033156783Semax /* NOT REACHED */ 1034156783Semax } 1035156783Semax splx(s); 1036156783Semax 1037156783Semax kn->kn_hook = (caddr_t) dev; 1038156783Semax knlist_add(&tp->tap_rsel.si_note, kn, 0); 1039156783Semax 1040156783Semax return (0); 1041156783Semax} /* tapkqfilter */ 1042156783Semax 1043156783Semax 1044156783Semax/* 1045156783Semax * tap_kqread 1046156783Semax * 1047156783Semax * Return true if there is data in the interface queue 1048156783Semax */ 1049156783Semaxstatic int 1050156783Semaxtapkqread(struct knote *kn, long hint) 1051156783Semax{ 1052156783Semax int ret, s; 1053156783Semax struct cdev *dev = (struct cdev *)(kn->kn_hook); 1054156783Semax struct tap_softc *tp = dev->si_drv1; 1055156783Semax struct ifnet *ifp = tp->tap_ifp; 1056156783Semax 1057156783Semax s = splimp(); 1058156783Semax if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) { 1059156783Semax TAPDEBUG("%s have data in queue. len = %d, minor = %#x\n", 1060156783Semax ifp->if_xname, ifp->if_snd.ifq_len, minor(dev)); 1061156783Semax ret = 1; 1062156783Semax } else { 1063156783Semax TAPDEBUG("%s waiting for data, minor = %#x\n", 1064156783Semax ifp->if_xname, minor(dev)); 1065156783Semax ret = 0; 1066156783Semax } 1067156783Semax splx(s); 1068156783Semax 1069156783Semax return (ret); 1070156783Semax} /* tapkqread */ 1071156783Semax 1072156783Semax 1073156783Semax/* 1074156783Semax * tap_kqwrite 1075156783Semax * 1076156783Semax * Always can write. Return the MTU in kn->data 1077156783Semax */ 1078156783Semaxstatic int 1079156783Semaxtapkqwrite(struct knote *kn, long hint) 1080156783Semax{ 1081156783Semax int s; 1082156783Semax struct tap_softc *tp = ((struct cdev *) kn->kn_hook)->si_drv1; 1083156783Semax struct ifnet *ifp = tp->tap_ifp; 1084156783Semax 1085156783Semax s = splimp(); 1086156783Semax kn->kn_data = ifp->if_mtu; 1087156783Semax splx(s); 1088156783Semax 1089156783Semax return (1); 1090156783Semax} /* tapkqwrite */ 1091156783Semax 1092156783Semax 1093156783Semaxstatic void 1094156783Semaxtapkqdetach(struct knote *kn) 1095156783Semax{ 1096156783Semax struct tap_softc *tp = ((struct cdev *) kn->kn_hook)->si_drv1; 1097156783Semax 1098156783Semax knlist_remove(&tp->tap_rsel.si_note, kn, 0); 1099156783Semax} /* tapkqdetach */ 1100156783Semax 1101