if_tap.c revision 163986
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 163986 2006-11-04 20:54:37Z csjp $ 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> 5063670Snsayer#include <sys/proc.h> 51139207Sphk#include <sys/selinfo.h> 5263670Snsayer#include <sys/signalvar.h> 5363670Snsayer#include <sys/socket.h> 5463670Snsayer#include <sys/sockio.h> 5563670Snsayer#include <sys/sysctl.h> 5663670Snsayer#include <sys/systm.h> 5763670Snsayer#include <sys/ttycom.h> 5863670Snsayer#include <sys/uio.h> 5983043Sbrooks#include <sys/queue.h> 6063670Snsayer 6163670Snsayer#include <net/bpf.h> 6263670Snsayer#include <net/ethernet.h> 6363670Snsayer#include <net/if.h> 64152315Sru#include <net/if_dl.h> 6563670Snsayer#include <net/route.h> 66147256Sbrooks#include <net/if_types.h> 6763670Snsayer 6863670Snsayer#include <netinet/in.h> 6963670Snsayer 7063670Snsayer#include <net/if_tapvar.h> 7163670Snsayer#include <net/if_tap.h> 7263670Snsayer 7363670Snsayer 7463670Snsayer#define CDEV_NAME "tap" 7563670Snsayer#define TAPDEBUG if (tapdebug) printf 7663670Snsayer 7763670Snsayer#define TAP "tap" 7863670Snsayer#define VMNET "vmnet" 7983043Sbrooks#define TAPMAXUNIT 0x7fff 80126077Sphk#define VMNET_DEV_MASK CLONE_FLAG0 8163670Snsayer 8263670Snsayer/* module */ 83111742Sdesstatic int tapmodevent(module_t, int, void *); 8463670Snsayer 8563670Snsayer/* device */ 86148868Srwatsonstatic void tapclone(void *, struct ucred *, char *, int, 87148868Srwatson struct cdev **); 88130585Sphkstatic void tapcreate(struct cdev *); 8963670Snsayer 9063670Snsayer/* network interface */ 9193084Sbdestatic void tapifstart(struct ifnet *); 9293084Sbdestatic int tapifioctl(struct ifnet *, u_long, caddr_t); 9393084Sbdestatic void tapifinit(void *); 9463670Snsayer 9563670Snsayer/* character device */ 9663670Snsayerstatic d_open_t tapopen; 9763670Snsayerstatic d_close_t tapclose; 9863670Snsayerstatic d_read_t tapread; 9963670Snsayerstatic d_write_t tapwrite; 10063670Snsayerstatic d_ioctl_t tapioctl; 10163670Snsayerstatic d_poll_t tappoll; 102156783Semaxstatic d_kqfilter_t tapkqfilter; 10363670Snsayer 104156783Semax/* kqueue(2) */ 105156783Semaxstatic int tapkqread(struct knote *, long); 106156783Semaxstatic int tapkqwrite(struct knote *, long); 107156783Semaxstatic void tapkqdetach(struct knote *); 108156783Semax 109156783Semaxstatic struct filterops tap_read_filterops = { 110156783Semax .f_isfd = 1, 111156783Semax .f_attach = NULL, 112156783Semax .f_detach = tapkqdetach, 113156783Semax .f_event = tapkqread, 114156783Semax}; 115156783Semax 116156783Semaxstatic struct filterops tap_write_filterops = { 117156783Semax .f_isfd = 1, 118156783Semax .f_attach = NULL, 119156783Semax .f_detach = tapkqdetach, 120156783Semax .f_event = tapkqwrite, 121156783Semax}; 122156783Semax 12363670Snsayerstatic struct cdevsw tap_cdevsw = { 124126080Sphk .d_version = D_VERSION, 125126188Sbde .d_flags = D_PSEUDO | D_NEEDGIANT, 126111815Sphk .d_open = tapopen, 127111815Sphk .d_close = tapclose, 128111815Sphk .d_read = tapread, 129111815Sphk .d_write = tapwrite, 130111815Sphk .d_ioctl = tapioctl, 131111815Sphk .d_poll = tappoll, 132111815Sphk .d_name = CDEV_NAME, 133156783Semax .d_kqfilter = tapkqfilter, 13463670Snsayer}; 13563670Snsayer 136127003Srwatson/* 137127003Srwatson * All global variables in if_tap.c are locked with tapmtx, with the 138127003Srwatson * exception of tapdebug, which is accessed unlocked; tapclones is 139127003Srwatson * static at runtime. 140127003Srwatson */ 141127003Srwatsonstatic struct mtx tapmtx; 14283043Sbrooksstatic int tapdebug = 0; /* debug flag */ 143144979Smdoddstatic int tapuopen = 0; /* allow user open() */ 14483043Sbrooksstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 145126077Sphkstatic struct clonedevs *tapclones; 14663670Snsayer 14763670SnsayerMALLOC_DECLARE(M_TAP); 14863670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 14963670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 150144979Smdodd 151144979SmdoddSYSCTL_DECL(_net_link); 152144979SmdoddSYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0, 153144979Smdodd "Ethernet tunnel software network interface"); 154144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0, 155144979Smdodd "Allow user to open /dev/tap (based on node permissions)"); 156144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, ""); 157144979Smdodd 15863670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL); 15963670Snsayer 16063670Snsayer/* 16163670Snsayer * tapmodevent 16263670Snsayer * 16363670Snsayer * module event handler 16463670Snsayer */ 16563670Snsayerstatic int 166156783Semaxtapmodevent(module_t mod, int type, void *data) 16763670Snsayer{ 16883043Sbrooks static eventhandler_tag eh_tag = NULL; 16983043Sbrooks struct tap_softc *tp = NULL; 17083043Sbrooks struct ifnet *ifp = NULL; 171126077Sphk int s; 17263670Snsayer 17363670Snsayer switch (type) { 17463670Snsayer case MOD_LOAD: 17563670Snsayer 17683043Sbrooks /* intitialize device */ 17783043Sbrooks 178127003Srwatson mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF); 17983043Sbrooks SLIST_INIT(&taphead); 18083043Sbrooks 181126845Sphk clone_setup(&tapclones); 18271602Sphk eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 183127003Srwatson if (eh_tag == NULL) { 184127170Srwatson clone_cleanup(&tapclones); 185127003Srwatson mtx_destroy(&tapmtx); 186126077Sphk return (ENOMEM); 187127003Srwatson } 18883043Sbrooks return (0); 18963670Snsayer 19083043Sbrooks case MOD_UNLOAD: 191127003Srwatson /* 192127003Srwatson * The EBUSY algorithm here can't quite atomically 193127003Srwatson * guarantee that this is race-free since we have to 194127003Srwatson * release the tap mtx to deregister the clone handler. 195127003Srwatson */ 196127003Srwatson mtx_lock(&tapmtx); 197127003Srwatson SLIST_FOREACH(tp, &taphead, tap_next) { 198127098Srwatson mtx_lock(&tp->tap_mtx); 199127003Srwatson if (tp->tap_flags & TAP_OPEN) { 200127098Srwatson mtx_unlock(&tp->tap_mtx); 201127003Srwatson mtx_unlock(&tapmtx); 20283043Sbrooks return (EBUSY); 203127003Srwatson } 204127098Srwatson mtx_unlock(&tp->tap_mtx); 205127003Srwatson } 206127003Srwatson mtx_unlock(&tapmtx); 20783043Sbrooks 20871602Sphk EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 20963670Snsayer 210127003Srwatson mtx_lock(&tapmtx); 21183043Sbrooks while ((tp = SLIST_FIRST(&taphead)) != NULL) { 21283043Sbrooks SLIST_REMOVE_HEAD(&taphead, tap_next); 213127003Srwatson mtx_unlock(&tapmtx); 21483043Sbrooks 215147256Sbrooks ifp = tp->tap_ifp; 21683043Sbrooks 217121816Sbrooks TAPDEBUG("detaching %s\n", ifp->if_xname); 21883043Sbrooks 219127098Srwatson /* Unlocked read. */ 220121816Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 221121816Sbrooks ("%s flags is out of sync", ifp->if_xname)); 22283043Sbrooks 223158697Semax knlist_destroy(&tp->tap_rsel.si_note); 224126077Sphk destroy_dev(tp->tap_dev); 22563670Snsayer s = splimp(); 226106939Ssam ether_ifdetach(ifp); 227147256Sbrooks if_free_type(ifp, IFT_ETHER); 22863670Snsayer splx(s); 22963670Snsayer 230127098Srwatson mtx_destroy(&tp->tap_mtx); 23193752Sluigi free(tp, M_TAP); 232127003Srwatson mtx_lock(&tapmtx); 23383043Sbrooks } 234127003Srwatson mtx_unlock(&tapmtx); 235126077Sphk clone_cleanup(&tapclones); 23663670Snsayer 237135354Srwatson mtx_destroy(&tapmtx); 238135354Srwatson 23983043Sbrooks break; 24063670Snsayer 24163670Snsayer default: 24263670Snsayer return (EOPNOTSUPP); 24363670Snsayer } 24463670Snsayer 24563670Snsayer return (0); 24663670Snsayer} /* tapmodevent */ 24763670Snsayer 24863670Snsayer 24963670Snsayer/* 25071602Sphk * DEVFS handler 25171602Sphk * 25271602Sphk * We need to support two kind of devices - tap and vmnet 25371602Sphk */ 25471602Sphkstatic void 255156783Semaxtapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev) 25671602Sphk{ 257126077Sphk u_int extra; 258126077Sphk int i, unit; 25983043Sbrooks char *device_name = name; 26071602Sphk 261130640Sphk if (*dev != NULL) 26271602Sphk return; 26371602Sphk 264126077Sphk device_name = TAP; 265126077Sphk extra = 0; 266126077Sphk if (strcmp(name, TAP) == 0) { 267126077Sphk unit = -1; 268126077Sphk } else if (strcmp(name, VMNET) == 0) { 269126077Sphk device_name = VMNET; 270126077Sphk extra = VMNET_DEV_MASK; 271126077Sphk unit = -1; 272126077Sphk } else if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 273126077Sphk device_name = VMNET; 274126077Sphk extra = VMNET_DEV_MASK; 275126077Sphk if (dev_stdclone(name, NULL, device_name, &unit) != 1) 276126077Sphk return; 27783043Sbrooks } 27871602Sphk 279126077Sphk /* find any existing device, or allocate new unit number */ 280126077Sphk i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra); 281126077Sphk if (i) { 282126796Sphk *dev = make_dev(&tap_cdevsw, unit2minor(unit | extra), 283126077Sphk UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit); 284144389Sphk if (*dev != NULL) { 285144389Sphk dev_ref(*dev); 286126077Sphk (*dev)->si_flags |= SI_CHEAPCLONE; 287144389Sphk } 28871602Sphk } 28971602Sphk} /* tapclone */ 29071602Sphk 29171602Sphk 29271602Sphk/* 29363670Snsayer * tapcreate 29463670Snsayer * 29563670Snsayer * to create interface 29663670Snsayer */ 29763670Snsayerstatic void 298156783Semaxtapcreate(struct cdev *dev) 29963670Snsayer{ 30063670Snsayer struct ifnet *ifp = NULL; 30163670Snsayer struct tap_softc *tp = NULL; 30263670Snsayer unsigned short macaddr_hi; 30363803Snsayer int unit, s; 30463670Snsayer char *name = NULL; 305147256Sbrooks u_char eaddr[6]; 30663670Snsayer 307126077Sphk dev->si_flags &= ~SI_CHEAPCLONE; 308126077Sphk 30963670Snsayer /* allocate driver storage and create device */ 310111119Simp MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 311127098Srwatson mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF); 312127003Srwatson mtx_lock(&tapmtx); 31383043Sbrooks SLIST_INSERT_HEAD(&taphead, tp, tap_next); 314127003Srwatson mtx_unlock(&tapmtx); 31563670Snsayer 316126796Sphk unit = dev2unit(dev); 31783043Sbrooks 31863670Snsayer /* select device: tap or vmnet */ 319126796Sphk if (unit & VMNET_DEV_MASK) { 32063670Snsayer name = VMNET; 32163803Snsayer tp->tap_flags |= TAP_VMNET; 32283043Sbrooks } else 32363670Snsayer name = TAP; 32463670Snsayer 325126796Sphk unit &= TAPMAXUNIT; 326126796Sphk 32783043Sbrooks TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 32883043Sbrooks 32963670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 33063670Snsayer macaddr_hi = htons(0x00bd); 331147256Sbrooks bcopy(&macaddr_hi, eaddr, sizeof(short)); 332147256Sbrooks bcopy(&ticks, &eaddr[2], sizeof(long)); 333147256Sbrooks eaddr[5] = (u_char)unit; 33463670Snsayer 335111742Sdes /* fill the rest and attach interface */ 336147256Sbrooks ifp = tp->tap_ifp = if_alloc(IFT_ETHER); 337147256Sbrooks if (ifp == NULL) 338147256Sbrooks panic("%s%d: can not if_alloc()", name, unit); 33963670Snsayer ifp->if_softc = tp; 340121816Sbrooks if_initname(ifp, name, unit); 34163670Snsayer ifp->if_init = tapifinit; 34263670Snsayer ifp->if_start = tapifstart; 34363670Snsayer ifp->if_ioctl = tapifioctl; 34463670Snsayer ifp->if_mtu = ETHERMTU; 34563670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 34663670Snsayer ifp->if_snd.ifq_maxlen = ifqmaxlen; 34763670Snsayer 34883043Sbrooks dev->si_drv1 = tp; 349126077Sphk tp->tap_dev = dev; 35083043Sbrooks 35163803Snsayer s = splimp(); 352147256Sbrooks ether_ifattach(ifp, eaddr); 35363803Snsayer splx(s); 35463670Snsayer 355127098Srwatson mtx_lock(&tp->tap_mtx); 35663803Snsayer tp->tap_flags |= TAP_INITED; 357127098Srwatson mtx_unlock(&tp->tap_mtx); 35863803Snsayer 359158697Semax knlist_init(&tp->tap_rsel.si_note, NULL, NULL, NULL, NULL); 360158697Semax 361121816Sbrooks TAPDEBUG("interface %s is created. minor = %#x\n", 362121816Sbrooks ifp->if_xname, minor(dev)); 36363670Snsayer} /* tapcreate */ 36463670Snsayer 36563670Snsayer 36663670Snsayer/* 367111742Sdes * tapopen 36863670Snsayer * 36963670Snsayer * to open tunnel. must be superuser 37063670Snsayer */ 37163670Snsayerstatic int 372156783Semaxtapopen(struct cdev *dev, int flag, int mode, struct thread *td) 37363670Snsayer{ 37463670Snsayer struct tap_softc *tp = NULL; 375133460Semax struct ifnet *ifp = NULL; 376144979Smdodd int s; 37763670Snsayer 378144979Smdodd if (tapuopen == 0 && suser(td) != 0) 379144979Smdodd return (EPERM); 38063670Snsayer 381126796Sphk if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT) 382126796Sphk return (ENXIO); 38383043Sbrooks 384127165Srwatson /* 385127165Srwatson * XXXRW: Non-atomic test-and-set of si_drv1. Currently protected 386127165Srwatson * by Giant, but the race actually exists under memory pressure as 387127165Srwatson * well even when running with Giant, as malloc() may sleep. 388127165Srwatson */ 38963670Snsayer tp = dev->si_drv1; 39063670Snsayer if (tp == NULL) { 39163670Snsayer tapcreate(dev); 39263670Snsayer tp = dev->si_drv1; 39363670Snsayer } 39463670Snsayer 395127165Srwatson mtx_lock(&tp->tap_mtx); 396127165Srwatson if (tp->tap_flags & TAP_OPEN) { 397127165Srwatson mtx_unlock(&tp->tap_mtx); 398127165Srwatson return (EBUSY); 399127165Srwatson } 40063670Snsayer 401152315Sru bcopy(IF_LLADDR(tp->tap_ifp), tp->ether_addr, sizeof(tp->ether_addr)); 40283366Sjulian tp->tap_pid = td->td_proc->p_pid; 40363670Snsayer tp->tap_flags |= TAP_OPEN; 404147256Sbrooks ifp = tp->tap_ifp; 405127098Srwatson mtx_unlock(&tp->tap_mtx); 40663670Snsayer 407133460Semax s = splimp(); 408148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 409148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 410133460Semax splx(s); 41163670Snsayer 412133460Semax TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev)); 413133460Semax 41463670Snsayer return (0); 41563670Snsayer} /* tapopen */ 41663670Snsayer 41763670Snsayer 41863670Snsayer/* 41963670Snsayer * tapclose 42063670Snsayer * 42163670Snsayer * close the device - mark i/f down & delete routing info 42263670Snsayer */ 42363670Snsayerstatic int 424156783Semaxtapclose(struct cdev *dev, int foo, int bar, struct thread *td) 42563670Snsayer{ 426156783Semax struct ifaddr *ifa; 42763670Snsayer struct tap_softc *tp = dev->si_drv1; 428147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 429126077Sphk int s; 43063670Snsayer 43163670Snsayer /* junk all pending output */ 43283043Sbrooks IF_DRAIN(&ifp->if_snd); 43363670Snsayer 43463803Snsayer /* 43563803Snsayer * do not bring the interface down, and do not anything with 43663803Snsayer * interface, if we are in VMnet mode. just close the device. 43763803Snsayer */ 43863803Snsayer 439127098Srwatson mtx_lock(&tp->tap_mtx); 44063803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 441127098Srwatson mtx_unlock(&tp->tap_mtx); 44263670Snsayer s = splimp(); 44363670Snsayer if_down(ifp); 444148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 44563803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 446146620Speadar rtinit(ifa, (int)RTM_DELETE, 0); 44763670Snsayer } 448146620Speadar if_purgeaddrs(ifp); 449148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 45063670Snsayer } 45163670Snsayer splx(s); 452127098Srwatson } else 453127098Srwatson mtx_unlock(&tp->tap_mtx); 45463670Snsayer 45596122Salfred funsetown(&tp->tap_sigio); 456122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 457156783Semax KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0); 45863670Snsayer 459127098Srwatson mtx_lock(&tp->tap_mtx); 46063670Snsayer tp->tap_flags &= ~TAP_OPEN; 46163670Snsayer tp->tap_pid = 0; 462127098Srwatson mtx_unlock(&tp->tap_mtx); 46363670Snsayer 464121816Sbrooks TAPDEBUG("%s is closed. minor = %#x\n", 465121816Sbrooks ifp->if_xname, minor(dev)); 46663670Snsayer 46763670Snsayer return (0); 46863670Snsayer} /* tapclose */ 46963670Snsayer 47063670Snsayer 47163670Snsayer/* 47263670Snsayer * tapifinit 47363670Snsayer * 47463670Snsayer * network interface initialization function 47563670Snsayer */ 47663670Snsayerstatic void 477156783Semaxtapifinit(void *xtp) 47863670Snsayer{ 47963670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 480147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 48163670Snsayer 482121816Sbrooks TAPDEBUG("initializing %s\n", ifp->if_xname); 48363670Snsayer 484148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 485148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 48663670Snsayer 48763670Snsayer /* attempt to start output */ 48863670Snsayer tapifstart(ifp); 48963670Snsayer} /* tapifinit */ 49063670Snsayer 49163670Snsayer 49263670Snsayer/* 49363670Snsayer * tapifioctl 49463670Snsayer * 49563670Snsayer * Process an ioctl request on network interface 49663670Snsayer */ 497105228Sphkstatic int 498156783Semaxtapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 49963670Snsayer{ 500160376Sbrooks struct tap_softc *tp = ifp->if_softc; 50163670Snsayer struct ifstat *ifs = NULL; 50263670Snsayer int s, dummy; 50363670Snsayer 50463670Snsayer switch (cmd) { 50563670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 50663670Snsayer case SIOCADDMULTI: 50763670Snsayer case SIOCDELMULTI: 50883043Sbrooks break; 50963670Snsayer 51063670Snsayer case SIOCGIFSTATUS: 51163670Snsayer s = splimp(); 51263670Snsayer ifs = (struct ifstat *)data; 51363670Snsayer dummy = strlen(ifs->ascii); 514127098Srwatson mtx_lock(&tp->tap_mtx); 51563670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 51663670Snsayer snprintf(ifs->ascii + dummy, 51763670Snsayer sizeof(ifs->ascii) - dummy, 51863670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 519127098Srwatson mtx_unlock(&tp->tap_mtx); 52063670Snsayer splx(s); 52183043Sbrooks break; 52263670Snsayer 52363670Snsayer default: 524106939Ssam s = splimp(); 525106939Ssam dummy = ether_ioctl(ifp, cmd, data); 526106939Ssam splx(s); 527106939Ssam return (dummy); 528156783Semax /* NOT REACHED */ 52963670Snsayer } 53063670Snsayer 53163670Snsayer return (0); 53263670Snsayer} /* tapifioctl */ 53363670Snsayer 53463670Snsayer 53563670Snsayer/* 536111742Sdes * tapifstart 537111742Sdes * 53863670Snsayer * queue packets from higher level ready to put out 53963670Snsayer */ 54063670Snsayerstatic void 541156783Semaxtapifstart(struct ifnet *ifp) 54263670Snsayer{ 54363670Snsayer struct tap_softc *tp = ifp->if_softc; 54463670Snsayer int s; 54563670Snsayer 546121816Sbrooks TAPDEBUG("%s starting\n", ifp->if_xname); 54763670Snsayer 54863803Snsayer /* 54963803Snsayer * do not junk pending output if we are in VMnet mode. 55063803Snsayer * XXX: can this do any harm because of queue overflow? 55163803Snsayer */ 55263803Snsayer 553127098Srwatson mtx_lock(&tp->tap_mtx); 554111742Sdes if (((tp->tap_flags & TAP_VMNET) == 0) && 55563803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 55663670Snsayer struct mbuf *m = NULL; 55763670Snsayer 558127098Srwatson mtx_unlock(&tp->tap_mtx); 559127098Srwatson 560127098Srwatson /* Unlocked read. */ 561121816Sbrooks TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 562121816Sbrooks tp->tap_flags); 56363670Snsayer 56463670Snsayer s = splimp(); 56563670Snsayer do { 56663670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 56763670Snsayer if (m != NULL) 56863670Snsayer m_freem(m); 56963670Snsayer ifp->if_oerrors ++; 57063670Snsayer } while (m != NULL); 57163670Snsayer splx(s); 57263670Snsayer 57363670Snsayer return; 57463670Snsayer } 575127098Srwatson mtx_unlock(&tp->tap_mtx); 57663670Snsayer 57763670Snsayer s = splimp(); 578148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 57963670Snsayer 58063670Snsayer if (ifp->if_snd.ifq_len != 0) { 581127098Srwatson mtx_lock(&tp->tap_mtx); 58263670Snsayer if (tp->tap_flags & TAP_RWAIT) { 58363670Snsayer tp->tap_flags &= ~TAP_RWAIT; 584111748Sdes wakeup(tp); 58563670Snsayer } 58663670Snsayer 587127098Srwatson if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) { 588127098Srwatson mtx_unlock(&tp->tap_mtx); 58995883Salfred pgsigio(&tp->tap_sigio, SIGIO, 0); 590127098Srwatson } else 591127098Srwatson mtx_unlock(&tp->tap_mtx); 59263670Snsayer 593122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 594156783Semax KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0); 59563670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 59663670Snsayer } 59763670Snsayer 598148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 59963670Snsayer splx(s); 60063670Snsayer} /* tapifstart */ 60163670Snsayer 60263670Snsayer 60363670Snsayer/* 60463670Snsayer * tapioctl 60563670Snsayer * 60663670Snsayer * the cdevsw interface is now pretty minimal 60763670Snsayer */ 60863670Snsayerstatic int 609156783Semaxtapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 61063670Snsayer{ 61163670Snsayer struct tap_softc *tp = dev->si_drv1; 612147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 613111742Sdes struct tapinfo *tapp = NULL; 61463670Snsayer int s; 615102052Ssobomax int f; 616162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 617162711Sru defined(COMPAT_FREEBSD4) 618162711Sru int ival; 619162711Sru#endif 62063670Snsayer 62163670Snsayer switch (cmd) { 622111742Sdes case TAPSIFINFO: 62363670Snsayer s = splimp(); 624111742Sdes tapp = (struct tapinfo *)data; 625111742Sdes ifp->if_mtu = tapp->mtu; 626111742Sdes ifp->if_type = tapp->type; 627111742Sdes ifp->if_baudrate = tapp->baudrate; 62863670Snsayer splx(s); 629111742Sdes break; 63063670Snsayer 631111742Sdes case TAPGIFINFO: 632111742Sdes tapp = (struct tapinfo *)data; 633111742Sdes tapp->mtu = ifp->if_mtu; 634111742Sdes tapp->type = ifp->if_type; 635111742Sdes tapp->baudrate = ifp->if_baudrate; 636111742Sdes break; 63763670Snsayer 63863670Snsayer case TAPSDEBUG: 639159079Smarius tapdebug = *(int *)data; 64083043Sbrooks break; 64163670Snsayer 64263670Snsayer case TAPGDEBUG: 643159079Smarius *(int *)data = tapdebug; 64483043Sbrooks break; 64563670Snsayer 64663670Snsayer case FIONBIO: 64783043Sbrooks break; 64863670Snsayer 64963670Snsayer case FIOASYNC: 65063803Snsayer s = splimp(); 651127098Srwatson mtx_lock(&tp->tap_mtx); 652159079Smarius if (*(int *)data) 65363670Snsayer tp->tap_flags |= TAP_ASYNC; 65463670Snsayer else 65563670Snsayer tp->tap_flags &= ~TAP_ASYNC; 656127098Srwatson mtx_unlock(&tp->tap_mtx); 65763803Snsayer splx(s); 65883043Sbrooks break; 65963670Snsayer 66063670Snsayer case FIONREAD: 66163670Snsayer s = splimp(); 66263670Snsayer if (ifp->if_snd.ifq_head) { 66363670Snsayer struct mbuf *mb = ifp->if_snd.ifq_head; 66463670Snsayer 665159079Smarius for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 666159079Smarius *(int *)data += mb->m_len; 66783043Sbrooks } else 668159079Smarius *(int *)data = 0; 66963670Snsayer splx(s); 67083043Sbrooks break; 67163670Snsayer 67263670Snsayer case FIOSETOWN: 673159079Smarius return (fsetown(*(int *)data, &tp->tap_sigio)); 67463670Snsayer 67563670Snsayer case FIOGETOWN: 676159079Smarius *(int *)data = fgetown(&tp->tap_sigio); 67763670Snsayer return (0); 67863670Snsayer 67963670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 68063670Snsayer case TIOCSPGRP: 681159079Smarius return (fsetown(-(*(int *)data), &tp->tap_sigio)); 68263670Snsayer 68363670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 68463670Snsayer case TIOCGPGRP: 685159079Smarius *(int *)data = -fgetown(&tp->tap_sigio); 68663670Snsayer return (0); 68763670Snsayer 68863670Snsayer /* VMware/VMnet port ioctl's */ 68963670Snsayer 69063670Snsayer case SIOCGIFFLAGS: /* get ifnet flags */ 69163670Snsayer bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 69283043Sbrooks break; 69363670Snsayer 694162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 695162711Sru defined(COMPAT_FREEBSD4) 696162711Sru case _IO('V', 0): 697162711Sru ival = IOCPARM_IVAL(data); 698162711Sru data = (caddr_t)&ival; 699162711Sru /* FALLTHROUGH */ 700162711Sru#endif 70183043Sbrooks case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 702162711Sru f = *(int *)data; 70363670Snsayer f &= 0x0fff; 70463670Snsayer f &= ~IFF_CANTCHANGE; 70563670Snsayer f |= IFF_UP; 70663670Snsayer 70763670Snsayer s = splimp(); 70863670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 70963670Snsayer splx(s); 71083043Sbrooks break; 71163670Snsayer 71263861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 71363670Snsayer case SIOCGIFADDR: 714127165Srwatson mtx_lock(&tp->tap_mtx); 71563861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 716127165Srwatson mtx_unlock(&tp->tap_mtx); 71783043Sbrooks break; 71863670Snsayer 71963861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 720127165Srwatson mtx_lock(&tp->tap_mtx); 72163861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 722127165Srwatson mtx_unlock(&tp->tap_mtx); 72383043Sbrooks break; 72463670Snsayer 72563670Snsayer default: 72663670Snsayer return (ENOTTY); 72763670Snsayer } 72863670Snsayer return (0); 72963670Snsayer} /* tapioctl */ 73063670Snsayer 73163670Snsayer 73263670Snsayer/* 73363670Snsayer * tapread 73463670Snsayer * 73563670Snsayer * the cdevsw read interface - reads a packet at a time, or at 73663670Snsayer * least as much of a packet as can be read 73763670Snsayer */ 73863670Snsayerstatic int 739156783Semaxtapread(struct cdev *dev, struct uio *uio, int flag) 74063670Snsayer{ 74163670Snsayer struct tap_softc *tp = dev->si_drv1; 742147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 74390227Sdillon struct mbuf *m = NULL; 74463670Snsayer int error = 0, len, s; 74563670Snsayer 746121816Sbrooks TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev)); 74763670Snsayer 748127098Srwatson mtx_lock(&tp->tap_mtx); 74963670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 750127098Srwatson mtx_unlock(&tp->tap_mtx); 751127098Srwatson 752127098Srwatson /* Unlocked read. */ 753121816Sbrooks TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 754121816Sbrooks ifp->if_xname, minor(dev), tp->tap_flags); 75563803Snsayer 75663670Snsayer return (EHOSTDOWN); 75763670Snsayer } 75863670Snsayer 75963670Snsayer tp->tap_flags &= ~TAP_RWAIT; 760127098Srwatson mtx_unlock(&tp->tap_mtx); 76163670Snsayer 76263670Snsayer /* sleep until we get a packet */ 76363670Snsayer do { 76463670Snsayer s = splimp(); 76590227Sdillon IF_DEQUEUE(&ifp->if_snd, m); 76663670Snsayer splx(s); 76763670Snsayer 76890227Sdillon if (m == NULL) { 769139207Sphk if (flag & O_NONBLOCK) 77063670Snsayer return (EWOULDBLOCK); 771111742Sdes 772127098Srwatson mtx_lock(&tp->tap_mtx); 77363670Snsayer tp->tap_flags |= TAP_RWAIT; 774127098Srwatson mtx_unlock(&tp->tap_mtx); 775111748Sdes error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); 77663670Snsayer if (error) 77763670Snsayer return (error); 77863670Snsayer } 77990227Sdillon } while (m == NULL); 78063670Snsayer 78163670Snsayer /* feed packet to bpf */ 782106939Ssam BPF_MTAP(ifp, m); 78363670Snsayer 78463670Snsayer /* xfer packet to user space */ 78590227Sdillon while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 78690227Sdillon len = min(uio->uio_resid, m->m_len); 78763670Snsayer if (len == 0) 78863670Snsayer break; 78963670Snsayer 790111741Sdes error = uiomove(mtod(m, void *), len, uio); 79190227Sdillon m = m_free(m); 79263670Snsayer } 79363670Snsayer 79490227Sdillon if (m != NULL) { 795121816Sbrooks TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 796121816Sbrooks minor(dev)); 79790227Sdillon m_freem(m); 79863670Snsayer } 79963670Snsayer 80063670Snsayer return (error); 80163670Snsayer} /* tapread */ 80263670Snsayer 80363670Snsayer 80463670Snsayer/* 80563670Snsayer * tapwrite 80663670Snsayer * 80763670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 80863670Snsayer */ 80963670Snsayerstatic int 810156783Semaxtapwrite(struct cdev *dev, struct uio *uio, int flag) 81163670Snsayer{ 81263670Snsayer struct tap_softc *tp = dev->si_drv1; 813147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 814137101Sglebius struct mbuf *m; 81563670Snsayer 816121816Sbrooks TAPDEBUG("%s writting, minor = %#x\n", 817121816Sbrooks ifp->if_xname, minor(dev)); 81863670Snsayer 81963670Snsayer if (uio->uio_resid == 0) 82063670Snsayer return (0); 82163670Snsayer 82263670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 823121816Sbrooks TAPDEBUG("%s invalid packet len = %d, minor = %#x\n", 824121816Sbrooks ifp->if_xname, uio->uio_resid, minor(dev)); 82563803Snsayer 82663670Snsayer return (EIO); 82763670Snsayer } 82863670Snsayer 829163915Sandre if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, ETHER_ALIGN, 830163915Sandre M_PKTHDR)) == NULL) { 83163670Snsayer ifp->if_ierrors ++; 832163986Scsjp return (ENOBUFS); 83363670Snsayer } 83463670Snsayer 835137101Sglebius m->m_pkthdr.rcvif = ifp; 836111742Sdes 837106939Ssam /* Pass packet up to parent. */ 838137101Sglebius (*ifp->if_input)(ifp, m); 839106939Ssam ifp->if_ipackets ++; /* ibytes are counted in parent */ 84063670Snsayer 84163670Snsayer return (0); 84263670Snsayer} /* tapwrite */ 84363670Snsayer 84463670Snsayer 84563670Snsayer/* 84663670Snsayer * tappoll 84763670Snsayer * 84863670Snsayer * the poll interface, this is only useful on reads 84963670Snsayer * really. the write detect always returns true, write never blocks 85063670Snsayer * anyway, it either accepts the packet or drops it 85163670Snsayer */ 85263670Snsayerstatic int 853156783Semaxtappoll(struct cdev *dev, int events, struct thread *td) 85463670Snsayer{ 85563670Snsayer struct tap_softc *tp = dev->si_drv1; 856147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 857111742Sdes int s, revents = 0; 85863670Snsayer 859121816Sbrooks TAPDEBUG("%s polling, minor = %#x\n", 860121816Sbrooks ifp->if_xname, minor(dev)); 86163670Snsayer 86263670Snsayer s = splimp(); 86363670Snsayer if (events & (POLLIN | POLLRDNORM)) { 86463670Snsayer if (ifp->if_snd.ifq_len > 0) { 865121816Sbrooks TAPDEBUG("%s have data in queue. len = %d, " \ 866121816Sbrooks "minor = %#x\n", ifp->if_xname, 86783043Sbrooks ifp->if_snd.ifq_len, minor(dev)); 86863803Snsayer 86963670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 87083043Sbrooks } else { 871121816Sbrooks TAPDEBUG("%s waiting for data, minor = %#x\n", 872121816Sbrooks ifp->if_xname, minor(dev)); 87363803Snsayer 87483805Sjhb selrecord(td, &tp->tap_rsel); 87563670Snsayer } 87663670Snsayer } 87763670Snsayer 87863670Snsayer if (events & (POLLOUT | POLLWRNORM)) 87963670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 88063670Snsayer 88163670Snsayer splx(s); 88263670Snsayer return (revents); 88363670Snsayer} /* tappoll */ 884156783Semax 885156783Semax 886156783Semax/* 887156783Semax * tap_kqfilter 888156783Semax * 889156783Semax * support for kevent() system call 890156783Semax */ 891156783Semaxstatic int 892156783Semaxtapkqfilter(struct cdev *dev, struct knote *kn) 893156783Semax{ 894156783Semax int s; 895156783Semax struct tap_softc *tp = dev->si_drv1; 896156783Semax struct ifnet *ifp = tp->tap_ifp; 897156783Semax 898156783Semax s = splimp(); 899156783Semax switch (kn->kn_filter) { 900156783Semax case EVFILT_READ: 901156783Semax TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n", 902156783Semax ifp->if_xname, minor(dev)); 903156783Semax kn->kn_fop = &tap_read_filterops; 904156783Semax break; 905156783Semax 906156783Semax case EVFILT_WRITE: 907156783Semax TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n", 908156783Semax ifp->if_xname, minor(dev)); 909156783Semax kn->kn_fop = &tap_write_filterops; 910156783Semax break; 911156783Semax 912156783Semax default: 913156783Semax TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n", 914156783Semax ifp->if_xname, minor(dev)); 915156783Semax splx(s); 916156783Semax return (EINVAL); 917156783Semax /* NOT REACHED */ 918156783Semax } 919156783Semax splx(s); 920156783Semax 921156783Semax kn->kn_hook = (caddr_t) dev; 922156783Semax knlist_add(&tp->tap_rsel.si_note, kn, 0); 923156783Semax 924156783Semax return (0); 925156783Semax} /* tapkqfilter */ 926156783Semax 927156783Semax 928156783Semax/* 929156783Semax * tap_kqread 930156783Semax * 931156783Semax * Return true if there is data in the interface queue 932156783Semax */ 933156783Semaxstatic int 934156783Semaxtapkqread(struct knote *kn, long hint) 935156783Semax{ 936156783Semax int ret, s; 937156783Semax struct cdev *dev = (struct cdev *)(kn->kn_hook); 938156783Semax struct tap_softc *tp = dev->si_drv1; 939156783Semax struct ifnet *ifp = tp->tap_ifp; 940156783Semax 941156783Semax s = splimp(); 942156783Semax if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) { 943156783Semax TAPDEBUG("%s have data in queue. len = %d, minor = %#x\n", 944156783Semax ifp->if_xname, ifp->if_snd.ifq_len, minor(dev)); 945156783Semax ret = 1; 946156783Semax } else { 947156783Semax TAPDEBUG("%s waiting for data, minor = %#x\n", 948156783Semax ifp->if_xname, minor(dev)); 949156783Semax ret = 0; 950156783Semax } 951156783Semax splx(s); 952156783Semax 953156783Semax return (ret); 954156783Semax} /* tapkqread */ 955156783Semax 956156783Semax 957156783Semax/* 958156783Semax * tap_kqwrite 959156783Semax * 960156783Semax * Always can write. Return the MTU in kn->data 961156783Semax */ 962156783Semaxstatic int 963156783Semaxtapkqwrite(struct knote *kn, long hint) 964156783Semax{ 965156783Semax int s; 966156783Semax struct tap_softc *tp = ((struct cdev *) kn->kn_hook)->si_drv1; 967156783Semax struct ifnet *ifp = tp->tap_ifp; 968156783Semax 969156783Semax s = splimp(); 970156783Semax kn->kn_data = ifp->if_mtu; 971156783Semax splx(s); 972156783Semax 973156783Semax return (1); 974156783Semax} /* tapkqwrite */ 975156783Semax 976156783Semax 977156783Semaxstatic void 978156783Semaxtapkqdetach(struct knote *kn) 979156783Semax{ 980156783Semax struct tap_softc *tp = ((struct cdev *) kn->kn_hook)->si_drv1; 981156783Semax 982156783Semax knlist_remove(&tp->tap_rsel.si_note, kn, 0); 983156783Semax} /* tapkqdetach */ 984156783Semax 985