if_tap.c revision 148887
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 148887 2005-08-09 10:20:02Z rwatson $ 3563803Snsayer * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ 3663670Snsayer */ 3763670Snsayer 3863670Snsayer#include "opt_inet.h" 3963670Snsayer 4063670Snsayer#include <sys/param.h> 4163670Snsayer#include <sys/conf.h> 42139207Sphk#include <sys/fcntl.h> 4363670Snsayer#include <sys/filio.h> 4463670Snsayer#include <sys/kernel.h> 4563670Snsayer#include <sys/malloc.h> 4663670Snsayer#include <sys/mbuf.h> 47129880Sphk#include <sys/module.h> 4863670Snsayer#include <sys/poll.h> 4963670Snsayer#include <sys/proc.h> 50139207Sphk#include <sys/selinfo.h> 5163670Snsayer#include <sys/signalvar.h> 5263670Snsayer#include <sys/socket.h> 5363670Snsayer#include <sys/sockio.h> 5463670Snsayer#include <sys/sysctl.h> 5563670Snsayer#include <sys/systm.h> 5663670Snsayer#include <sys/ttycom.h> 5763670Snsayer#include <sys/uio.h> 5883043Sbrooks#include <sys/queue.h> 5963670Snsayer 6063670Snsayer#include <net/bpf.h> 6163670Snsayer#include <net/ethernet.h> 6263670Snsayer#include <net/if.h> 6363670Snsayer#include <net/if_arp.h> 6463670Snsayer#include <net/route.h> 65147256Sbrooks#include <net/if_types.h> 6663670Snsayer 6763670Snsayer#include <netinet/in.h> 6863670Snsayer 6963670Snsayer#include <net/if_tapvar.h> 7063670Snsayer#include <net/if_tap.h> 7163670Snsayer 7263670Snsayer 7363670Snsayer#define CDEV_NAME "tap" 7463670Snsayer#define TAPDEBUG if (tapdebug) printf 7563670Snsayer 7663670Snsayer#define TAP "tap" 7763670Snsayer#define VMNET "vmnet" 7883043Sbrooks#define TAPMAXUNIT 0x7fff 79126077Sphk#define VMNET_DEV_MASK CLONE_FLAG0 8063670Snsayer 8163670Snsayer/* module */ 82111742Sdesstatic int tapmodevent(module_t, int, void *); 8363670Snsayer 8463670Snsayer/* device */ 85148868Srwatsonstatic void tapclone(void *, struct ucred *, char *, int, 86148868Srwatson struct cdev **); 87130585Sphkstatic void tapcreate(struct cdev *); 8863670Snsayer 8963670Snsayer/* network interface */ 9093084Sbdestatic void tapifstart(struct ifnet *); 9193084Sbdestatic int tapifioctl(struct ifnet *, u_long, caddr_t); 9293084Sbdestatic void tapifinit(void *); 9363670Snsayer 9463670Snsayer/* character device */ 9563670Snsayerstatic d_open_t tapopen; 9663670Snsayerstatic d_close_t tapclose; 9763670Snsayerstatic d_read_t tapread; 9863670Snsayerstatic d_write_t tapwrite; 9963670Snsayerstatic d_ioctl_t tapioctl; 10063670Snsayerstatic d_poll_t tappoll; 10163670Snsayer 10263670Snsayerstatic struct cdevsw tap_cdevsw = { 103126080Sphk .d_version = D_VERSION, 104126188Sbde .d_flags = D_PSEUDO | D_NEEDGIANT, 105111815Sphk .d_open = tapopen, 106111815Sphk .d_close = tapclose, 107111815Sphk .d_read = tapread, 108111815Sphk .d_write = tapwrite, 109111815Sphk .d_ioctl = tapioctl, 110111815Sphk .d_poll = tappoll, 111111815Sphk .d_name = CDEV_NAME, 11263670Snsayer}; 11363670Snsayer 114127003Srwatson/* 115127003Srwatson * All global variables in if_tap.c are locked with tapmtx, with the 116127003Srwatson * exception of tapdebug, which is accessed unlocked; tapclones is 117127003Srwatson * static at runtime. 118127003Srwatson */ 119127003Srwatsonstatic struct mtx tapmtx; 12083043Sbrooksstatic int tapdebug = 0; /* debug flag */ 121144979Smdoddstatic int tapuopen = 0; /* allow user open() */ 12283043Sbrooksstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 123126077Sphkstatic struct clonedevs *tapclones; 12463670Snsayer 12563670SnsayerMALLOC_DECLARE(M_TAP); 12663670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 12763670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 128144979Smdodd 129144979SmdoddSYSCTL_DECL(_net_link); 130144979SmdoddSYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0, 131144979Smdodd "Ethernet tunnel software network interface"); 132144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0, 133144979Smdodd "Allow user to open /dev/tap (based on node permissions)"); 134144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, ""); 135144979Smdodd 13663670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL); 13763670Snsayer 13863670Snsayer/* 13963670Snsayer * tapmodevent 14063670Snsayer * 14163670Snsayer * module event handler 14263670Snsayer */ 14363670Snsayerstatic int 14463670Snsayertapmodevent(mod, type, data) 14563670Snsayer module_t mod; 14663670Snsayer int type; 14763670Snsayer void *data; 14863670Snsayer{ 14983043Sbrooks static eventhandler_tag eh_tag = NULL; 15083043Sbrooks struct tap_softc *tp = NULL; 15183043Sbrooks struct ifnet *ifp = NULL; 152126077Sphk int s; 15363670Snsayer 15463670Snsayer switch (type) { 15563670Snsayer case MOD_LOAD: 15663670Snsayer 15783043Sbrooks /* intitialize device */ 15883043Sbrooks 159127003Srwatson mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF); 16083043Sbrooks SLIST_INIT(&taphead); 16183043Sbrooks 162126845Sphk clone_setup(&tapclones); 16371602Sphk eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 164127003Srwatson if (eh_tag == NULL) { 165127170Srwatson clone_cleanup(&tapclones); 166127003Srwatson mtx_destroy(&tapmtx); 167126077Sphk return (ENOMEM); 168127003Srwatson } 16983043Sbrooks return (0); 17063670Snsayer 17183043Sbrooks case MOD_UNLOAD: 172127003Srwatson /* 173127003Srwatson * The EBUSY algorithm here can't quite atomically 174127003Srwatson * guarantee that this is race-free since we have to 175127003Srwatson * release the tap mtx to deregister the clone handler. 176127003Srwatson */ 177127003Srwatson mtx_lock(&tapmtx); 178127003Srwatson SLIST_FOREACH(tp, &taphead, tap_next) { 179127098Srwatson mtx_lock(&tp->tap_mtx); 180127003Srwatson if (tp->tap_flags & TAP_OPEN) { 181127098Srwatson mtx_unlock(&tp->tap_mtx); 182127003Srwatson mtx_unlock(&tapmtx); 18383043Sbrooks return (EBUSY); 184127003Srwatson } 185127098Srwatson mtx_unlock(&tp->tap_mtx); 186127003Srwatson } 187127003Srwatson mtx_unlock(&tapmtx); 18883043Sbrooks 18971602Sphk EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 19063670Snsayer 191127003Srwatson mtx_lock(&tapmtx); 19283043Sbrooks while ((tp = SLIST_FIRST(&taphead)) != NULL) { 19383043Sbrooks SLIST_REMOVE_HEAD(&taphead, tap_next); 194127003Srwatson mtx_unlock(&tapmtx); 19583043Sbrooks 196147256Sbrooks ifp = tp->tap_ifp; 19783043Sbrooks 198121816Sbrooks TAPDEBUG("detaching %s\n", ifp->if_xname); 19983043Sbrooks 200127098Srwatson /* Unlocked read. */ 201121816Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 202121816Sbrooks ("%s flags is out of sync", ifp->if_xname)); 20383043Sbrooks 204126077Sphk destroy_dev(tp->tap_dev); 20563670Snsayer s = splimp(); 206106939Ssam ether_ifdetach(ifp); 207147256Sbrooks if_free_type(ifp, IFT_ETHER); 20863670Snsayer splx(s); 20963670Snsayer 210127098Srwatson mtx_destroy(&tp->tap_mtx); 21193752Sluigi free(tp, M_TAP); 212127003Srwatson mtx_lock(&tapmtx); 21383043Sbrooks } 214127003Srwatson mtx_unlock(&tapmtx); 215126077Sphk clone_cleanup(&tapclones); 21663670Snsayer 217135354Srwatson mtx_destroy(&tapmtx); 218135354Srwatson 21983043Sbrooks break; 22063670Snsayer 22163670Snsayer default: 22263670Snsayer return (EOPNOTSUPP); 22363670Snsayer } 22463670Snsayer 22563670Snsayer return (0); 22663670Snsayer} /* tapmodevent */ 22763670Snsayer 22863670Snsayer 22963670Snsayer/* 23071602Sphk * DEVFS handler 23171602Sphk * 23271602Sphk * We need to support two kind of devices - tap and vmnet 23371602Sphk */ 23471602Sphkstatic void 235148868Srwatsontapclone(arg, cred, name, namelen, dev) 23671602Sphk void *arg; 237148868Srwatson struct ucred *cred; 23871602Sphk char *name; 23971602Sphk int namelen; 240130585Sphk struct cdev **dev; 24171602Sphk{ 242126077Sphk u_int extra; 243126077Sphk int i, unit; 24483043Sbrooks char *device_name = name; 24571602Sphk 246130640Sphk if (*dev != NULL) 24771602Sphk return; 24871602Sphk 249126077Sphk device_name = TAP; 250126077Sphk extra = 0; 251126077Sphk if (strcmp(name, TAP) == 0) { 252126077Sphk unit = -1; 253126077Sphk } else if (strcmp(name, VMNET) == 0) { 254126077Sphk device_name = VMNET; 255126077Sphk extra = VMNET_DEV_MASK; 256126077Sphk unit = -1; 257126077Sphk } else if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 258126077Sphk device_name = VMNET; 259126077Sphk extra = VMNET_DEV_MASK; 260126077Sphk if (dev_stdclone(name, NULL, device_name, &unit) != 1) 261126077Sphk return; 26283043Sbrooks } 26371602Sphk 264126077Sphk /* find any existing device, or allocate new unit number */ 265126077Sphk i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra); 266126077Sphk if (i) { 267126796Sphk *dev = make_dev(&tap_cdevsw, unit2minor(unit | extra), 268126077Sphk UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit); 269144389Sphk if (*dev != NULL) { 270144389Sphk dev_ref(*dev); 271126077Sphk (*dev)->si_flags |= SI_CHEAPCLONE; 272144389Sphk } 27371602Sphk } 27471602Sphk} /* tapclone */ 27571602Sphk 27671602Sphk 27771602Sphk/* 27863670Snsayer * tapcreate 27963670Snsayer * 28063670Snsayer * to create interface 28163670Snsayer */ 28263670Snsayerstatic void 28363670Snsayertapcreate(dev) 284130585Sphk struct cdev *dev; 28563670Snsayer{ 28663670Snsayer struct ifnet *ifp = NULL; 28763670Snsayer struct tap_softc *tp = NULL; 28863670Snsayer unsigned short macaddr_hi; 28963803Snsayer int unit, s; 29063670Snsayer char *name = NULL; 291147256Sbrooks u_char eaddr[6]; 29263670Snsayer 293126077Sphk dev->si_flags &= ~SI_CHEAPCLONE; 294126077Sphk 29563670Snsayer /* allocate driver storage and create device */ 296111119Simp MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 297127098Srwatson mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF); 298127003Srwatson mtx_lock(&tapmtx); 29983043Sbrooks SLIST_INSERT_HEAD(&taphead, tp, tap_next); 300127003Srwatson mtx_unlock(&tapmtx); 30163670Snsayer 302126796Sphk unit = dev2unit(dev); 30383043Sbrooks 30463670Snsayer /* select device: tap or vmnet */ 305126796Sphk if (unit & VMNET_DEV_MASK) { 30663670Snsayer name = VMNET; 30763803Snsayer tp->tap_flags |= TAP_VMNET; 30883043Sbrooks } else 30963670Snsayer name = TAP; 31063670Snsayer 311126796Sphk unit &= TAPMAXUNIT; 312126796Sphk 31383043Sbrooks TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 31483043Sbrooks 31563670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 31663670Snsayer macaddr_hi = htons(0x00bd); 317147256Sbrooks bcopy(&macaddr_hi, eaddr, sizeof(short)); 318147256Sbrooks bcopy(&ticks, &eaddr[2], sizeof(long)); 319147256Sbrooks eaddr[5] = (u_char)unit; 32063670Snsayer 321111742Sdes /* fill the rest and attach interface */ 322147256Sbrooks ifp = tp->tap_ifp = if_alloc(IFT_ETHER); 323147256Sbrooks if (ifp == NULL) 324147256Sbrooks panic("%s%d: can not if_alloc()", name, unit); 32563670Snsayer ifp->if_softc = tp; 326121816Sbrooks if_initname(ifp, name, unit); 32763670Snsayer ifp->if_init = tapifinit; 32863670Snsayer ifp->if_start = tapifstart; 32963670Snsayer ifp->if_ioctl = tapifioctl; 33063670Snsayer ifp->if_mtu = ETHERMTU; 33163670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 33263670Snsayer ifp->if_snd.ifq_maxlen = ifqmaxlen; 33363670Snsayer 33483043Sbrooks dev->si_drv1 = tp; 335126077Sphk tp->tap_dev = dev; 33683043Sbrooks 33763803Snsayer s = splimp(); 338147256Sbrooks ether_ifattach(ifp, eaddr); 33963803Snsayer splx(s); 34063670Snsayer 341127098Srwatson mtx_lock(&tp->tap_mtx); 34263803Snsayer tp->tap_flags |= TAP_INITED; 343127098Srwatson mtx_unlock(&tp->tap_mtx); 34463803Snsayer 345121816Sbrooks TAPDEBUG("interface %s is created. minor = %#x\n", 346121816Sbrooks ifp->if_xname, minor(dev)); 34763670Snsayer} /* tapcreate */ 34863670Snsayer 34963670Snsayer 35063670Snsayer/* 351111742Sdes * tapopen 35263670Snsayer * 35363670Snsayer * to open tunnel. must be superuser 35463670Snsayer */ 35563670Snsayerstatic int 35683366Sjuliantapopen(dev, flag, mode, td) 357130585Sphk struct cdev *dev; 35863670Snsayer int flag; 35963670Snsayer int mode; 36083366Sjulian struct thread *td; 36163670Snsayer{ 36263670Snsayer struct tap_softc *tp = NULL; 363133460Semax struct ifnet *ifp = NULL; 364144979Smdodd int s; 36563670Snsayer 366144979Smdodd if (tapuopen == 0 && suser(td) != 0) 367144979Smdodd return (EPERM); 36863670Snsayer 369126796Sphk if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT) 370126796Sphk return (ENXIO); 37183043Sbrooks 372127165Srwatson /* 373127165Srwatson * XXXRW: Non-atomic test-and-set of si_drv1. Currently protected 374127165Srwatson * by Giant, but the race actually exists under memory pressure as 375127165Srwatson * well even when running with Giant, as malloc() may sleep. 376127165Srwatson */ 37763670Snsayer tp = dev->si_drv1; 37863670Snsayer if (tp == NULL) { 37963670Snsayer tapcreate(dev); 38063670Snsayer tp = dev->si_drv1; 38163670Snsayer } 38263670Snsayer 383127165Srwatson mtx_lock(&tp->tap_mtx); 384127165Srwatson if (tp->tap_flags & TAP_OPEN) { 385127165Srwatson mtx_unlock(&tp->tap_mtx); 386127165Srwatson return (EBUSY); 387127165Srwatson } 38863670Snsayer 389147256Sbrooks bcopy(IFP2ENADDR(tp->tap_ifp), tp->ether_addr, sizeof(tp->ether_addr)); 39083366Sjulian tp->tap_pid = td->td_proc->p_pid; 39163670Snsayer tp->tap_flags |= TAP_OPEN; 392147256Sbrooks ifp = tp->tap_ifp; 393127098Srwatson mtx_unlock(&tp->tap_mtx); 39463670Snsayer 395133460Semax s = splimp(); 396148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 397148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 398133460Semax splx(s); 39963670Snsayer 400133460Semax TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev)); 401133460Semax 40263670Snsayer return (0); 40363670Snsayer} /* tapopen */ 40463670Snsayer 40563670Snsayer 40663670Snsayer/* 40763670Snsayer * tapclose 40863670Snsayer * 40963670Snsayer * close the device - mark i/f down & delete routing info 41063670Snsayer */ 41163670Snsayerstatic int 41283366Sjuliantapclose(dev, foo, bar, td) 413130585Sphk struct cdev *dev; 41463670Snsayer int foo; 41563670Snsayer int bar; 41683366Sjulian struct thread *td; 41763670Snsayer{ 418146620Speadar struct ifaddr *ifa; 41963670Snsayer struct tap_softc *tp = dev->si_drv1; 420147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 421126077Sphk int s; 42263670Snsayer 42363670Snsayer /* junk all pending output */ 42483043Sbrooks IF_DRAIN(&ifp->if_snd); 42563670Snsayer 42663803Snsayer /* 42763803Snsayer * do not bring the interface down, and do not anything with 42863803Snsayer * interface, if we are in VMnet mode. just close the device. 42963803Snsayer */ 43063803Snsayer 431127098Srwatson mtx_lock(&tp->tap_mtx); 43263803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 433127098Srwatson mtx_unlock(&tp->tap_mtx); 43463670Snsayer s = splimp(); 43563670Snsayer if_down(ifp); 436148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 43763803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 438146620Speadar rtinit(ifa, (int)RTM_DELETE, 0); 43963670Snsayer } 440146620Speadar if_purgeaddrs(ifp); 441148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 44263670Snsayer } 44363670Snsayer splx(s); 444127098Srwatson } else 445127098Srwatson mtx_unlock(&tp->tap_mtx); 44663670Snsayer 44796122Salfred funsetown(&tp->tap_sigio); 448122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 44963670Snsayer 450127098Srwatson mtx_lock(&tp->tap_mtx); 45163670Snsayer tp->tap_flags &= ~TAP_OPEN; 45263670Snsayer tp->tap_pid = 0; 453127098Srwatson mtx_unlock(&tp->tap_mtx); 45463670Snsayer 455121816Sbrooks TAPDEBUG("%s is closed. minor = %#x\n", 456121816Sbrooks ifp->if_xname, minor(dev)); 45763670Snsayer 45863670Snsayer return (0); 45963670Snsayer} /* tapclose */ 46063670Snsayer 46163670Snsayer 46263670Snsayer/* 46363670Snsayer * tapifinit 46463670Snsayer * 46563670Snsayer * network interface initialization function 46663670Snsayer */ 46763670Snsayerstatic void 46863670Snsayertapifinit(xtp) 46963670Snsayer void *xtp; 47063670Snsayer{ 47163670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 472147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 47363670Snsayer 474121816Sbrooks TAPDEBUG("initializing %s\n", ifp->if_xname); 47563670Snsayer 476148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 477148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 47863670Snsayer 47963670Snsayer /* attempt to start output */ 48063670Snsayer tapifstart(ifp); 48163670Snsayer} /* tapifinit */ 48263670Snsayer 48363670Snsayer 48463670Snsayer/* 48563670Snsayer * tapifioctl 48663670Snsayer * 48763670Snsayer * Process an ioctl request on network interface 48863670Snsayer */ 489105228Sphkstatic int 49063670Snsayertapifioctl(ifp, cmd, data) 49163670Snsayer struct ifnet *ifp; 49263670Snsayer u_long cmd; 49363670Snsayer caddr_t data; 49463670Snsayer{ 495111742Sdes struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 49663670Snsayer struct ifstat *ifs = NULL; 49763670Snsayer int s, dummy; 49863670Snsayer 49963670Snsayer switch (cmd) { 50063670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 50163670Snsayer case SIOCADDMULTI: 50263670Snsayer case SIOCDELMULTI: 50383043Sbrooks break; 50463670Snsayer 50563670Snsayer case SIOCGIFSTATUS: 50663670Snsayer s = splimp(); 50763670Snsayer ifs = (struct ifstat *)data; 50863670Snsayer dummy = strlen(ifs->ascii); 509127098Srwatson mtx_lock(&tp->tap_mtx); 51063670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 51163670Snsayer snprintf(ifs->ascii + dummy, 51263670Snsayer sizeof(ifs->ascii) - dummy, 51363670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 514127098Srwatson mtx_unlock(&tp->tap_mtx); 51563670Snsayer splx(s); 51683043Sbrooks break; 51763670Snsayer 51863670Snsayer default: 519106939Ssam s = splimp(); 520106939Ssam dummy = ether_ioctl(ifp, cmd, data); 521106939Ssam splx(s); 522106939Ssam return (dummy); 52363670Snsayer } 52463670Snsayer 52563670Snsayer return (0); 52663670Snsayer} /* tapifioctl */ 52763670Snsayer 52863670Snsayer 52963670Snsayer/* 530111742Sdes * tapifstart 531111742Sdes * 53263670Snsayer * queue packets from higher level ready to put out 53363670Snsayer */ 53463670Snsayerstatic void 53563670Snsayertapifstart(ifp) 53663670Snsayer struct ifnet *ifp; 53763670Snsayer{ 53863670Snsayer struct tap_softc *tp = ifp->if_softc; 53963670Snsayer int s; 54063670Snsayer 541121816Sbrooks TAPDEBUG("%s starting\n", ifp->if_xname); 54263670Snsayer 54363803Snsayer /* 54463803Snsayer * do not junk pending output if we are in VMnet mode. 54563803Snsayer * XXX: can this do any harm because of queue overflow? 54663803Snsayer */ 54763803Snsayer 548127098Srwatson mtx_lock(&tp->tap_mtx); 549111742Sdes if (((tp->tap_flags & TAP_VMNET) == 0) && 55063803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 55163670Snsayer struct mbuf *m = NULL; 55263670Snsayer 553127098Srwatson mtx_unlock(&tp->tap_mtx); 554127098Srwatson 555127098Srwatson /* Unlocked read. */ 556121816Sbrooks TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 557121816Sbrooks tp->tap_flags); 55863670Snsayer 55963670Snsayer s = splimp(); 56063670Snsayer do { 56163670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 56263670Snsayer if (m != NULL) 56363670Snsayer m_freem(m); 56463670Snsayer ifp->if_oerrors ++; 56563670Snsayer } while (m != NULL); 56663670Snsayer splx(s); 56763670Snsayer 56863670Snsayer return; 56963670Snsayer } 570127098Srwatson mtx_unlock(&tp->tap_mtx); 57163670Snsayer 57263670Snsayer s = splimp(); 573148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 57463670Snsayer 57563670Snsayer if (ifp->if_snd.ifq_len != 0) { 576127098Srwatson mtx_lock(&tp->tap_mtx); 57763670Snsayer if (tp->tap_flags & TAP_RWAIT) { 57863670Snsayer tp->tap_flags &= ~TAP_RWAIT; 579111748Sdes wakeup(tp); 58063670Snsayer } 58163670Snsayer 582127098Srwatson if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) { 583127098Srwatson mtx_unlock(&tp->tap_mtx); 58495883Salfred pgsigio(&tp->tap_sigio, SIGIO, 0); 585127098Srwatson } else 586127098Srwatson mtx_unlock(&tp->tap_mtx); 58763670Snsayer 588122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 58963670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 59063670Snsayer } 59163670Snsayer 592148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 59363670Snsayer splx(s); 59463670Snsayer} /* tapifstart */ 59563670Snsayer 59663670Snsayer 59763670Snsayer/* 59863670Snsayer * tapioctl 59963670Snsayer * 60063670Snsayer * the cdevsw interface is now pretty minimal 60163670Snsayer */ 60263670Snsayerstatic int 60383366Sjuliantapioctl(dev, cmd, data, flag, td) 604130585Sphk struct cdev *dev; 60563670Snsayer u_long cmd; 60663670Snsayer caddr_t data; 60763670Snsayer int flag; 60883366Sjulian struct thread *td; 60963670Snsayer{ 61063670Snsayer struct tap_softc *tp = dev->si_drv1; 611147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 612111742Sdes struct tapinfo *tapp = NULL; 61363670Snsayer int s; 614102052Ssobomax int f; 61563670Snsayer 61663670Snsayer switch (cmd) { 617111742Sdes case TAPSIFINFO: 61863670Snsayer s = splimp(); 619111742Sdes tapp = (struct tapinfo *)data; 620111742Sdes ifp->if_mtu = tapp->mtu; 621111742Sdes ifp->if_type = tapp->type; 622111742Sdes ifp->if_baudrate = tapp->baudrate; 62363670Snsayer splx(s); 624111742Sdes break; 62563670Snsayer 626111742Sdes case TAPGIFINFO: 627111742Sdes tapp = (struct tapinfo *)data; 628111742Sdes tapp->mtu = ifp->if_mtu; 629111742Sdes tapp->type = ifp->if_type; 630111742Sdes tapp->baudrate = ifp->if_baudrate; 631111742Sdes break; 63263670Snsayer 63363670Snsayer case TAPSDEBUG: 63463670Snsayer tapdebug = *(int *)data; 63583043Sbrooks break; 63663670Snsayer 63763670Snsayer case TAPGDEBUG: 63863670Snsayer *(int *)data = tapdebug; 63983043Sbrooks break; 64063670Snsayer 64163670Snsayer case FIONBIO: 64283043Sbrooks break; 64363670Snsayer 64463670Snsayer case FIOASYNC: 64563803Snsayer s = splimp(); 646127098Srwatson mtx_lock(&tp->tap_mtx); 64763670Snsayer if (*(int *)data) 64863670Snsayer tp->tap_flags |= TAP_ASYNC; 64963670Snsayer else 65063670Snsayer tp->tap_flags &= ~TAP_ASYNC; 651127098Srwatson mtx_unlock(&tp->tap_mtx); 65263803Snsayer splx(s); 65383043Sbrooks break; 65463670Snsayer 65563670Snsayer case FIONREAD: 65663670Snsayer s = splimp(); 65763670Snsayer if (ifp->if_snd.ifq_head) { 65863670Snsayer struct mbuf *mb = ifp->if_snd.ifq_head; 65963670Snsayer 66063803Snsayer for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 66163670Snsayer *(int *)data += mb->m_len; 66283043Sbrooks } else 66363670Snsayer *(int *)data = 0; 66463670Snsayer splx(s); 66583043Sbrooks break; 66663670Snsayer 66763670Snsayer case FIOSETOWN: 66863670Snsayer return (fsetown(*(int *)data, &tp->tap_sigio)); 66963670Snsayer 67063670Snsayer case FIOGETOWN: 671104393Struckman *(int *)data = fgetown(&tp->tap_sigio); 67263670Snsayer return (0); 67363670Snsayer 67463670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 67563670Snsayer case TIOCSPGRP: 67663670Snsayer return (fsetown(-(*(int *)data), &tp->tap_sigio)); 67763670Snsayer 67863670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 67963670Snsayer case TIOCGPGRP: 680104393Struckman *(int *)data = -fgetown(&tp->tap_sigio); 68163670Snsayer return (0); 68263670Snsayer 68363670Snsayer /* VMware/VMnet port ioctl's */ 68463670Snsayer 68563670Snsayer case SIOCGIFFLAGS: /* get ifnet flags */ 68663670Snsayer bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 68783043Sbrooks break; 68863670Snsayer 68983043Sbrooks case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 690102052Ssobomax f = *(int *)data; 69163670Snsayer f &= 0x0fff; 69263670Snsayer f &= ~IFF_CANTCHANGE; 69363670Snsayer f |= IFF_UP; 69463670Snsayer 69563670Snsayer s = splimp(); 69663670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 69763670Snsayer splx(s); 69883043Sbrooks break; 69963670Snsayer 70063861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 70163670Snsayer case SIOCGIFADDR: 702127165Srwatson mtx_lock(&tp->tap_mtx); 70363861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 704127165Srwatson mtx_unlock(&tp->tap_mtx); 70583043Sbrooks break; 70663670Snsayer 70763861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 708127165Srwatson mtx_lock(&tp->tap_mtx); 70963861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 710127165Srwatson mtx_unlock(&tp->tap_mtx); 71183043Sbrooks break; 71263670Snsayer 71363670Snsayer default: 71463670Snsayer return (ENOTTY); 71563670Snsayer } 71663670Snsayer return (0); 71763670Snsayer} /* tapioctl */ 71863670Snsayer 71963670Snsayer 72063670Snsayer/* 72163670Snsayer * tapread 72263670Snsayer * 72363670Snsayer * the cdevsw read interface - reads a packet at a time, or at 72463670Snsayer * least as much of a packet as can be read 72563670Snsayer */ 72663670Snsayerstatic int 72763670Snsayertapread(dev, uio, flag) 728130585Sphk struct cdev *dev; 72963670Snsayer struct uio *uio; 73063670Snsayer int flag; 73163670Snsayer{ 73263670Snsayer struct tap_softc *tp = dev->si_drv1; 733147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 73490227Sdillon struct mbuf *m = NULL; 73563670Snsayer int error = 0, len, s; 73663670Snsayer 737121816Sbrooks TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev)); 73863670Snsayer 739127098Srwatson mtx_lock(&tp->tap_mtx); 74063670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 741127098Srwatson mtx_unlock(&tp->tap_mtx); 742127098Srwatson 743127098Srwatson /* Unlocked read. */ 744121816Sbrooks TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 745121816Sbrooks ifp->if_xname, minor(dev), tp->tap_flags); 74663803Snsayer 74763670Snsayer return (EHOSTDOWN); 74863670Snsayer } 74963670Snsayer 75063670Snsayer tp->tap_flags &= ~TAP_RWAIT; 751127098Srwatson mtx_unlock(&tp->tap_mtx); 75263670Snsayer 75363670Snsayer /* sleep until we get a packet */ 75463670Snsayer do { 75563670Snsayer s = splimp(); 75690227Sdillon IF_DEQUEUE(&ifp->if_snd, m); 75763670Snsayer splx(s); 75863670Snsayer 75990227Sdillon if (m == NULL) { 760139207Sphk if (flag & O_NONBLOCK) 76163670Snsayer return (EWOULDBLOCK); 762111742Sdes 763127098Srwatson mtx_lock(&tp->tap_mtx); 76463670Snsayer tp->tap_flags |= TAP_RWAIT; 765127098Srwatson mtx_unlock(&tp->tap_mtx); 766111748Sdes error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); 76763670Snsayer if (error) 76863670Snsayer return (error); 76963670Snsayer } 77090227Sdillon } while (m == NULL); 77163670Snsayer 77263670Snsayer /* feed packet to bpf */ 773106939Ssam BPF_MTAP(ifp, m); 77463670Snsayer 77563670Snsayer /* xfer packet to user space */ 77690227Sdillon while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 77790227Sdillon len = min(uio->uio_resid, m->m_len); 77863670Snsayer if (len == 0) 77963670Snsayer break; 78063670Snsayer 781111741Sdes error = uiomove(mtod(m, void *), len, uio); 78290227Sdillon m = m_free(m); 78363670Snsayer } 78463670Snsayer 78590227Sdillon if (m != NULL) { 786121816Sbrooks TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 787121816Sbrooks minor(dev)); 78890227Sdillon m_freem(m); 78963670Snsayer } 79063670Snsayer 79163670Snsayer return (error); 79263670Snsayer} /* tapread */ 79363670Snsayer 79463670Snsayer 79563670Snsayer/* 79663670Snsayer * tapwrite 79763670Snsayer * 79863670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 79963670Snsayer */ 80063670Snsayerstatic int 80163670Snsayertapwrite(dev, uio, flag) 802130585Sphk struct cdev *dev; 80363670Snsayer struct uio *uio; 80463670Snsayer int flag; 80563670Snsayer{ 80663670Snsayer struct tap_softc *tp = dev->si_drv1; 807147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 808137101Sglebius struct mbuf *m; 809137101Sglebius int error = 0; 81063670Snsayer 811121816Sbrooks TAPDEBUG("%s writting, minor = %#x\n", 812121816Sbrooks ifp->if_xname, minor(dev)); 81363670Snsayer 81463670Snsayer if (uio->uio_resid == 0) 81563670Snsayer return (0); 81663670Snsayer 81763670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 818121816Sbrooks TAPDEBUG("%s invalid packet len = %d, minor = %#x\n", 819121816Sbrooks ifp->if_xname, uio->uio_resid, minor(dev)); 82063803Snsayer 82163670Snsayer return (EIO); 82263670Snsayer } 82363670Snsayer 824145883Semax if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, ETHER_ALIGN)) == NULL) { 82563670Snsayer ifp->if_ierrors ++; 82663670Snsayer return (error); 82763670Snsayer } 82863670Snsayer 829137101Sglebius m->m_pkthdr.rcvif = ifp; 830111742Sdes 831106939Ssam /* Pass packet up to parent. */ 832137101Sglebius (*ifp->if_input)(ifp, m); 833106939Ssam ifp->if_ipackets ++; /* ibytes are counted in parent */ 83463670Snsayer 83563670Snsayer return (0); 83663670Snsayer} /* tapwrite */ 83763670Snsayer 83863670Snsayer 83963670Snsayer/* 84063670Snsayer * tappoll 84163670Snsayer * 84263670Snsayer * the poll interface, this is only useful on reads 84363670Snsayer * really. the write detect always returns true, write never blocks 84463670Snsayer * anyway, it either accepts the packet or drops it 84563670Snsayer */ 84663670Snsayerstatic int 84783366Sjuliantappoll(dev, events, td) 848130585Sphk struct cdev *dev; 84963670Snsayer int events; 85083366Sjulian struct thread *td; 85163670Snsayer{ 85263670Snsayer struct tap_softc *tp = dev->si_drv1; 853147256Sbrooks struct ifnet *ifp = tp->tap_ifp; 854111742Sdes int s, revents = 0; 85563670Snsayer 856121816Sbrooks TAPDEBUG("%s polling, minor = %#x\n", 857121816Sbrooks ifp->if_xname, minor(dev)); 85863670Snsayer 85963670Snsayer s = splimp(); 86063670Snsayer if (events & (POLLIN | POLLRDNORM)) { 86163670Snsayer if (ifp->if_snd.ifq_len > 0) { 862121816Sbrooks TAPDEBUG("%s have data in queue. len = %d, " \ 863121816Sbrooks "minor = %#x\n", ifp->if_xname, 86483043Sbrooks ifp->if_snd.ifq_len, minor(dev)); 86563803Snsayer 86663670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 86783043Sbrooks } else { 868121816Sbrooks TAPDEBUG("%s waiting for data, minor = %#x\n", 869121816Sbrooks ifp->if_xname, minor(dev)); 87063803Snsayer 87183805Sjhb selrecord(td, &tp->tap_rsel); 87263670Snsayer } 87363670Snsayer } 87463670Snsayer 87563670Snsayer if (events & (POLLOUT | POLLWRNORM)) 87663670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 87763670Snsayer 87863670Snsayer splx(s); 87963670Snsayer return (revents); 88063670Snsayer} /* tappoll */ 881