if_tap.c revision 166443
190792Sgshapiro/*- 294334Sgshapiro * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com> 390792Sgshapiro * All rights reserved. 490792Sgshapiro * 590792Sgshapiro * Redistribution and use in source and binary forms, with or without 690792Sgshapiro * modification, are permitted provided that the following conditions 790792Sgshapiro * are met: 890792Sgshapiro * 1. Redistributions of source code must retain the above copyright 990792Sgshapiro * notice, this list of conditions and the following disclaimer. 1090792Sgshapiro * 2. Redistributions in binary form must reproduce the above copyright 1190792Sgshapiro * notice, this list of conditions and the following disclaimer in the 1290792Sgshapiro * documentation and/or other materials provided with the distribution. 13102528Sgshapiro * 1490792Sgshapiro * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1590792Sgshapiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1690792Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1790792Sgshapiro * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1890792Sgshapiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1990792Sgshapiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2090792Sgshapiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2190792Sgshapiro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2290792Sgshapiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2390792Sgshapiro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2490792Sgshapiro * SUCH DAMAGE. 2590792Sgshapiro * 2690792Sgshapiro * BASED ON: 2790792Sgshapiro * ------------------------------------------------------------------------- 2890792Sgshapiro * 2990792Sgshapiro * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> 3090792Sgshapiro * Nottingham University 1987. 3190792Sgshapiro */ 3290792Sgshapiro 3390792Sgshapiro/* 3490792Sgshapiro * $FreeBSD: head/sys/net/if_tap.c 166443 2007-02-03 02:57:45Z bms $ 3590792Sgshapiro * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ 3690792Sgshapiro */ 3790792Sgshapiro 3890792Sgshapiro#include "opt_compat.h" 3990792Sgshapiro#include "opt_inet.h" 4090792Sgshapiro 4190792Sgshapiro#include <sys/param.h> 4290792Sgshapiro#include <sys/conf.h> 4390792Sgshapiro#include <sys/fcntl.h> 4490792Sgshapiro#include <sys/filio.h> 4590792Sgshapiro#include <sys/kernel.h> 4690792Sgshapiro#include <sys/malloc.h> 4790792Sgshapiro#include <sys/mbuf.h> 4890792Sgshapiro#include <sys/module.h> 4990792Sgshapiro#include <sys/poll.h> 5090792Sgshapiro#include <sys/priv.h> 5190792Sgshapiro#include <sys/proc.h> 5290792Sgshapiro#include <sys/selinfo.h> 5390792Sgshapiro#include <sys/signalvar.h> 5490792Sgshapiro#include <sys/socket.h> 5590792Sgshapiro#include <sys/sockio.h> 5690792Sgshapiro#include <sys/sysctl.h> 5790792Sgshapiro#include <sys/systm.h> 5890792Sgshapiro#include <sys/ttycom.h> 5990792Sgshapiro#include <sys/uio.h> 6090792Sgshapiro#include <sys/queue.h> 6190792Sgshapiro 6290792Sgshapiro#include <net/bpf.h> 6390792Sgshapiro#include <net/ethernet.h> 6490792Sgshapiro#include <net/if.h> 6590792Sgshapiro#include <net/if_dl.h> 6690792Sgshapiro#include <net/route.h> 6790792Sgshapiro#include <net/if_types.h> 6890792Sgshapiro 6990792Sgshapiro#include <netinet/in.h> 7090792Sgshapiro 7190792Sgshapiro#include <net/if_tapvar.h> 7290792Sgshapiro#include <net/if_tap.h> 7390792Sgshapiro 7490792Sgshapiro 7590792Sgshapiro#define CDEV_NAME "tap" 7690792Sgshapiro#define TAPDEBUG if (tapdebug) printf 7790792Sgshapiro 7890792Sgshapiro#define TAP "tap" 7990792Sgshapiro#define VMNET "vmnet" 8090792Sgshapiro#define TAPMAXUNIT 0x7fff 8190792Sgshapiro#define VMNET_DEV_MASK CLONE_FLAG0 8290792Sgshapiro 8390792Sgshapiro/* module */ 8490792Sgshapirostatic int tapmodevent(module_t, int, void *); 8590792Sgshapiro 8690792Sgshapiro/* device */ 8790792Sgshapirostatic void tapclone(void *, struct ucred *, char *, int, 8890792Sgshapiro struct cdev **); 8990792Sgshapirostatic void tapcreate(struct cdev *); 9090792Sgshapiro 9190792Sgshapiro/* network interface */ 9290792Sgshapirostatic void tapifstart(struct ifnet *); 9390792Sgshapirostatic int tapifioctl(struct ifnet *, u_long, caddr_t); 9490792Sgshapirostatic void tapifinit(void *); 9590792Sgshapiro 9690792Sgshapiro/* character device */ 9790792Sgshapirostatic d_open_t tapopen; 9890792Sgshapirostatic d_close_t tapclose; 9990792Sgshapirostatic d_read_t tapread; 10090792Sgshapirostatic d_write_t tapwrite; 10190792Sgshapirostatic d_ioctl_t tapioctl; 10290792Sgshapirostatic d_poll_t tappoll; 10390792Sgshapirostatic d_kqfilter_t tapkqfilter; 10490792Sgshapiro 10590792Sgshapiro/* kqueue(2) */ 10690792Sgshapirostatic int tapkqread(struct knote *, long); 10790792Sgshapirostatic int tapkqwrite(struct knote *, long); 10894334Sgshapirostatic void tapkqdetach(struct knote *); 10990792Sgshapiro 11090792Sgshapirostatic struct filterops tap_read_filterops = { 11190792Sgshapiro .f_isfd = 1, 11290792Sgshapiro .f_attach = NULL, 11390792Sgshapiro .f_detach = tapkqdetach, 11490792Sgshapiro .f_event = tapkqread, 11590792Sgshapiro}; 11690792Sgshapiro 11790792Sgshapirostatic struct filterops tap_write_filterops = { 11890792Sgshapiro .f_isfd = 1, 11990792Sgshapiro .f_attach = NULL, 12090792Sgshapiro .f_detach = tapkqdetach, 12190792Sgshapiro .f_event = tapkqwrite, 12290792Sgshapiro}; 12390792Sgshapiro 12490792Sgshapirostatic struct cdevsw tap_cdevsw = { 12590792Sgshapiro .d_version = D_VERSION, 12690792Sgshapiro .d_flags = D_PSEUDO | D_NEEDGIANT, 12790792Sgshapiro .d_open = tapopen, 12890792Sgshapiro .d_close = tapclose, 12990792Sgshapiro .d_read = tapread, 13090792Sgshapiro .d_write = tapwrite, 13190792Sgshapiro .d_ioctl = tapioctl, 13290792Sgshapiro .d_poll = tappoll, 13390792Sgshapiro .d_name = CDEV_NAME, 13490792Sgshapiro .d_kqfilter = tapkqfilter, 13590792Sgshapiro}; 13690792Sgshapiro 13790792Sgshapiro/* 13890792Sgshapiro * All global variables in if_tap.c are locked with tapmtx, with the 13990792Sgshapiro * exception of tapdebug, which is accessed unlocked; tapclones is 14090792Sgshapiro * static at runtime. 14190792Sgshapiro */ 14290792Sgshapirostatic struct mtx tapmtx; 14390792Sgshapirostatic int tapdebug = 0; /* debug flag */ 14490792Sgshapirostatic int tapuopen = 0; /* allow user open() */ 14590792Sgshapirostatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 14690792Sgshapirostatic struct clonedevs *tapclones; 14790792Sgshapiro 14890792SgshapiroMALLOC_DECLARE(M_TAP); 14990792SgshapiroMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 15090792SgshapiroSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 15190792Sgshapiro 15290792SgshapiroSYSCTL_DECL(_net_link); 15390792SgshapiroSYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0, 15490792Sgshapiro "Ethernet tunnel software network interface"); 15590792SgshapiroSYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0, 15690792Sgshapiro "Allow user to open /dev/tap (based on node permissions)"); 15790792SgshapiroSYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, ""); 15890792Sgshapiro 15990792SgshapiroDEV_MODULE(if_tap, tapmodevent, NULL); 16090792Sgshapiro 16190792Sgshapiro/* 16290792Sgshapiro * tapmodevent 16390792Sgshapiro * 16490792Sgshapiro * module event handler 16590792Sgshapiro */ 16690792Sgshapirostatic int 16790792Sgshapirotapmodevent(module_t mod, int type, void *data) 16890792Sgshapiro{ 16990792Sgshapiro static eventhandler_tag eh_tag = NULL; 17090792Sgshapiro struct tap_softc *tp = NULL; 17190792Sgshapiro struct ifnet *ifp = NULL; 17290792Sgshapiro int s; 17390792Sgshapiro 17490792Sgshapiro switch (type) { 17590792Sgshapiro case MOD_LOAD: 17690792Sgshapiro 17790792Sgshapiro /* intitialize device */ 17890792Sgshapiro 17990792Sgshapiro mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF); 18090792Sgshapiro SLIST_INIT(&taphead); 18190792Sgshapiro 18290792Sgshapiro clone_setup(&tapclones); 18390792Sgshapiro eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 18490792Sgshapiro if (eh_tag == NULL) { 18590792Sgshapiro clone_cleanup(&tapclones); 18690792Sgshapiro mtx_destroy(&tapmtx); 18790792Sgshapiro return (ENOMEM); 18890792Sgshapiro } 18990792Sgshapiro return (0); 19090792Sgshapiro 19190792Sgshapiro case MOD_UNLOAD: 19290792Sgshapiro /* 19390792Sgshapiro * The EBUSY algorithm here can't quite atomically 19490792Sgshapiro * guarantee that this is race-free since we have to 19590792Sgshapiro * release the tap mtx to deregister the clone handler. 19690792Sgshapiro */ 19790792Sgshapiro mtx_lock(&tapmtx); 19890792Sgshapiro SLIST_FOREACH(tp, &taphead, tap_next) { 19990792Sgshapiro mtx_lock(&tp->tap_mtx); 20090792Sgshapiro if (tp->tap_flags & TAP_OPEN) { 20190792Sgshapiro mtx_unlock(&tp->tap_mtx); 20290792Sgshapiro mtx_unlock(&tapmtx); 20390792Sgshapiro return (EBUSY); 20490792Sgshapiro } 20590792Sgshapiro mtx_unlock(&tp->tap_mtx); 20690792Sgshapiro } 20790792Sgshapiro mtx_unlock(&tapmtx); 20890792Sgshapiro 20990792Sgshapiro EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 21090792Sgshapiro 21190792Sgshapiro mtx_lock(&tapmtx); 21290792Sgshapiro while ((tp = SLIST_FIRST(&taphead)) != NULL) { 21390792Sgshapiro SLIST_REMOVE_HEAD(&taphead, tap_next); 21490792Sgshapiro mtx_unlock(&tapmtx); 21590792Sgshapiro 21690792Sgshapiro ifp = tp->tap_ifp; 21790792Sgshapiro 21890792Sgshapiro TAPDEBUG("detaching %s\n", ifp->if_xname); 21990792Sgshapiro 22090792Sgshapiro /* Unlocked read. */ 22190792Sgshapiro KASSERT(!(tp->tap_flags & TAP_OPEN), 22290792Sgshapiro ("%s flags is out of sync", ifp->if_xname)); 22390792Sgshapiro 22490792Sgshapiro knlist_destroy(&tp->tap_rsel.si_note); 22590792Sgshapiro destroy_dev(tp->tap_dev); 22690792Sgshapiro s = splimp(); 22790792Sgshapiro ether_ifdetach(ifp); 22890792Sgshapiro if_free_type(ifp, IFT_ETHER); 22990792Sgshapiro splx(s); 23090792Sgshapiro 23190792Sgshapiro mtx_destroy(&tp->tap_mtx); 23290792Sgshapiro free(tp, M_TAP); 23390792Sgshapiro mtx_lock(&tapmtx); 23490792Sgshapiro } 23590792Sgshapiro mtx_unlock(&tapmtx); 23690792Sgshapiro clone_cleanup(&tapclones); 23790792Sgshapiro 23890792Sgshapiro mtx_destroy(&tapmtx); 23990792Sgshapiro 24090792Sgshapiro break; 24190792Sgshapiro 24290792Sgshapiro default: 24390792Sgshapiro return (EOPNOTSUPP); 24490792Sgshapiro } 24590792Sgshapiro 24690792Sgshapiro return (0); 24790792Sgshapiro} /* tapmodevent */ 24890792Sgshapiro 24990792Sgshapiro 25090792Sgshapiro/* 25190792Sgshapiro * DEVFS handler 25290792Sgshapiro * 25390792Sgshapiro * We need to support two kind of devices - tap and vmnet 25490792Sgshapiro */ 25590792Sgshapirostatic void 25690792Sgshapirotapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev) 25790792Sgshapiro{ 25890792Sgshapiro int extra; 25990792Sgshapiro int i, unit; 26090792Sgshapiro char *device_name = name; 26190792Sgshapiro 26290792Sgshapiro if (*dev != NULL) 26390792Sgshapiro return; 26490792Sgshapiro 26590792Sgshapiro device_name = TAP; 26690792Sgshapiro extra = 0; 26790792Sgshapiro if (strcmp(name, TAP) == 0) { 26890792Sgshapiro unit = -1; 26990792Sgshapiro } else if (strcmp(name, VMNET) == 0) { 27090792Sgshapiro device_name = VMNET; 27190792Sgshapiro extra = VMNET_DEV_MASK; 27290792Sgshapiro unit = -1; 27390792Sgshapiro } else if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 27490792Sgshapiro device_name = VMNET; 27590792Sgshapiro extra = VMNET_DEV_MASK; 27690792Sgshapiro if (dev_stdclone(name, NULL, device_name, &unit) != 1) 27790792Sgshapiro return; 27890792Sgshapiro } 27990792Sgshapiro 28090792Sgshapiro /* find any existing device, or allocate new unit number */ 28190792Sgshapiro i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra); 28290792Sgshapiro if (i) { 28390792Sgshapiro *dev = make_dev(&tap_cdevsw, unit2minor(unit | extra), 28490792Sgshapiro UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit); 28590792Sgshapiro if (*dev != NULL) { 28690792Sgshapiro dev_ref(*dev); 28790792Sgshapiro (*dev)->si_flags |= SI_CHEAPCLONE; 28890792Sgshapiro } 28990792Sgshapiro } 29090792Sgshapiro} /* tapclone */ 29190792Sgshapiro 29290792Sgshapiro 29390792Sgshapiro/* 29490792Sgshapiro * tapcreate 29590792Sgshapiro * 29690792Sgshapiro * to create interface 29790792Sgshapiro */ 29890792Sgshapirostatic void 29990792Sgshapirotapcreate(struct cdev *dev) 30090792Sgshapiro{ 30190792Sgshapiro struct ifnet *ifp = NULL; 30290792Sgshapiro struct tap_softc *tp = NULL; 30390792Sgshapiro unsigned short macaddr_hi; 30490792Sgshapiro int unit, s; 30590792Sgshapiro char *name = NULL; 30690792Sgshapiro u_char eaddr[6]; 30790792Sgshapiro 30890792Sgshapiro dev->si_flags &= ~SI_CHEAPCLONE; 30990792Sgshapiro 31090792Sgshapiro /* allocate driver storage and create device */ 31190792Sgshapiro MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 31290792Sgshapiro mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF); 31390792Sgshapiro mtx_lock(&tapmtx); 31490792Sgshapiro SLIST_INSERT_HEAD(&taphead, tp, tap_next); 31590792Sgshapiro mtx_unlock(&tapmtx); 31690792Sgshapiro 31790792Sgshapiro unit = dev2unit(dev); 31890792Sgshapiro 31990792Sgshapiro /* select device: tap or vmnet */ 32090792Sgshapiro if (unit & VMNET_DEV_MASK) { 32190792Sgshapiro name = VMNET; 32290792Sgshapiro tp->tap_flags |= TAP_VMNET; 32390792Sgshapiro } else 32490792Sgshapiro name = TAP; 32590792Sgshapiro 32690792Sgshapiro unit &= TAPMAXUNIT; 32790792Sgshapiro 32890792Sgshapiro TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 32990792Sgshapiro 33090792Sgshapiro /* generate fake MAC address: 00 bd xx xx xx unit_no */ 33190792Sgshapiro macaddr_hi = htons(0x00bd); 33290792Sgshapiro bcopy(&macaddr_hi, eaddr, sizeof(short)); 33390792Sgshapiro bcopy(&ticks, &eaddr[2], sizeof(long)); 33490792Sgshapiro eaddr[5] = (u_char)unit; 33590792Sgshapiro 33690792Sgshapiro /* fill the rest and attach interface */ 33790792Sgshapiro ifp = tp->tap_ifp = if_alloc(IFT_ETHER); 33890792Sgshapiro if (ifp == NULL) 33990792Sgshapiro panic("%s%d: can not if_alloc()", name, unit); 34090792Sgshapiro ifp->if_softc = tp; 34190792Sgshapiro if_initname(ifp, name, unit); 34290792Sgshapiro ifp->if_init = tapifinit; 34390792Sgshapiro ifp->if_start = tapifstart; 34490792Sgshapiro ifp->if_ioctl = tapifioctl; 34590792Sgshapiro ifp->if_mtu = ETHERMTU; 34690792Sgshapiro ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 34790792Sgshapiro ifp->if_snd.ifq_maxlen = ifqmaxlen; 34890792Sgshapiro 34990792Sgshapiro dev->si_drv1 = tp; 35090792Sgshapiro tp->tap_dev = dev; 35190792Sgshapiro 35290792Sgshapiro s = splimp(); 35390792Sgshapiro ether_ifattach(ifp, eaddr); 35490792Sgshapiro splx(s); 35590792Sgshapiro 35690792Sgshapiro mtx_lock(&tp->tap_mtx); 35790792Sgshapiro tp->tap_flags |= TAP_INITED; 35890792Sgshapiro mtx_unlock(&tp->tap_mtx); 35990792Sgshapiro 36090792Sgshapiro knlist_init(&tp->tap_rsel.si_note, NULL, NULL, NULL, NULL); 36190792Sgshapiro 36290792Sgshapiro TAPDEBUG("interface %s is created. minor = %#x\n", 36390792Sgshapiro ifp->if_xname, minor(dev)); 36490792Sgshapiro} /* tapcreate */ 36590792Sgshapiro 36690792Sgshapiro 36790792Sgshapiro/* 36890792Sgshapiro * tapopen 36990792Sgshapiro * 37090792Sgshapiro * to open tunnel. must be superuser 37190792Sgshapiro */ 37290792Sgshapirostatic int 37390792Sgshapirotapopen(struct cdev *dev, int flag, int mode, struct thread *td) 37490792Sgshapiro{ 37590792Sgshapiro struct tap_softc *tp = NULL; 37690792Sgshapiro struct ifnet *ifp = NULL; 37790792Sgshapiro int error, s; 37890792Sgshapiro 37990792Sgshapiro if (tapuopen == 0) { 38090792Sgshapiro error = priv_check(td, PRIV_NET_TAP); 38190792Sgshapiro if (error) 38290792Sgshapiro return (error); 38390792Sgshapiro } 38490792Sgshapiro 38590792Sgshapiro if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT) 38690792Sgshapiro return (ENXIO); 38790792Sgshapiro 38890792Sgshapiro /* 38990792Sgshapiro * XXXRW: Non-atomic test-and-set of si_drv1. Currently protected 39090792Sgshapiro * by Giant, but the race actually exists under memory pressure as 39190792Sgshapiro * well even when running with Giant, as malloc() may sleep. 39290792Sgshapiro */ 39390792Sgshapiro tp = dev->si_drv1; 39490792Sgshapiro if (tp == NULL) { 39590792Sgshapiro tapcreate(dev); 39690792Sgshapiro tp = dev->si_drv1; 39790792Sgshapiro } 39890792Sgshapiro 39990792Sgshapiro mtx_lock(&tp->tap_mtx); 40090792Sgshapiro if (tp->tap_flags & TAP_OPEN) { 40190792Sgshapiro mtx_unlock(&tp->tap_mtx); 40290792Sgshapiro return (EBUSY); 40390792Sgshapiro } 40490792Sgshapiro 40590792Sgshapiro bcopy(IF_LLADDR(tp->tap_ifp), tp->ether_addr, sizeof(tp->ether_addr)); 40690792Sgshapiro tp->tap_pid = td->td_proc->p_pid; 40790792Sgshapiro tp->tap_flags |= TAP_OPEN; 40890792Sgshapiro ifp = tp->tap_ifp; 40990792Sgshapiro mtx_unlock(&tp->tap_mtx); 41090792Sgshapiro 41190792Sgshapiro s = splimp(); 41290792Sgshapiro ifp->if_drv_flags |= IFF_DRV_RUNNING; 41390792Sgshapiro ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 41490792Sgshapiro splx(s); 41590792Sgshapiro 41690792Sgshapiro TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev)); 41790792Sgshapiro 41890792Sgshapiro return (0); 41990792Sgshapiro} /* tapopen */ 42090792Sgshapiro 42190792Sgshapiro 42290792Sgshapiro/* 42390792Sgshapiro * tapclose 42490792Sgshapiro * 42590792Sgshapiro * close the device - mark i/f down & delete routing info 42690792Sgshapiro */ 42790792Sgshapirostatic int 42890792Sgshapirotapclose(struct cdev *dev, int foo, int bar, struct thread *td) 42990792Sgshapiro{ 43090792Sgshapiro struct ifaddr *ifa; 43190792Sgshapiro struct tap_softc *tp = dev->si_drv1; 43290792Sgshapiro struct ifnet *ifp = tp->tap_ifp; 43390792Sgshapiro int s; 43490792Sgshapiro 43590792Sgshapiro /* junk all pending output */ 43690792Sgshapiro IF_DRAIN(&ifp->if_snd); 43790792Sgshapiro 43890792Sgshapiro /* 43990792Sgshapiro * do not bring the interface down, and do not anything with 44090792Sgshapiro * interface, if we are in VMnet mode. just close the device. 44190792Sgshapiro */ 44290792Sgshapiro 44390792Sgshapiro mtx_lock(&tp->tap_mtx); 44490792Sgshapiro if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 44590792Sgshapiro mtx_unlock(&tp->tap_mtx); 44690792Sgshapiro s = splimp(); 44790792Sgshapiro if_down(ifp); 44890792Sgshapiro if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 44990792Sgshapiro TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 45090792Sgshapiro rtinit(ifa, (int)RTM_DELETE, 0); 45190792Sgshapiro } 45290792Sgshapiro if_purgeaddrs(ifp); 45390792Sgshapiro ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 45490792Sgshapiro } 45590792Sgshapiro splx(s); 45690792Sgshapiro } else 45790792Sgshapiro mtx_unlock(&tp->tap_mtx); 45890792Sgshapiro 45990792Sgshapiro funsetown(&tp->tap_sigio); 46090792Sgshapiro selwakeuppri(&tp->tap_rsel, PZERO+1); 46190792Sgshapiro KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0); 46290792Sgshapiro 46390792Sgshapiro mtx_lock(&tp->tap_mtx); 46490792Sgshapiro tp->tap_flags &= ~TAP_OPEN; 46590792Sgshapiro tp->tap_pid = 0; 46690792Sgshapiro mtx_unlock(&tp->tap_mtx); 46790792Sgshapiro 46890792Sgshapiro TAPDEBUG("%s is closed. minor = %#x\n", 46990792Sgshapiro ifp->if_xname, minor(dev)); 47090792Sgshapiro 47190792Sgshapiro return (0); 47290792Sgshapiro} /* tapclose */ 47390792Sgshapiro 47490792Sgshapiro 47590792Sgshapiro/* 47690792Sgshapiro * tapifinit 47790792Sgshapiro * 47890792Sgshapiro * network interface initialization function 47990792Sgshapiro */ 48090792Sgshapirostatic void 48190792Sgshapirotapifinit(void *xtp) 48290792Sgshapiro{ 48390792Sgshapiro struct tap_softc *tp = (struct tap_softc *)xtp; 48490792Sgshapiro struct ifnet *ifp = tp->tap_ifp; 48590792Sgshapiro 48690792Sgshapiro TAPDEBUG("initializing %s\n", ifp->if_xname); 48790792Sgshapiro 48890792Sgshapiro ifp->if_drv_flags |= IFF_DRV_RUNNING; 48990792Sgshapiro ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 49090792Sgshapiro 49190792Sgshapiro /* attempt to start output */ 49290792Sgshapiro tapifstart(ifp); 49390792Sgshapiro} /* tapifinit */ 49490792Sgshapiro 49590792Sgshapiro 49690792Sgshapiro/* 49790792Sgshapiro * tapifioctl 49890792Sgshapiro * 49990792Sgshapiro * Process an ioctl request on network interface 50090792Sgshapiro */ 50190792Sgshapirostatic int 50290792Sgshapirotapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 50390792Sgshapiro{ 50490792Sgshapiro struct tap_softc *tp = ifp->if_softc; 50590792Sgshapiro struct ifstat *ifs = NULL; 50690792Sgshapiro int s, dummy; 50790792Sgshapiro 50890792Sgshapiro switch (cmd) { 50990792Sgshapiro case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 51090792Sgshapiro case SIOCADDMULTI: 51190792Sgshapiro case SIOCDELMULTI: 51290792Sgshapiro break; 51390792Sgshapiro 51490792Sgshapiro case SIOCGIFSTATUS: 51590792Sgshapiro s = splimp(); 51690792Sgshapiro ifs = (struct ifstat *)data; 51790792Sgshapiro dummy = strlen(ifs->ascii); 51890792Sgshapiro mtx_lock(&tp->tap_mtx); 51990792Sgshapiro if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 52090792Sgshapiro snprintf(ifs->ascii + dummy, 52190792Sgshapiro sizeof(ifs->ascii) - dummy, 52290792Sgshapiro "\tOpened by PID %d\n", tp->tap_pid); 52390792Sgshapiro mtx_unlock(&tp->tap_mtx); 52490792Sgshapiro splx(s); 52590792Sgshapiro break; 52690792Sgshapiro 52790792Sgshapiro default: 52890792Sgshapiro s = splimp(); 52990792Sgshapiro dummy = ether_ioctl(ifp, cmd, data); 53090792Sgshapiro splx(s); 53190792Sgshapiro return (dummy); 53290792Sgshapiro /* NOT REACHED */ 53390792Sgshapiro } 53490792Sgshapiro 53590792Sgshapiro return (0); 53690792Sgshapiro} /* tapifioctl */ 53790792Sgshapiro 53890792Sgshapiro 53990792Sgshapiro/* 54090792Sgshapiro * tapifstart 54190792Sgshapiro * 54290792Sgshapiro * queue packets from higher level ready to put out 54390792Sgshapiro */ 54490792Sgshapirostatic void 54590792Sgshapirotapifstart(struct ifnet *ifp) 54690792Sgshapiro{ 54790792Sgshapiro struct tap_softc *tp = ifp->if_softc; 54890792Sgshapiro int s; 54990792Sgshapiro 55090792Sgshapiro TAPDEBUG("%s starting\n", ifp->if_xname); 55190792Sgshapiro 55290792Sgshapiro /* 55390792Sgshapiro * do not junk pending output if we are in VMnet mode. 55490792Sgshapiro * XXX: can this do any harm because of queue overflow? 55590792Sgshapiro */ 55690792Sgshapiro 55790792Sgshapiro mtx_lock(&tp->tap_mtx); 55890792Sgshapiro if (((tp->tap_flags & TAP_VMNET) == 0) && 55990792Sgshapiro ((tp->tap_flags & TAP_READY) != TAP_READY)) { 56090792Sgshapiro struct mbuf *m = NULL; 56190792Sgshapiro 56290792Sgshapiro mtx_unlock(&tp->tap_mtx); 56390792Sgshapiro 56490792Sgshapiro /* Unlocked read. */ 56590792Sgshapiro TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 56690792Sgshapiro tp->tap_flags); 56790792Sgshapiro 56890792Sgshapiro s = splimp(); 56990792Sgshapiro do { 57090792Sgshapiro IF_DEQUEUE(&ifp->if_snd, m); 57190792Sgshapiro if (m != NULL) 57290792Sgshapiro m_freem(m); 57390792Sgshapiro ifp->if_oerrors ++; 57490792Sgshapiro } while (m != NULL); 57590792Sgshapiro splx(s); 57690792Sgshapiro 57790792Sgshapiro return; 57890792Sgshapiro } 57990792Sgshapiro mtx_unlock(&tp->tap_mtx); 58090792Sgshapiro 58190792Sgshapiro s = splimp(); 58290792Sgshapiro ifp->if_drv_flags |= IFF_DRV_OACTIVE; 58390792Sgshapiro 58490792Sgshapiro if (ifp->if_snd.ifq_len != 0) { 58590792Sgshapiro mtx_lock(&tp->tap_mtx); 58690792Sgshapiro if (tp->tap_flags & TAP_RWAIT) { 58790792Sgshapiro tp->tap_flags &= ~TAP_RWAIT; 58890792Sgshapiro wakeup(tp); 58990792Sgshapiro } 59090792Sgshapiro 59190792Sgshapiro if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) { 59290792Sgshapiro mtx_unlock(&tp->tap_mtx); 59390792Sgshapiro pgsigio(&tp->tap_sigio, SIGIO, 0); 59490792Sgshapiro } else 59590792Sgshapiro mtx_unlock(&tp->tap_mtx); 59690792Sgshapiro 59790792Sgshapiro selwakeuppri(&tp->tap_rsel, PZERO+1); 59890792Sgshapiro KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0); 59990792Sgshapiro ifp->if_opackets ++; /* obytes are counted in ether_output */ 60090792Sgshapiro } 60190792Sgshapiro 60290792Sgshapiro ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 60390792Sgshapiro splx(s); 60490792Sgshapiro} /* tapifstart */ 60590792Sgshapiro 60690792Sgshapiro 60790792Sgshapiro/* 60890792Sgshapiro * tapioctl 60990792Sgshapiro * 61090792Sgshapiro * the cdevsw interface is now pretty minimal 61190792Sgshapiro */ 61298121Sgshapirostatic int 61398121Sgshapirotapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 61498121Sgshapiro{ 61598121Sgshapiro struct tap_softc *tp = dev->si_drv1; 61698121Sgshapiro struct ifnet *ifp = tp->tap_ifp; 61798121Sgshapiro struct tapinfo *tapp = NULL; 61890792Sgshapiro int s; 61990792Sgshapiro int f; 62090792Sgshapiro#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 62190792Sgshapiro defined(COMPAT_FREEBSD4) 62290792Sgshapiro int ival; 62390792Sgshapiro#endif 62490792Sgshapiro 62590792Sgshapiro switch (cmd) { 62690792Sgshapiro case TAPSIFINFO: 62794334Sgshapiro s = splimp(); 62894334Sgshapiro tapp = (struct tapinfo *)data; 62994334Sgshapiro ifp->if_mtu = tapp->mtu; 63094334Sgshapiro ifp->if_type = tapp->type; 63194334Sgshapiro ifp->if_baudrate = tapp->baudrate; 63294334Sgshapiro splx(s); 63394334Sgshapiro break; 63494334Sgshapiro 63594334Sgshapiro case TAPGIFINFO: 63690792Sgshapiro tapp = (struct tapinfo *)data; 63790792Sgshapiro tapp->mtu = ifp->if_mtu; 63890792Sgshapiro tapp->type = ifp->if_type; 63990792Sgshapiro tapp->baudrate = ifp->if_baudrate; 64090792Sgshapiro break; 64190792Sgshapiro 64290792Sgshapiro case TAPSDEBUG: 64390792Sgshapiro tapdebug = *(int *)data; 64490792Sgshapiro break; 64590792Sgshapiro 64690792Sgshapiro case TAPGDEBUG: 64790792Sgshapiro *(int *)data = tapdebug; 64890792Sgshapiro break; 64990792Sgshapiro 65090792Sgshapiro case FIONBIO: 65190792Sgshapiro break; 65290792Sgshapiro 65390792Sgshapiro case FIOASYNC: 65490792Sgshapiro s = splimp(); 65590792Sgshapiro mtx_lock(&tp->tap_mtx); 65690792Sgshapiro if (*(int *)data) 65790792Sgshapiro tp->tap_flags |= TAP_ASYNC; 65890792Sgshapiro else 65990792Sgshapiro tp->tap_flags &= ~TAP_ASYNC; 66090792Sgshapiro mtx_unlock(&tp->tap_mtx); 66190792Sgshapiro splx(s); 66290792Sgshapiro break; 66390792Sgshapiro 66490792Sgshapiro case FIONREAD: 66590792Sgshapiro s = splimp(); 66690792Sgshapiro if (ifp->if_snd.ifq_head) { 66790792Sgshapiro struct mbuf *mb = ifp->if_snd.ifq_head; 66890792Sgshapiro 66990792Sgshapiro for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 67090792Sgshapiro *(int *)data += mb->m_len; 67190792Sgshapiro } else 67290792Sgshapiro *(int *)data = 0; 67390792Sgshapiro splx(s); 67490792Sgshapiro break; 67590792Sgshapiro 67690792Sgshapiro case FIOSETOWN: 67790792Sgshapiro return (fsetown(*(int *)data, &tp->tap_sigio)); 67890792Sgshapiro 67990792Sgshapiro case FIOGETOWN: 68090792Sgshapiro *(int *)data = fgetown(&tp->tap_sigio); 68190792Sgshapiro return (0); 68290792Sgshapiro 68390792Sgshapiro /* this is deprecated, FIOSETOWN should be used instead */ 68490792Sgshapiro case TIOCSPGRP: 68590792Sgshapiro return (fsetown(-(*(int *)data), &tp->tap_sigio)); 68690792Sgshapiro 68790792Sgshapiro /* this is deprecated, FIOGETOWN should be used instead */ 68890792Sgshapiro case TIOCGPGRP: 68990792Sgshapiro *(int *)data = -fgetown(&tp->tap_sigio); 69090792Sgshapiro return (0); 69190792Sgshapiro 69290792Sgshapiro /* VMware/VMnet port ioctl's */ 69390792Sgshapiro 69490792Sgshapiro case SIOCGIFFLAGS: /* get ifnet flags */ 69590792Sgshapiro bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 69690792Sgshapiro break; 69790792Sgshapiro 69890792Sgshapiro#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 69990792Sgshapiro defined(COMPAT_FREEBSD4) 70090792Sgshapiro case _IO('V', 0): 70190792Sgshapiro ival = IOCPARM_IVAL(data); 70290792Sgshapiro data = (caddr_t)&ival; 70390792Sgshapiro /* FALLTHROUGH */ 70490792Sgshapiro#endif 70590792Sgshapiro case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 70690792Sgshapiro f = *(int *)data; 70790792Sgshapiro f &= 0x0fff; 70890792Sgshapiro f &= ~IFF_CANTCHANGE; 70990792Sgshapiro f |= IFF_UP; 71090792Sgshapiro 71190792Sgshapiro s = splimp(); 71290792Sgshapiro ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 71390792Sgshapiro splx(s); 71490792Sgshapiro break; 71590792Sgshapiro 71690792Sgshapiro case OSIOCGIFADDR: /* get MAC address of the remote side */ 71790792Sgshapiro case SIOCGIFADDR: 71890792Sgshapiro mtx_lock(&tp->tap_mtx); 71990792Sgshapiro bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 72090792Sgshapiro mtx_unlock(&tp->tap_mtx); 72190792Sgshapiro break; 72290792Sgshapiro 72390792Sgshapiro case SIOCSIFADDR: /* set MAC address of the remote side */ 724102528Sgshapiro mtx_lock(&tp->tap_mtx); 72590792Sgshapiro bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 72690792Sgshapiro mtx_unlock(&tp->tap_mtx); 72790792Sgshapiro break; 72890792Sgshapiro 72990792Sgshapiro default: 73090792Sgshapiro return (ENOTTY); 73190792Sgshapiro } 73290792Sgshapiro return (0); 73390792Sgshapiro} /* tapioctl */ 73490792Sgshapiro 73594334Sgshapiro 73694334Sgshapiro/* 737102528Sgshapiro * tapread 73894334Sgshapiro * 73990792Sgshapiro * the cdevsw read interface - reads a packet at a time, or at 74090792Sgshapiro * least as much of a packet as can be read 74190792Sgshapiro */ 74290792Sgshapirostatic int 74390792Sgshapirotapread(struct cdev *dev, struct uio *uio, int flag) 74490792Sgshapiro{ 74590792Sgshapiro struct tap_softc *tp = dev->si_drv1; 74690792Sgshapiro struct ifnet *ifp = tp->tap_ifp; 74790792Sgshapiro struct mbuf *m = NULL; 74890792Sgshapiro int error = 0, len, s; 74990792Sgshapiro 75090792Sgshapiro TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev)); 75190792Sgshapiro 75290792Sgshapiro mtx_lock(&tp->tap_mtx); 75390792Sgshapiro if ((tp->tap_flags & TAP_READY) != TAP_READY) { 75490792Sgshapiro mtx_unlock(&tp->tap_mtx); 75590792Sgshapiro 75690792Sgshapiro /* Unlocked read. */ 75790792Sgshapiro TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 75890792Sgshapiro ifp->if_xname, minor(dev), tp->tap_flags); 75990792Sgshapiro 76090792Sgshapiro return (EHOSTDOWN); 76190792Sgshapiro } 76290792Sgshapiro 76390792Sgshapiro tp->tap_flags &= ~TAP_RWAIT; 76490792Sgshapiro mtx_unlock(&tp->tap_mtx); 76590792Sgshapiro 76690792Sgshapiro /* sleep until we get a packet */ 76790792Sgshapiro do { 76890792Sgshapiro s = splimp(); 76990792Sgshapiro IF_DEQUEUE(&ifp->if_snd, m); 77090792Sgshapiro splx(s); 77190792Sgshapiro 77290792Sgshapiro if (m == NULL) { 77390792Sgshapiro if (flag & O_NONBLOCK) 77490792Sgshapiro return (EWOULDBLOCK); 77590792Sgshapiro 77690792Sgshapiro mtx_lock(&tp->tap_mtx); 77790792Sgshapiro tp->tap_flags |= TAP_RWAIT; 77890792Sgshapiro mtx_unlock(&tp->tap_mtx); 77990792Sgshapiro error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); 78090792Sgshapiro if (error) 78190792Sgshapiro return (error); 78290792Sgshapiro } 78390792Sgshapiro } while (m == NULL); 78490792Sgshapiro 78590792Sgshapiro /* feed packet to bpf */ 78690792Sgshapiro BPF_MTAP(ifp, m); 78790792Sgshapiro 78890792Sgshapiro /* xfer packet to user space */ 78990792Sgshapiro while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 79090792Sgshapiro len = min(uio->uio_resid, m->m_len); 79190792Sgshapiro if (len == 0) 79290792Sgshapiro break; 79390792Sgshapiro 79490792Sgshapiro error = uiomove(mtod(m, void *), len, uio); 79590792Sgshapiro m = m_free(m); 79690792Sgshapiro } 79790792Sgshapiro 79890792Sgshapiro if (m != NULL) { 79990792Sgshapiro TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 80090792Sgshapiro minor(dev)); 80190792Sgshapiro m_freem(m); 80290792Sgshapiro } 80390792Sgshapiro 80490792Sgshapiro return (error); 80590792Sgshapiro} /* tapread */ 80690792Sgshapiro 80790792Sgshapiro 80890792Sgshapiro/* 80990792Sgshapiro * tapwrite 81090792Sgshapiro * 81190792Sgshapiro * the cdevsw write interface - an atomic write is a packet - or else! 81290792Sgshapiro */ 81390792Sgshapirostatic int 81490792Sgshapirotapwrite(struct cdev *dev, struct uio *uio, int flag) 81590792Sgshapiro{ 81690792Sgshapiro struct ether_header *eh; 81790792Sgshapiro struct tap_softc *tp = dev->si_drv1; 81890792Sgshapiro struct ifnet *ifp = tp->tap_ifp; 81990792Sgshapiro struct mbuf *m; 82090792Sgshapiro 82190792Sgshapiro TAPDEBUG("%s writting, minor = %#x\n", 82290792Sgshapiro ifp->if_xname, minor(dev)); 82390792Sgshapiro 82490792Sgshapiro if (uio->uio_resid == 0) 82590792Sgshapiro return (0); 82690792Sgshapiro 82790792Sgshapiro if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 82890792Sgshapiro TAPDEBUG("%s invalid packet len = %d, minor = %#x\n", 82990792Sgshapiro ifp->if_xname, uio->uio_resid, minor(dev)); 83090792Sgshapiro 83190792Sgshapiro return (EIO); 83290792Sgshapiro } 83390792Sgshapiro 83490792Sgshapiro if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, ETHER_ALIGN, 83590792Sgshapiro M_PKTHDR)) == NULL) { 83690792Sgshapiro ifp->if_ierrors ++; 83790792Sgshapiro return (ENOBUFS); 83890792Sgshapiro } 83990792Sgshapiro 84090792Sgshapiro m->m_pkthdr.rcvif = ifp; 84190792Sgshapiro 84290792Sgshapiro /* 84390792Sgshapiro * Only pass a unicast frame to ether_input(), if it would actually 84490792Sgshapiro * have been received by non-virtual hardware. 84590792Sgshapiro */ 84690792Sgshapiro if (m->m_len < sizeof(struct ether_header)) { 84790792Sgshapiro m_freem(m); 84890792Sgshapiro return (0); 84990792Sgshapiro } 85090792Sgshapiro eh = mtod(m, struct ether_header *); 85190792Sgshapiro 85290792Sgshapiro if (eh && (ifp->if_flags & IFF_PROMISC) == 0 && 85390792Sgshapiro !ETHER_IS_MULTICAST(eh->ether_dhost) && 85490792Sgshapiro bcmp(eh->ether_dhost, IF_LLADDR(ifp), ETHER_ADDR_LEN) != 0) { 85590792Sgshapiro m_freem(m); 85690792Sgshapiro return (0); 85790792Sgshapiro } 85890792Sgshapiro 85990792Sgshapiro /* Pass packet up to parent. */ 86090792Sgshapiro (*ifp->if_input)(ifp, m); 86190792Sgshapiro ifp->if_ipackets ++; /* ibytes are counted in parent */ 86290792Sgshapiro 86390792Sgshapiro return (0); 86490792Sgshapiro} /* tapwrite */ 86590792Sgshapiro 86690792Sgshapiro 86790792Sgshapiro/* 86890792Sgshapiro * tappoll 86990792Sgshapiro * 87090792Sgshapiro * the poll interface, this is only useful on reads 87190792Sgshapiro * really. the write detect always returns true, write never blocks 87290792Sgshapiro * anyway, it either accepts the packet or drops it 87390792Sgshapiro */ 87490792Sgshapirostatic int 87590792Sgshapirotappoll(struct cdev *dev, int events, struct thread *td) 87690792Sgshapiro{ 87790792Sgshapiro struct tap_softc *tp = dev->si_drv1; 87890792Sgshapiro struct ifnet *ifp = tp->tap_ifp; 87990792Sgshapiro int s, revents = 0; 88090792Sgshapiro 88190792Sgshapiro TAPDEBUG("%s polling, minor = %#x\n", 88290792Sgshapiro ifp->if_xname, minor(dev)); 88390792Sgshapiro 88490792Sgshapiro s = splimp(); 88590792Sgshapiro if (events & (POLLIN | POLLRDNORM)) { 88690792Sgshapiro if (ifp->if_snd.ifq_len > 0) { 88790792Sgshapiro TAPDEBUG("%s have data in queue. len = %d, " \ 88890792Sgshapiro "minor = %#x\n", ifp->if_xname, 88990792Sgshapiro ifp->if_snd.ifq_len, minor(dev)); 89090792Sgshapiro 89190792Sgshapiro revents |= (events & (POLLIN | POLLRDNORM)); 89290792Sgshapiro } else { 89390792Sgshapiro TAPDEBUG("%s waiting for data, minor = %#x\n", 89490792Sgshapiro ifp->if_xname, minor(dev)); 89590792Sgshapiro 89690792Sgshapiro selrecord(td, &tp->tap_rsel); 89790792Sgshapiro } 89890792Sgshapiro } 89990792Sgshapiro 90090792Sgshapiro if (events & (POLLOUT | POLLWRNORM)) 90190792Sgshapiro revents |= (events & (POLLOUT | POLLWRNORM)); 90290792Sgshapiro 90390792Sgshapiro splx(s); 90490792Sgshapiro return (revents); 90590792Sgshapiro} /* tappoll */ 90690792Sgshapiro 90790792Sgshapiro 90890792Sgshapiro/* 90990792Sgshapiro * tap_kqfilter 91090792Sgshapiro * 91190792Sgshapiro * support for kevent() system call 91290792Sgshapiro */ 91390792Sgshapirostatic int 91490792Sgshapirotapkqfilter(struct cdev *dev, struct knote *kn) 91590792Sgshapiro{ 91690792Sgshapiro int s; 91790792Sgshapiro struct tap_softc *tp = dev->si_drv1; 91890792Sgshapiro struct ifnet *ifp = tp->tap_ifp; 91990792Sgshapiro 92090792Sgshapiro s = splimp(); 92190792Sgshapiro switch (kn->kn_filter) { 92290792Sgshapiro case EVFILT_READ: 92390792Sgshapiro TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n", 92490792Sgshapiro ifp->if_xname, minor(dev)); 92590792Sgshapiro kn->kn_fop = &tap_read_filterops; 92690792Sgshapiro break; 92790792Sgshapiro 92890792Sgshapiro case EVFILT_WRITE: 92990792Sgshapiro TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n", 93090792Sgshapiro ifp->if_xname, minor(dev)); 93190792Sgshapiro kn->kn_fop = &tap_write_filterops; 93290792Sgshapiro break; 93390792Sgshapiro 93490792Sgshapiro default: 93590792Sgshapiro TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n", 93690792Sgshapiro ifp->if_xname, minor(dev)); 93790792Sgshapiro splx(s); 93890792Sgshapiro return (EINVAL); 93990792Sgshapiro /* NOT REACHED */ 94090792Sgshapiro } 94190792Sgshapiro splx(s); 94290792Sgshapiro 94390792Sgshapiro kn->kn_hook = (caddr_t) dev; 94490792Sgshapiro knlist_add(&tp->tap_rsel.si_note, kn, 0); 94590792Sgshapiro 94690792Sgshapiro return (0); 94790792Sgshapiro} /* tapkqfilter */ 94890792Sgshapiro 94990792Sgshapiro 95090792Sgshapiro/* 95190792Sgshapiro * tap_kqread 95290792Sgshapiro * 95390792Sgshapiro * Return true if there is data in the interface queue 95490792Sgshapiro */ 95590792Sgshapirostatic int 95690792Sgshapirotapkqread(struct knote *kn, long hint) 95790792Sgshapiro{ 95890792Sgshapiro int ret, s; 95990792Sgshapiro struct cdev *dev = (struct cdev *)(kn->kn_hook); 96090792Sgshapiro struct tap_softc *tp = dev->si_drv1; 96190792Sgshapiro struct ifnet *ifp = tp->tap_ifp; 96290792Sgshapiro 96390792Sgshapiro s = splimp(); 96490792Sgshapiro if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) { 96590792Sgshapiro TAPDEBUG("%s have data in queue. len = %d, minor = %#x\n", 96690792Sgshapiro ifp->if_xname, ifp->if_snd.ifq_len, minor(dev)); 96790792Sgshapiro ret = 1; 96890792Sgshapiro } else { 96990792Sgshapiro TAPDEBUG("%s waiting for data, minor = %#x\n", 97090792Sgshapiro ifp->if_xname, minor(dev)); 97190792Sgshapiro ret = 0; 97290792Sgshapiro } 97390792Sgshapiro splx(s); 97490792Sgshapiro 97590792Sgshapiro return (ret); 97690792Sgshapiro} /* tapkqread */ 97790792Sgshapiro 97890792Sgshapiro 97990792Sgshapiro/* 98090792Sgshapiro * tap_kqwrite 98190792Sgshapiro * 98290792Sgshapiro * Always can write. Return the MTU in kn->data 98390792Sgshapiro */ 98490792Sgshapirostatic int 98590792Sgshapirotapkqwrite(struct knote *kn, long hint) 98690792Sgshapiro{ 98790792Sgshapiro int s; 98890792Sgshapiro struct tap_softc *tp = ((struct cdev *) kn->kn_hook)->si_drv1; 98990792Sgshapiro struct ifnet *ifp = tp->tap_ifp; 99090792Sgshapiro 99190792Sgshapiro s = splimp(); 99290792Sgshapiro kn->kn_data = ifp->if_mtu; 99390792Sgshapiro splx(s); 99490792Sgshapiro 99590792Sgshapiro return (1); 99690792Sgshapiro} /* tapkqwrite */ 99790792Sgshapiro 99890792Sgshapiro 99990792Sgshapirostatic void 100090792Sgshapirotapkqdetach(struct knote *kn) 100190792Sgshapiro{ 100290792Sgshapiro struct tap_softc *tp = ((struct cdev *) kn->kn_hook)->si_drv1; 100390792Sgshapiro 100490792Sgshapiro knlist_remove(&tp->tap_rsel.si_note, kn, 0); 100590792Sgshapiro} /* tapkqdetach */ 100690792Sgshapiro 100790792Sgshapiro