if_tap.c revision 166443
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 166443 2007-02-03 02:57:45Z 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> 65152315Sru#include <net/if_dl.h> 6663670Snsayer#include <net/route.h> 67147256Sbrooks#include <net/if_types.h> 6863670Snsayer 6963670Snsayer#include <netinet/in.h> 7063670Snsayer 7163670Snsayer#include <net/if_tapvar.h> 7263670Snsayer#include <net/if_tap.h> 7363670Snsayer 7463670Snsayer 7563670Snsayer#define CDEV_NAME "tap" 7663670Snsayer#define TAPDEBUG if (tapdebug) printf 7763670Snsayer 7863670Snsayer#define TAP "tap" 7963670Snsayer#define VMNET "vmnet" 8083043Sbrooks#define TAPMAXUNIT 0x7fff 81126077Sphk#define VMNET_DEV_MASK CLONE_FLAG0 8263670Snsayer 8363670Snsayer/* module */ 84111742Sdesstatic int tapmodevent(module_t, int, void *); 8563670Snsayer 8663670Snsayer/* device */ 87148868Srwatsonstatic void tapclone(void *, struct ucred *, char *, int, 88148868Srwatson struct cdev **); 89130585Sphkstatic void tapcreate(struct cdev *); 9063670Snsayer 9163670Snsayer/* network interface */ 9293084Sbdestatic void tapifstart(struct ifnet *); 9393084Sbdestatic int tapifioctl(struct ifnet *, u_long, caddr_t); 9493084Sbdestatic void tapifinit(void *); 9563670Snsayer 9663670Snsayer/* character device */ 9763670Snsayerstatic d_open_t tapopen; 9863670Snsayerstatic d_close_t tapclose; 9963670Snsayerstatic d_read_t tapread; 10063670Snsayerstatic d_write_t tapwrite; 10163670Snsayerstatic d_ioctl_t tapioctl; 10263670Snsayerstatic d_poll_t tappoll; 103156783Semaxstatic d_kqfilter_t tapkqfilter; 10463670Snsayer 105156783Semax/* kqueue(2) */ 106156783Semaxstatic int tapkqread(struct knote *, long); 107156783Semaxstatic int tapkqwrite(struct knote *, long); 108156783Semaxstatic void tapkqdetach(struct knote *); 109156783Semax 110156783Semaxstatic struct filterops tap_read_filterops = { 111156783Semax .f_isfd = 1, 112156783Semax .f_attach = NULL, 113156783Semax .f_detach = tapkqdetach, 114156783Semax .f_event = tapkqread, 115156783Semax}; 116156783Semax 117156783Semaxstatic struct filterops tap_write_filterops = { 118156783Semax .f_isfd = 1, 119156783Semax .f_attach = NULL, 120156783Semax .f_detach = tapkqdetach, 121156783Semax .f_event = tapkqwrite, 122156783Semax}; 123156783Semax 12463670Snsayerstatic struct cdevsw tap_cdevsw = { 125126080Sphk .d_version = D_VERSION, 126126188Sbde .d_flags = D_PSEUDO | D_NEEDGIANT, 127111815Sphk .d_open = tapopen, 128111815Sphk .d_close = tapclose, 129111815Sphk .d_read = tapread, 130111815Sphk .d_write = tapwrite, 131111815Sphk .d_ioctl = tapioctl, 132111815Sphk .d_poll = tappoll, 133111815Sphk .d_name = CDEV_NAME, 134156783Semax .d_kqfilter = tapkqfilter, 13563670Snsayer}; 13663670Snsayer 137127003Srwatson/* 138127003Srwatson * All global variables in if_tap.c are locked with tapmtx, with the 139127003Srwatson * exception of tapdebug, which is accessed unlocked; tapclones is 140127003Srwatson * static at runtime. 141127003Srwatson */ 142127003Srwatsonstatic struct mtx tapmtx; 14383043Sbrooksstatic int tapdebug = 0; /* debug flag */ 144144979Smdoddstatic int tapuopen = 0; /* allow user open() */ 14583043Sbrooksstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 146126077Sphkstatic struct clonedevs *tapclones; 14763670Snsayer 14863670SnsayerMALLOC_DECLARE(M_TAP); 14963670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 15063670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 151144979Smdodd 152144979SmdoddSYSCTL_DECL(_net_link); 153144979SmdoddSYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0, 154144979Smdodd "Ethernet tunnel software network interface"); 155144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0, 156144979Smdodd "Allow user to open /dev/tap (based on node permissions)"); 157144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, ""); 158144979Smdodd 15963670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL); 16063670Snsayer 16163670Snsayer/* 16263670Snsayer * tapmodevent 16363670Snsayer * 16463670Snsayer * module event handler 16563670Snsayer */ 16663670Snsayerstatic int 167156783Semaxtapmodevent(module_t mod, int type, void *data) 16863670Snsayer{ 16983043Sbrooks static eventhandler_tag eh_tag = NULL; 17083043Sbrooks struct tap_softc *tp = NULL; 17183043Sbrooks struct ifnet *ifp = NULL; 172126077Sphk int s; 17363670Snsayer 17463670Snsayer switch (type) { 17563670Snsayer case MOD_LOAD: 17663670Snsayer 17783043Sbrooks /* intitialize device */ 17883043Sbrooks 179127003Srwatson mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF); 18083043Sbrooks SLIST_INIT(&taphead); 18183043Sbrooks 182126845Sphk clone_setup(&tapclones); 18371602Sphk eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 184127003Srwatson if (eh_tag == NULL) { 185127170Srwatson clone_cleanup(&tapclones); 186127003Srwatson mtx_destroy(&tapmtx); 187126077Sphk return (ENOMEM); 188127003Srwatson } 18983043Sbrooks return (0); 19063670Snsayer 19183043Sbrooks case MOD_UNLOAD: 192127003Srwatson /* 193127003Srwatson * The EBUSY algorithm here can't quite atomically 194127003Srwatson * guarantee that this is race-free since we have to 195127003Srwatson * release the tap mtx to deregister the clone handler. 196127003Srwatson */ 197127003Srwatson mtx_lock(&tapmtx); 198127003Srwatson SLIST_FOREACH(tp, &taphead, tap_next) { 199127098Srwatson mtx_lock(&tp->tap_mtx); 200127003Srwatson if (tp->tap_flags & TAP_OPEN) { 201127098Srwatson mtx_unlock(&tp->tap_mtx); 202127003Srwatson mtx_unlock(&tapmtx); 20383043Sbrooks return (EBUSY); 204127003Srwatson } 205127098Srwatson mtx_unlock(&tp->tap_mtx); 206127003Srwatson } 207127003Srwatson mtx_unlock(&tapmtx); 20883043Sbrooks 20971602Sphk EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 21063670Snsayer 211127003Srwatson mtx_lock(&tapmtx); 21283043Sbrooks while ((tp = SLIST_FIRST(&taphead)) != NULL) { 21383043Sbrooks SLIST_REMOVE_HEAD(&taphead, tap_next); 214127003Srwatson mtx_unlock(&tapmtx); 21583043Sbrooks 216147256Sbrooks ifp = tp->tap_ifp; 21783043Sbrooks 218121816Sbrooks TAPDEBUG("detaching %s\n", ifp->if_xname); 21983043Sbrooks 220127098Srwatson /* Unlocked read. */ 221121816Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 222121816Sbrooks ("%s flags is out of sync", ifp->if_xname)); 22383043Sbrooks 224158697Semax knlist_destroy(&tp->tap_rsel.si_note); 225126077Sphk destroy_dev(tp->tap_dev); 22663670Snsayer s = splimp(); 227106939Ssam ether_ifdetach(ifp); 228147256Sbrooks if_free_type(ifp, IFT_ETHER); 22963670Snsayer splx(s); 23063670Snsayer 231127098Srwatson mtx_destroy(&tp->tap_mtx); 23293752Sluigi free(tp, M_TAP); 233127003Srwatson mtx_lock(&tapmtx); 23483043Sbrooks } 235127003Srwatson mtx_unlock(&tapmtx); 236126077Sphk clone_cleanup(&tapclones); 23763670Snsayer 238135354Srwatson mtx_destroy(&tapmtx); 239135354Srwatson 24083043Sbrooks break; 24163670Snsayer 24263670Snsayer default: 24363670Snsayer return (EOPNOTSUPP); 24463670Snsayer } 24563670Snsayer 24663670Snsayer return (0); 24763670Snsayer} /* tapmodevent */ 24863670Snsayer 24963670Snsayer 25063670Snsayer/* 25171602Sphk * DEVFS handler 25271602Sphk * 25371602Sphk * We need to support two kind of devices - tap and vmnet 25471602Sphk */ 25571602Sphkstatic void 256156783Semaxtapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev) 25771602Sphk{ 258166438Sbms int extra; 259126077Sphk int i, unit; 26083043Sbrooks char *device_name = name; 26171602Sphk 262130640Sphk if (*dev != NULL) 26371602Sphk return; 26471602Sphk 265126077Sphk device_name = TAP; 266126077Sphk extra = 0; 267126077Sphk if (strcmp(name, TAP) == 0) { 268126077Sphk unit = -1; 269126077Sphk } else if (strcmp(name, VMNET) == 0) { 270126077Sphk device_name = VMNET; 271126077Sphk extra = VMNET_DEV_MASK; 272126077Sphk unit = -1; 273126077Sphk } else if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 274126077Sphk device_name = VMNET; 275126077Sphk extra = VMNET_DEV_MASK; 276126077Sphk if (dev_stdclone(name, NULL, device_name, &unit) != 1) 277126077Sphk return; 27883043Sbrooks } 27971602Sphk 280126077Sphk /* find any existing device, or allocate new unit number */ 281126077Sphk i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra); 282126077Sphk if (i) { 283126796Sphk *dev = make_dev(&tap_cdevsw, unit2minor(unit | extra), 284126077Sphk UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit); 285144389Sphk if (*dev != NULL) { 286144389Sphk dev_ref(*dev); 287126077Sphk (*dev)->si_flags |= SI_CHEAPCLONE; 288144389Sphk } 28971602Sphk } 29071602Sphk} /* tapclone */ 29171602Sphk 29271602Sphk 29371602Sphk/* 29463670Snsayer * tapcreate 29563670Snsayer * 29663670Snsayer * to create interface 29763670Snsayer */ 29863670Snsayerstatic void 299156783Semaxtapcreate(struct cdev *dev) 30063670Snsayer{ 30163670Snsayer struct ifnet *ifp = NULL; 30263670Snsayer struct tap_softc *tp = NULL; 30363670Snsayer unsigned short macaddr_hi; 30463803Snsayer int unit, s; 30563670Snsayer char *name = NULL; 306147256Sbrooks u_char eaddr[6]; 30763670Snsayer 308126077Sphk dev->si_flags &= ~SI_CHEAPCLONE; 309126077Sphk 31063670Snsayer /* allocate driver storage and create device */ 311111119Simp MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 312127098Srwatson mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF); 313127003Srwatson mtx_lock(&tapmtx); 31483043Sbrooks SLIST_INSERT_HEAD(&taphead, tp, tap_next); 315127003Srwatson mtx_unlock(&tapmtx); 31663670Snsayer 317126796Sphk unit = dev2unit(dev); 31883043Sbrooks 31963670Snsayer /* select device: tap or vmnet */ 320126796Sphk if (unit & VMNET_DEV_MASK) { 32163670Snsayer name = VMNET; 32263803Snsayer tp->tap_flags |= TAP_VMNET; 32383043Sbrooks } else 32463670Snsayer name = TAP; 32563670Snsayer 326126796Sphk unit &= TAPMAXUNIT; 327126796Sphk 32883043Sbrooks TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 32983043Sbrooks 33063670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 33163670Snsayer macaddr_hi = htons(0x00bd); 332147256Sbrooks bcopy(&macaddr_hi, eaddr, sizeof(short)); 333147256Sbrooks bcopy(&ticks, &eaddr[2], sizeof(long)); 334147256Sbrooks eaddr[5] = (u_char)unit; 33563670Snsayer 336111742Sdes /* fill the rest and attach interface */ 337147256Sbrooks ifp = tp->tap_ifp = if_alloc(IFT_ETHER); 338147256Sbrooks if (ifp == NULL) 339147256Sbrooks panic("%s%d: can not if_alloc()", name, unit); 34063670Snsayer ifp->if_softc = tp; 341121816Sbrooks if_initname(ifp, name, unit); 34263670Snsayer ifp->if_init = tapifinit; 34363670Snsayer ifp->if_start = tapifstart; 34463670Snsayer ifp->if_ioctl = tapifioctl; 34563670Snsayer ifp->if_mtu = ETHERMTU; 34663670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 34763670Snsayer ifp->if_snd.ifq_maxlen = ifqmaxlen; 34863670Snsayer 34983043Sbrooks dev->si_drv1 = tp; 350126077Sphk tp->tap_dev = dev; 35183043Sbrooks 35263803Snsayer s = splimp(); 353147256Sbrooks ether_ifattach(ifp, eaddr); 35463803Snsayer splx(s); 35563670Snsayer 356127098Srwatson mtx_lock(&tp->tap_mtx); 35763803Snsayer tp->tap_flags |= TAP_INITED; 358127098Srwatson mtx_unlock(&tp->tap_mtx); 35963803Snsayer 360158697Semax knlist_init(&tp->tap_rsel.si_note, NULL, NULL, NULL, NULL); 361158697Semax 362121816Sbrooks TAPDEBUG("interface %s is created. minor = %#x\n", 363121816Sbrooks ifp->if_xname, minor(dev)); 36463670Snsayer} /* tapcreate */ 36563670Snsayer 36663670Snsayer 36763670Snsayer/* 368111742Sdes * tapopen 36963670Snsayer * 37063670Snsayer * to open tunnel. must be superuser 37163670Snsayer */ 37263670Snsayerstatic int 373156783Semaxtapopen(struct cdev *dev, int flag, int mode, struct thread *td) 37463670Snsayer{ 37563670Snsayer struct tap_softc *tp = NULL; 376133460Semax struct ifnet *ifp = NULL; 377164033Srwatson int error, s; 37863670Snsayer 379164033Srwatson if (tapuopen == 0) { 380164033Srwatson error = priv_check(td, PRIV_NET_TAP); 381164033Srwatson if (error) 382164033Srwatson return (error); 383164033Srwatson } 38463670Snsayer 385126796Sphk if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT) 386126796Sphk return (ENXIO); 38783043Sbrooks 388127165Srwatson /* 389127165Srwatson * XXXRW: Non-atomic test-and-set of si_drv1. Currently protected 390127165Srwatson * by Giant, but the race actually exists under memory pressure as 391127165Srwatson * well even when running with Giant, as malloc() may sleep. 392127165Srwatson */ 39363670Snsayer tp = dev->si_drv1; 39463670Snsayer if (tp == NULL) { 39563670Snsayer tapcreate(dev); 39663670Snsayer tp = dev->si_drv1; 39763670Snsayer } 39863670Snsayer 399127165Srwatson mtx_lock(&tp->tap_mtx); 400127165Srwatson if (tp->tap_flags & TAP_OPEN) { 401127165Srwatson mtx_unlock(&tp->tap_mtx); 402127165Srwatson return (EBUSY); 403127165Srwatson } 40463670Snsayer 405152315Sru bcopy(IF_LLADDR(tp->tap_ifp), tp->ether_addr, sizeof(tp->ether_addr)); 40683366Sjulian tp->tap_pid = td->td_proc->p_pid; 40763670Snsayer tp->tap_flags |= TAP_OPEN; 408147256Sbrooks ifp = tp->tap_ifp; 409127098Srwatson mtx_unlock(&tp->tap_mtx); 41063670Snsayer 411133460Semax s = splimp(); 412148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 413148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 414133460Semax splx(s); 41563670Snsayer 416133460Semax TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev)); 417133460Semax 41863670Snsayer return (0); 41963670Snsayer} /* tapopen */ 42063670Snsayer 42163670Snsayer 42263670Snsayer/* 42363670Snsayer * tapclose 42463670Snsayer * 42563670Snsayer * close the device - mark i/f down & delete routing info 42663670Snsayer */ 42763670Snsayerstatic int 428156783Semaxtapclose(struct cdev *dev, int foo, int bar, struct thread *td) 42963670Snsayer{ 430156783Semax struct ifaddr *ifa; 43163670Snsayer struct tap_softc *tp = dev->si_drv1; 432147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 433126077Sphk int s; 43463670Snsayer 43563670Snsayer /* junk all pending output */ 43683043Sbrooks IF_DRAIN(&ifp->if_snd); 43763670Snsayer 43863803Snsayer /* 43963803Snsayer * do not bring the interface down, and do not anything with 44063803Snsayer * interface, if we are in VMnet mode. just close the device. 44163803Snsayer */ 44263803Snsayer 443127098Srwatson mtx_lock(&tp->tap_mtx); 44463803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 445127098Srwatson mtx_unlock(&tp->tap_mtx); 44663670Snsayer s = splimp(); 44763670Snsayer if_down(ifp); 448148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 44963803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 450146620Speadar rtinit(ifa, (int)RTM_DELETE, 0); 45163670Snsayer } 452146620Speadar if_purgeaddrs(ifp); 453148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 45463670Snsayer } 45563670Snsayer splx(s); 456127098Srwatson } else 457127098Srwatson mtx_unlock(&tp->tap_mtx); 45863670Snsayer 45996122Salfred funsetown(&tp->tap_sigio); 460122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 461156783Semax KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0); 46263670Snsayer 463127098Srwatson mtx_lock(&tp->tap_mtx); 46463670Snsayer tp->tap_flags &= ~TAP_OPEN; 46563670Snsayer tp->tap_pid = 0; 466127098Srwatson mtx_unlock(&tp->tap_mtx); 46763670Snsayer 468121816Sbrooks TAPDEBUG("%s is closed. minor = %#x\n", 469121816Sbrooks ifp->if_xname, minor(dev)); 47063670Snsayer 47163670Snsayer return (0); 47263670Snsayer} /* tapclose */ 47363670Snsayer 47463670Snsayer 47563670Snsayer/* 47663670Snsayer * tapifinit 47763670Snsayer * 47863670Snsayer * network interface initialization function 47963670Snsayer */ 48063670Snsayerstatic void 481156783Semaxtapifinit(void *xtp) 48263670Snsayer{ 48363670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 484147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 48563670Snsayer 486121816Sbrooks TAPDEBUG("initializing %s\n", ifp->if_xname); 48763670Snsayer 488148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 489148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 49063670Snsayer 49163670Snsayer /* attempt to start output */ 49263670Snsayer tapifstart(ifp); 49363670Snsayer} /* tapifinit */ 49463670Snsayer 49563670Snsayer 49663670Snsayer/* 49763670Snsayer * tapifioctl 49863670Snsayer * 49963670Snsayer * Process an ioctl request on network interface 50063670Snsayer */ 501105228Sphkstatic int 502156783Semaxtapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 50363670Snsayer{ 504160376Sbrooks struct tap_softc *tp = ifp->if_softc; 50563670Snsayer struct ifstat *ifs = NULL; 50663670Snsayer int s, dummy; 50763670Snsayer 50863670Snsayer switch (cmd) { 50963670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 51063670Snsayer case SIOCADDMULTI: 51163670Snsayer case SIOCDELMULTI: 51283043Sbrooks break; 51363670Snsayer 51463670Snsayer case SIOCGIFSTATUS: 51563670Snsayer s = splimp(); 51663670Snsayer ifs = (struct ifstat *)data; 51763670Snsayer dummy = strlen(ifs->ascii); 518127098Srwatson mtx_lock(&tp->tap_mtx); 51963670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 52063670Snsayer snprintf(ifs->ascii + dummy, 52163670Snsayer sizeof(ifs->ascii) - dummy, 52263670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 523127098Srwatson mtx_unlock(&tp->tap_mtx); 52463670Snsayer splx(s); 52583043Sbrooks break; 52663670Snsayer 52763670Snsayer default: 528106939Ssam s = splimp(); 529106939Ssam dummy = ether_ioctl(ifp, cmd, data); 530106939Ssam splx(s); 531106939Ssam return (dummy); 532156783Semax /* NOT REACHED */ 53363670Snsayer } 53463670Snsayer 53563670Snsayer return (0); 53663670Snsayer} /* tapifioctl */ 53763670Snsayer 53863670Snsayer 53963670Snsayer/* 540111742Sdes * tapifstart 541111742Sdes * 54263670Snsayer * queue packets from higher level ready to put out 54363670Snsayer */ 54463670Snsayerstatic void 545156783Semaxtapifstart(struct ifnet *ifp) 54663670Snsayer{ 54763670Snsayer struct tap_softc *tp = ifp->if_softc; 54863670Snsayer int s; 54963670Snsayer 550121816Sbrooks TAPDEBUG("%s starting\n", ifp->if_xname); 55163670Snsayer 55263803Snsayer /* 55363803Snsayer * do not junk pending output if we are in VMnet mode. 55463803Snsayer * XXX: can this do any harm because of queue overflow? 55563803Snsayer */ 55663803Snsayer 557127098Srwatson mtx_lock(&tp->tap_mtx); 558111742Sdes if (((tp->tap_flags & TAP_VMNET) == 0) && 55963803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 56063670Snsayer struct mbuf *m = NULL; 56163670Snsayer 562127098Srwatson mtx_unlock(&tp->tap_mtx); 563127098Srwatson 564127098Srwatson /* Unlocked read. */ 565121816Sbrooks TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 566121816Sbrooks tp->tap_flags); 56763670Snsayer 56863670Snsayer s = splimp(); 56963670Snsayer do { 57063670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 57163670Snsayer if (m != NULL) 57263670Snsayer m_freem(m); 57363670Snsayer ifp->if_oerrors ++; 57463670Snsayer } while (m != NULL); 57563670Snsayer splx(s); 57663670Snsayer 57763670Snsayer return; 57863670Snsayer } 579127098Srwatson mtx_unlock(&tp->tap_mtx); 58063670Snsayer 58163670Snsayer s = splimp(); 582148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 58363670Snsayer 58463670Snsayer if (ifp->if_snd.ifq_len != 0) { 585127098Srwatson mtx_lock(&tp->tap_mtx); 58663670Snsayer if (tp->tap_flags & TAP_RWAIT) { 58763670Snsayer tp->tap_flags &= ~TAP_RWAIT; 588111748Sdes wakeup(tp); 58963670Snsayer } 59063670Snsayer 591127098Srwatson if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) { 592127098Srwatson mtx_unlock(&tp->tap_mtx); 59395883Salfred pgsigio(&tp->tap_sigio, SIGIO, 0); 594127098Srwatson } else 595127098Srwatson mtx_unlock(&tp->tap_mtx); 59663670Snsayer 597122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 598156783Semax KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0); 59963670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 60063670Snsayer } 60163670Snsayer 602148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 60363670Snsayer splx(s); 60463670Snsayer} /* tapifstart */ 60563670Snsayer 60663670Snsayer 60763670Snsayer/* 60863670Snsayer * tapioctl 60963670Snsayer * 61063670Snsayer * the cdevsw interface is now pretty minimal 61163670Snsayer */ 61263670Snsayerstatic int 613156783Semaxtapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 61463670Snsayer{ 61563670Snsayer struct tap_softc *tp = dev->si_drv1; 616147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 617111742Sdes struct tapinfo *tapp = NULL; 61863670Snsayer int s; 619102052Ssobomax int f; 620162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 621162711Sru defined(COMPAT_FREEBSD4) 622162711Sru int ival; 623162711Sru#endif 62463670Snsayer 62563670Snsayer switch (cmd) { 626111742Sdes case TAPSIFINFO: 62763670Snsayer s = splimp(); 628111742Sdes tapp = (struct tapinfo *)data; 629111742Sdes ifp->if_mtu = tapp->mtu; 630111742Sdes ifp->if_type = tapp->type; 631111742Sdes ifp->if_baudrate = tapp->baudrate; 63263670Snsayer splx(s); 633111742Sdes break; 63463670Snsayer 635111742Sdes case TAPGIFINFO: 636111742Sdes tapp = (struct tapinfo *)data; 637111742Sdes tapp->mtu = ifp->if_mtu; 638111742Sdes tapp->type = ifp->if_type; 639111742Sdes tapp->baudrate = ifp->if_baudrate; 640111742Sdes break; 64163670Snsayer 64263670Snsayer case TAPSDEBUG: 643159079Smarius tapdebug = *(int *)data; 64483043Sbrooks break; 64563670Snsayer 64663670Snsayer case TAPGDEBUG: 647159079Smarius *(int *)data = tapdebug; 64883043Sbrooks break; 64963670Snsayer 65063670Snsayer case FIONBIO: 65183043Sbrooks break; 65263670Snsayer 65363670Snsayer case FIOASYNC: 65463803Snsayer s = splimp(); 655127098Srwatson mtx_lock(&tp->tap_mtx); 656159079Smarius if (*(int *)data) 65763670Snsayer tp->tap_flags |= TAP_ASYNC; 65863670Snsayer else 65963670Snsayer tp->tap_flags &= ~TAP_ASYNC; 660127098Srwatson mtx_unlock(&tp->tap_mtx); 66163803Snsayer splx(s); 66283043Sbrooks break; 66363670Snsayer 66463670Snsayer case FIONREAD: 66563670Snsayer s = splimp(); 66663670Snsayer if (ifp->if_snd.ifq_head) { 66763670Snsayer struct mbuf *mb = ifp->if_snd.ifq_head; 66863670Snsayer 669159079Smarius for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 670159079Smarius *(int *)data += mb->m_len; 67183043Sbrooks } else 672159079Smarius *(int *)data = 0; 67363670Snsayer splx(s); 67483043Sbrooks break; 67563670Snsayer 67663670Snsayer case FIOSETOWN: 677159079Smarius return (fsetown(*(int *)data, &tp->tap_sigio)); 67863670Snsayer 67963670Snsayer case FIOGETOWN: 680159079Smarius *(int *)data = fgetown(&tp->tap_sigio); 68163670Snsayer return (0); 68263670Snsayer 68363670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 68463670Snsayer case TIOCSPGRP: 685159079Smarius return (fsetown(-(*(int *)data), &tp->tap_sigio)); 68663670Snsayer 68763670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 68863670Snsayer case TIOCGPGRP: 689159079Smarius *(int *)data = -fgetown(&tp->tap_sigio); 69063670Snsayer return (0); 69163670Snsayer 69263670Snsayer /* VMware/VMnet port ioctl's */ 69363670Snsayer 69463670Snsayer case SIOCGIFFLAGS: /* get ifnet flags */ 69563670Snsayer bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 69683043Sbrooks break; 69763670Snsayer 698162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 699162711Sru defined(COMPAT_FREEBSD4) 700162711Sru case _IO('V', 0): 701162711Sru ival = IOCPARM_IVAL(data); 702162711Sru data = (caddr_t)&ival; 703162711Sru /* FALLTHROUGH */ 704162711Sru#endif 70583043Sbrooks case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 706162711Sru f = *(int *)data; 70763670Snsayer f &= 0x0fff; 70863670Snsayer f &= ~IFF_CANTCHANGE; 70963670Snsayer f |= IFF_UP; 71063670Snsayer 71163670Snsayer s = splimp(); 71263670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 71363670Snsayer splx(s); 71483043Sbrooks break; 71563670Snsayer 71663861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 71763670Snsayer case SIOCGIFADDR: 718127165Srwatson mtx_lock(&tp->tap_mtx); 71963861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 720127165Srwatson mtx_unlock(&tp->tap_mtx); 72183043Sbrooks break; 72263670Snsayer 72363861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 724127165Srwatson mtx_lock(&tp->tap_mtx); 72563861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 726127165Srwatson mtx_unlock(&tp->tap_mtx); 72783043Sbrooks break; 72863670Snsayer 72963670Snsayer default: 73063670Snsayer return (ENOTTY); 73163670Snsayer } 73263670Snsayer return (0); 73363670Snsayer} /* tapioctl */ 73463670Snsayer 73563670Snsayer 73663670Snsayer/* 73763670Snsayer * tapread 73863670Snsayer * 73963670Snsayer * the cdevsw read interface - reads a packet at a time, or at 74063670Snsayer * least as much of a packet as can be read 74163670Snsayer */ 74263670Snsayerstatic int 743156783Semaxtapread(struct cdev *dev, struct uio *uio, int flag) 74463670Snsayer{ 74563670Snsayer struct tap_softc *tp = dev->si_drv1; 746147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 74790227Sdillon struct mbuf *m = NULL; 74863670Snsayer int error = 0, len, s; 74963670Snsayer 750121816Sbrooks TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev)); 75163670Snsayer 752127098Srwatson mtx_lock(&tp->tap_mtx); 75363670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 754127098Srwatson mtx_unlock(&tp->tap_mtx); 755127098Srwatson 756127098Srwatson /* Unlocked read. */ 757121816Sbrooks TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 758121816Sbrooks ifp->if_xname, minor(dev), tp->tap_flags); 75963803Snsayer 76063670Snsayer return (EHOSTDOWN); 76163670Snsayer } 76263670Snsayer 76363670Snsayer tp->tap_flags &= ~TAP_RWAIT; 764127098Srwatson mtx_unlock(&tp->tap_mtx); 76563670Snsayer 76663670Snsayer /* sleep until we get a packet */ 76763670Snsayer do { 76863670Snsayer s = splimp(); 76990227Sdillon IF_DEQUEUE(&ifp->if_snd, m); 77063670Snsayer splx(s); 77163670Snsayer 77290227Sdillon if (m == NULL) { 773139207Sphk if (flag & O_NONBLOCK) 77463670Snsayer return (EWOULDBLOCK); 775111742Sdes 776127098Srwatson mtx_lock(&tp->tap_mtx); 77763670Snsayer tp->tap_flags |= TAP_RWAIT; 778127098Srwatson mtx_unlock(&tp->tap_mtx); 779111748Sdes error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); 78063670Snsayer if (error) 78163670Snsayer return (error); 78263670Snsayer } 78390227Sdillon } while (m == NULL); 78463670Snsayer 78563670Snsayer /* feed packet to bpf */ 786106939Ssam BPF_MTAP(ifp, m); 78763670Snsayer 78863670Snsayer /* xfer packet to user space */ 78990227Sdillon while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 79090227Sdillon len = min(uio->uio_resid, m->m_len); 79163670Snsayer if (len == 0) 79263670Snsayer break; 79363670Snsayer 794111741Sdes error = uiomove(mtod(m, void *), len, uio); 79590227Sdillon m = m_free(m); 79663670Snsayer } 79763670Snsayer 79890227Sdillon if (m != NULL) { 799121816Sbrooks TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 800121816Sbrooks minor(dev)); 80190227Sdillon m_freem(m); 80263670Snsayer } 80363670Snsayer 80463670Snsayer return (error); 80563670Snsayer} /* tapread */ 80663670Snsayer 80763670Snsayer 80863670Snsayer/* 80963670Snsayer * tapwrite 81063670Snsayer * 81163670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 81263670Snsayer */ 81363670Snsayerstatic int 814156783Semaxtapwrite(struct cdev *dev, struct uio *uio, int flag) 81563670Snsayer{ 816166443Sbms struct ether_header *eh; 81763670Snsayer struct tap_softc *tp = dev->si_drv1; 818147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 819137101Sglebius struct mbuf *m; 82063670Snsayer 821121816Sbrooks TAPDEBUG("%s writting, minor = %#x\n", 822121816Sbrooks ifp->if_xname, minor(dev)); 82363670Snsayer 82463670Snsayer if (uio->uio_resid == 0) 82563670Snsayer return (0); 82663670Snsayer 82763670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 828121816Sbrooks TAPDEBUG("%s invalid packet len = %d, minor = %#x\n", 829121816Sbrooks ifp->if_xname, uio->uio_resid, minor(dev)); 83063803Snsayer 83163670Snsayer return (EIO); 83263670Snsayer } 83363670Snsayer 834163915Sandre if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, ETHER_ALIGN, 835163915Sandre M_PKTHDR)) == NULL) { 83663670Snsayer ifp->if_ierrors ++; 837163986Scsjp return (ENOBUFS); 83863670Snsayer } 83963670Snsayer 840137101Sglebius m->m_pkthdr.rcvif = ifp; 841111742Sdes 842166443Sbms /* 843166443Sbms * Only pass a unicast frame to ether_input(), if it would actually 844166443Sbms * have been received by non-virtual hardware. 845166443Sbms */ 846166443Sbms if (m->m_len < sizeof(struct ether_header)) { 847166443Sbms m_freem(m); 848166443Sbms return (0); 849166443Sbms } 850166443Sbms eh = mtod(m, struct ether_header *); 851166443Sbms 852166443Sbms if (eh && (ifp->if_flags & IFF_PROMISC) == 0 && 853166443Sbms !ETHER_IS_MULTICAST(eh->ether_dhost) && 854166443Sbms bcmp(eh->ether_dhost, IF_LLADDR(ifp), ETHER_ADDR_LEN) != 0) { 855166443Sbms m_freem(m); 856166443Sbms return (0); 857166443Sbms } 858166443Sbms 859106939Ssam /* Pass packet up to parent. */ 860137101Sglebius (*ifp->if_input)(ifp, m); 861106939Ssam ifp->if_ipackets ++; /* ibytes are counted in parent */ 86263670Snsayer 86363670Snsayer return (0); 86463670Snsayer} /* tapwrite */ 86563670Snsayer 86663670Snsayer 86763670Snsayer/* 86863670Snsayer * tappoll 86963670Snsayer * 87063670Snsayer * the poll interface, this is only useful on reads 87163670Snsayer * really. the write detect always returns true, write never blocks 87263670Snsayer * anyway, it either accepts the packet or drops it 87363670Snsayer */ 87463670Snsayerstatic int 875156783Semaxtappoll(struct cdev *dev, int events, struct thread *td) 87663670Snsayer{ 87763670Snsayer struct tap_softc *tp = dev->si_drv1; 878147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 879111742Sdes int s, revents = 0; 88063670Snsayer 881121816Sbrooks TAPDEBUG("%s polling, minor = %#x\n", 882121816Sbrooks ifp->if_xname, minor(dev)); 88363670Snsayer 88463670Snsayer s = splimp(); 88563670Snsayer if (events & (POLLIN | POLLRDNORM)) { 88663670Snsayer if (ifp->if_snd.ifq_len > 0) { 887121816Sbrooks TAPDEBUG("%s have data in queue. len = %d, " \ 888121816Sbrooks "minor = %#x\n", ifp->if_xname, 88983043Sbrooks ifp->if_snd.ifq_len, minor(dev)); 89063803Snsayer 89163670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 89283043Sbrooks } else { 893121816Sbrooks TAPDEBUG("%s waiting for data, minor = %#x\n", 894121816Sbrooks ifp->if_xname, minor(dev)); 89563803Snsayer 89683805Sjhb selrecord(td, &tp->tap_rsel); 89763670Snsayer } 89863670Snsayer } 89963670Snsayer 90063670Snsayer if (events & (POLLOUT | POLLWRNORM)) 90163670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 90263670Snsayer 90363670Snsayer splx(s); 90463670Snsayer return (revents); 90563670Snsayer} /* tappoll */ 906156783Semax 907156783Semax 908156783Semax/* 909156783Semax * tap_kqfilter 910156783Semax * 911156783Semax * support for kevent() system call 912156783Semax */ 913156783Semaxstatic int 914156783Semaxtapkqfilter(struct cdev *dev, struct knote *kn) 915156783Semax{ 916156783Semax int s; 917156783Semax struct tap_softc *tp = dev->si_drv1; 918156783Semax struct ifnet *ifp = tp->tap_ifp; 919156783Semax 920156783Semax s = splimp(); 921156783Semax switch (kn->kn_filter) { 922156783Semax case EVFILT_READ: 923156783Semax TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n", 924156783Semax ifp->if_xname, minor(dev)); 925156783Semax kn->kn_fop = &tap_read_filterops; 926156783Semax break; 927156783Semax 928156783Semax case EVFILT_WRITE: 929156783Semax TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n", 930156783Semax ifp->if_xname, minor(dev)); 931156783Semax kn->kn_fop = &tap_write_filterops; 932156783Semax break; 933156783Semax 934156783Semax default: 935156783Semax TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n", 936156783Semax ifp->if_xname, minor(dev)); 937156783Semax splx(s); 938156783Semax return (EINVAL); 939156783Semax /* NOT REACHED */ 940156783Semax } 941156783Semax splx(s); 942156783Semax 943156783Semax kn->kn_hook = (caddr_t) dev; 944156783Semax knlist_add(&tp->tap_rsel.si_note, kn, 0); 945156783Semax 946156783Semax return (0); 947156783Semax} /* tapkqfilter */ 948156783Semax 949156783Semax 950156783Semax/* 951156783Semax * tap_kqread 952156783Semax * 953156783Semax * Return true if there is data in the interface queue 954156783Semax */ 955156783Semaxstatic int 956156783Semaxtapkqread(struct knote *kn, long hint) 957156783Semax{ 958156783Semax int ret, s; 959156783Semax struct cdev *dev = (struct cdev *)(kn->kn_hook); 960156783Semax struct tap_softc *tp = dev->si_drv1; 961156783Semax struct ifnet *ifp = tp->tap_ifp; 962156783Semax 963156783Semax s = splimp(); 964156783Semax if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) { 965156783Semax TAPDEBUG("%s have data in queue. len = %d, minor = %#x\n", 966156783Semax ifp->if_xname, ifp->if_snd.ifq_len, minor(dev)); 967156783Semax ret = 1; 968156783Semax } else { 969156783Semax TAPDEBUG("%s waiting for data, minor = %#x\n", 970156783Semax ifp->if_xname, minor(dev)); 971156783Semax ret = 0; 972156783Semax } 973156783Semax splx(s); 974156783Semax 975156783Semax return (ret); 976156783Semax} /* tapkqread */ 977156783Semax 978156783Semax 979156783Semax/* 980156783Semax * tap_kqwrite 981156783Semax * 982156783Semax * Always can write. Return the MTU in kn->data 983156783Semax */ 984156783Semaxstatic int 985156783Semaxtapkqwrite(struct knote *kn, long hint) 986156783Semax{ 987156783Semax int s; 988156783Semax struct tap_softc *tp = ((struct cdev *) kn->kn_hook)->si_drv1; 989156783Semax struct ifnet *ifp = tp->tap_ifp; 990156783Semax 991156783Semax s = splimp(); 992156783Semax kn->kn_data = ifp->if_mtu; 993156783Semax splx(s); 994156783Semax 995156783Semax return (1); 996156783Semax} /* tapkqwrite */ 997156783Semax 998156783Semax 999156783Semaxstatic void 1000156783Semaxtapkqdetach(struct knote *kn) 1001156783Semax{ 1002156783Semax struct tap_softc *tp = ((struct cdev *) kn->kn_hook)->si_drv1; 1003156783Semax 1004156783Semax knlist_remove(&tp->tap_rsel.si_note, kn, 0); 1005156783Semax} /* tapkqdetach */ 1006156783Semax 1007