if_tap.c revision 145883
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 145883 2005-05-04 18:55:03Z emax $ 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> 6563670Snsayer 6663670Snsayer#include <netinet/in.h> 6763670Snsayer 6863670Snsayer#include <net/if_tapvar.h> 6963670Snsayer#include <net/if_tap.h> 7063670Snsayer 7163670Snsayer 7263670Snsayer#define CDEV_NAME "tap" 7363670Snsayer#define TAPDEBUG if (tapdebug) printf 7463670Snsayer 7563670Snsayer#define TAP "tap" 7663670Snsayer#define VMNET "vmnet" 7783043Sbrooks#define TAPMAXUNIT 0x7fff 78126077Sphk#define VMNET_DEV_MASK CLONE_FLAG0 7963670Snsayer 8063670Snsayer/* module */ 81111742Sdesstatic int tapmodevent(module_t, int, void *); 8263670Snsayer 8363670Snsayer/* device */ 84130585Sphkstatic void tapclone(void *, char *, int, struct cdev **); 85130585Sphkstatic void tapcreate(struct cdev *); 8663670Snsayer 8763670Snsayer/* network interface */ 8893084Sbdestatic void tapifstart(struct ifnet *); 8993084Sbdestatic int tapifioctl(struct ifnet *, u_long, caddr_t); 9093084Sbdestatic void tapifinit(void *); 9163670Snsayer 9263670Snsayer/* character device */ 9363670Snsayerstatic d_open_t tapopen; 9463670Snsayerstatic d_close_t tapclose; 9563670Snsayerstatic d_read_t tapread; 9663670Snsayerstatic d_write_t tapwrite; 9763670Snsayerstatic d_ioctl_t tapioctl; 9863670Snsayerstatic d_poll_t tappoll; 9963670Snsayer 10063670Snsayerstatic struct cdevsw tap_cdevsw = { 101126080Sphk .d_version = D_VERSION, 102126188Sbde .d_flags = D_PSEUDO | D_NEEDGIANT, 103111815Sphk .d_open = tapopen, 104111815Sphk .d_close = tapclose, 105111815Sphk .d_read = tapread, 106111815Sphk .d_write = tapwrite, 107111815Sphk .d_ioctl = tapioctl, 108111815Sphk .d_poll = tappoll, 109111815Sphk .d_name = CDEV_NAME, 11063670Snsayer}; 11163670Snsayer 112127003Srwatson/* 113127003Srwatson * All global variables in if_tap.c are locked with tapmtx, with the 114127003Srwatson * exception of tapdebug, which is accessed unlocked; tapclones is 115127003Srwatson * static at runtime. 116127003Srwatson */ 117127003Srwatsonstatic struct mtx tapmtx; 11883043Sbrooksstatic int tapdebug = 0; /* debug flag */ 119144979Smdoddstatic int tapuopen = 0; /* allow user open() */ 12083043Sbrooksstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 121126077Sphkstatic struct clonedevs *tapclones; 12263670Snsayer 12363670SnsayerMALLOC_DECLARE(M_TAP); 12463670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 12563670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 126144979Smdodd 127144979SmdoddSYSCTL_DECL(_net_link); 128144979SmdoddSYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0, 129144979Smdodd "Ethernet tunnel software network interface"); 130144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0, 131144979Smdodd "Allow user to open /dev/tap (based on node permissions)"); 132144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, ""); 133144979Smdodd 13463670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL); 13563670Snsayer 13663670Snsayer/* 13763670Snsayer * tapmodevent 13863670Snsayer * 13963670Snsayer * module event handler 14063670Snsayer */ 14163670Snsayerstatic int 14263670Snsayertapmodevent(mod, type, data) 14363670Snsayer module_t mod; 14463670Snsayer int type; 14563670Snsayer void *data; 14663670Snsayer{ 14783043Sbrooks static eventhandler_tag eh_tag = NULL; 14883043Sbrooks struct tap_softc *tp = NULL; 14983043Sbrooks struct ifnet *ifp = NULL; 150126077Sphk int s; 15163670Snsayer 15263670Snsayer switch (type) { 15363670Snsayer case MOD_LOAD: 15463670Snsayer 15583043Sbrooks /* intitialize device */ 15683043Sbrooks 157127003Srwatson mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF); 15883043Sbrooks SLIST_INIT(&taphead); 15983043Sbrooks 160126845Sphk clone_setup(&tapclones); 16171602Sphk eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 162127003Srwatson if (eh_tag == NULL) { 163127170Srwatson clone_cleanup(&tapclones); 164127003Srwatson mtx_destroy(&tapmtx); 165126077Sphk return (ENOMEM); 166127003Srwatson } 16783043Sbrooks return (0); 16863670Snsayer 16983043Sbrooks case MOD_UNLOAD: 170127003Srwatson /* 171127003Srwatson * The EBUSY algorithm here can't quite atomically 172127003Srwatson * guarantee that this is race-free since we have to 173127003Srwatson * release the tap mtx to deregister the clone handler. 174127003Srwatson */ 175127003Srwatson mtx_lock(&tapmtx); 176127003Srwatson SLIST_FOREACH(tp, &taphead, tap_next) { 177127098Srwatson mtx_lock(&tp->tap_mtx); 178127003Srwatson if (tp->tap_flags & TAP_OPEN) { 179127098Srwatson mtx_unlock(&tp->tap_mtx); 180127003Srwatson mtx_unlock(&tapmtx); 18183043Sbrooks return (EBUSY); 182127003Srwatson } 183127098Srwatson mtx_unlock(&tp->tap_mtx); 184127003Srwatson } 185127003Srwatson mtx_unlock(&tapmtx); 18683043Sbrooks 18771602Sphk EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 18863670Snsayer 189127003Srwatson mtx_lock(&tapmtx); 19083043Sbrooks while ((tp = SLIST_FIRST(&taphead)) != NULL) { 19183043Sbrooks SLIST_REMOVE_HEAD(&taphead, tap_next); 192127003Srwatson mtx_unlock(&tapmtx); 19383043Sbrooks 19483043Sbrooks ifp = &tp->tap_if; 19583043Sbrooks 196121816Sbrooks TAPDEBUG("detaching %s\n", ifp->if_xname); 19783043Sbrooks 198127098Srwatson /* Unlocked read. */ 199121816Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 200121816Sbrooks ("%s flags is out of sync", ifp->if_xname)); 20183043Sbrooks 202126077Sphk destroy_dev(tp->tap_dev); 20363670Snsayer s = splimp(); 204106939Ssam ether_ifdetach(ifp); 20563670Snsayer splx(s); 20663670Snsayer 207127098Srwatson mtx_destroy(&tp->tap_mtx); 20893752Sluigi free(tp, M_TAP); 209127003Srwatson mtx_lock(&tapmtx); 21083043Sbrooks } 211127003Srwatson mtx_unlock(&tapmtx); 212126077Sphk clone_cleanup(&tapclones); 21363670Snsayer 214135354Srwatson mtx_destroy(&tapmtx); 215135354Srwatson 21683043Sbrooks break; 21763670Snsayer 21863670Snsayer default: 21963670Snsayer return (EOPNOTSUPP); 22063670Snsayer } 22163670Snsayer 22263670Snsayer return (0); 22363670Snsayer} /* tapmodevent */ 22463670Snsayer 22563670Snsayer 22663670Snsayer/* 22771602Sphk * DEVFS handler 22871602Sphk * 22971602Sphk * We need to support two kind of devices - tap and vmnet 23071602Sphk */ 23171602Sphkstatic void 23271602Sphktapclone(arg, name, namelen, dev) 23371602Sphk void *arg; 23471602Sphk char *name; 23571602Sphk int namelen; 236130585Sphk struct cdev **dev; 23771602Sphk{ 238126077Sphk u_int extra; 239126077Sphk int i, unit; 24083043Sbrooks char *device_name = name; 24171602Sphk 242130640Sphk if (*dev != NULL) 24371602Sphk return; 24471602Sphk 245126077Sphk device_name = TAP; 246126077Sphk extra = 0; 247126077Sphk if (strcmp(name, TAP) == 0) { 248126077Sphk unit = -1; 249126077Sphk } else if (strcmp(name, VMNET) == 0) { 250126077Sphk device_name = VMNET; 251126077Sphk extra = VMNET_DEV_MASK; 252126077Sphk unit = -1; 253126077Sphk } else if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 254126077Sphk device_name = VMNET; 255126077Sphk extra = VMNET_DEV_MASK; 256126077Sphk if (dev_stdclone(name, NULL, device_name, &unit) != 1) 257126077Sphk return; 25883043Sbrooks } 25971602Sphk 260126077Sphk /* find any existing device, or allocate new unit number */ 261126077Sphk i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra); 262126077Sphk if (i) { 263126796Sphk *dev = make_dev(&tap_cdevsw, unit2minor(unit | extra), 264126077Sphk UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit); 265144389Sphk if (*dev != NULL) { 266144389Sphk dev_ref(*dev); 267126077Sphk (*dev)->si_flags |= SI_CHEAPCLONE; 268144389Sphk } 26971602Sphk } 27071602Sphk} /* tapclone */ 27171602Sphk 27271602Sphk 27371602Sphk/* 27463670Snsayer * tapcreate 27563670Snsayer * 27663670Snsayer * to create interface 27763670Snsayer */ 27863670Snsayerstatic void 27963670Snsayertapcreate(dev) 280130585Sphk struct cdev *dev; 28163670Snsayer{ 28263670Snsayer struct ifnet *ifp = NULL; 28363670Snsayer struct tap_softc *tp = NULL; 28463670Snsayer unsigned short macaddr_hi; 28563803Snsayer int unit, s; 28663670Snsayer char *name = NULL; 28763670Snsayer 288126077Sphk dev->si_flags &= ~SI_CHEAPCLONE; 289126077Sphk 29063670Snsayer /* allocate driver storage and create device */ 291111119Simp MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 292127098Srwatson mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF); 293127003Srwatson mtx_lock(&tapmtx); 29483043Sbrooks SLIST_INSERT_HEAD(&taphead, tp, tap_next); 295127003Srwatson mtx_unlock(&tapmtx); 29663670Snsayer 297126796Sphk unit = dev2unit(dev); 29883043Sbrooks 29963670Snsayer /* select device: tap or vmnet */ 300126796Sphk if (unit & VMNET_DEV_MASK) { 30163670Snsayer name = VMNET; 30263803Snsayer tp->tap_flags |= TAP_VMNET; 30383043Sbrooks } else 30463670Snsayer name = TAP; 30563670Snsayer 306126796Sphk unit &= TAPMAXUNIT; 307126796Sphk 30883043Sbrooks TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 30983043Sbrooks 31063670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 31163670Snsayer macaddr_hi = htons(0x00bd); 31263670Snsayer bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 31363670Snsayer bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 31463670Snsayer tp->arpcom.ac_enaddr[5] = (u_char)unit; 31563670Snsayer 316111742Sdes /* fill the rest and attach interface */ 31763670Snsayer ifp = &tp->tap_if; 31863670Snsayer ifp->if_softc = tp; 319121816Sbrooks if_initname(ifp, name, unit); 32063670Snsayer ifp->if_init = tapifinit; 32163670Snsayer ifp->if_start = tapifstart; 32263670Snsayer ifp->if_ioctl = tapifioctl; 32363670Snsayer ifp->if_mtu = ETHERMTU; 32463670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 32563670Snsayer ifp->if_snd.ifq_maxlen = ifqmaxlen; 32663670Snsayer 32783043Sbrooks dev->si_drv1 = tp; 328126077Sphk tp->tap_dev = dev; 32983043Sbrooks 33063803Snsayer s = splimp(); 331106939Ssam ether_ifattach(ifp, tp->arpcom.ac_enaddr); 33263803Snsayer splx(s); 33363670Snsayer 334127098Srwatson mtx_lock(&tp->tap_mtx); 33563803Snsayer tp->tap_flags |= TAP_INITED; 336127098Srwatson mtx_unlock(&tp->tap_mtx); 33763803Snsayer 338121816Sbrooks TAPDEBUG("interface %s is created. minor = %#x\n", 339121816Sbrooks ifp->if_xname, minor(dev)); 34063670Snsayer} /* tapcreate */ 34163670Snsayer 34263670Snsayer 34363670Snsayer/* 344111742Sdes * tapopen 34563670Snsayer * 34663670Snsayer * to open tunnel. must be superuser 34763670Snsayer */ 34863670Snsayerstatic int 34983366Sjuliantapopen(dev, flag, mode, td) 350130585Sphk struct cdev *dev; 35163670Snsayer int flag; 35263670Snsayer int mode; 35383366Sjulian struct thread *td; 35463670Snsayer{ 35563670Snsayer struct tap_softc *tp = NULL; 356133460Semax struct ifnet *ifp = NULL; 357144979Smdodd int s; 35863670Snsayer 359144979Smdodd if (tapuopen == 0 && suser(td) != 0) 360144979Smdodd return (EPERM); 36163670Snsayer 362126796Sphk if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT) 363126796Sphk return (ENXIO); 36483043Sbrooks 365127165Srwatson /* 366127165Srwatson * XXXRW: Non-atomic test-and-set of si_drv1. Currently protected 367127165Srwatson * by Giant, but the race actually exists under memory pressure as 368127165Srwatson * well even when running with Giant, as malloc() may sleep. 369127165Srwatson */ 37063670Snsayer tp = dev->si_drv1; 37163670Snsayer if (tp == NULL) { 37263670Snsayer tapcreate(dev); 37363670Snsayer tp = dev->si_drv1; 37463670Snsayer } 37563670Snsayer 376127165Srwatson mtx_lock(&tp->tap_mtx); 377127165Srwatson if (tp->tap_flags & TAP_OPEN) { 378127165Srwatson mtx_unlock(&tp->tap_mtx); 379127165Srwatson return (EBUSY); 380127165Srwatson } 38163670Snsayer 38263861Snsayer bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 38383366Sjulian tp->tap_pid = td->td_proc->p_pid; 38463670Snsayer tp->tap_flags |= TAP_OPEN; 385133460Semax ifp = &tp->tap_if; 386127098Srwatson mtx_unlock(&tp->tap_mtx); 38763670Snsayer 388133460Semax s = splimp(); 389133460Semax ifp->if_flags |= IFF_RUNNING; 390133460Semax ifp->if_flags &= ~IFF_OACTIVE; 391133460Semax splx(s); 39263670Snsayer 393133460Semax TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev)); 394133460Semax 39563670Snsayer return (0); 39663670Snsayer} /* tapopen */ 39763670Snsayer 39863670Snsayer 39963670Snsayer/* 40063670Snsayer * tapclose 40163670Snsayer * 40263670Snsayer * close the device - mark i/f down & delete routing info 40363670Snsayer */ 40463670Snsayerstatic int 40583366Sjuliantapclose(dev, foo, bar, td) 406130585Sphk struct cdev *dev; 40763670Snsayer int foo; 40863670Snsayer int bar; 40983366Sjulian struct thread *td; 41063670Snsayer{ 41163670Snsayer struct tap_softc *tp = dev->si_drv1; 41263670Snsayer struct ifnet *ifp = &tp->tap_if; 413126077Sphk int s; 41463670Snsayer 41563670Snsayer /* junk all pending output */ 41683043Sbrooks IF_DRAIN(&ifp->if_snd); 41763670Snsayer 41863803Snsayer /* 41963803Snsayer * do not bring the interface down, and do not anything with 42063803Snsayer * interface, if we are in VMnet mode. just close the device. 42163803Snsayer */ 42263803Snsayer 423127098Srwatson mtx_lock(&tp->tap_mtx); 42463803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 425127098Srwatson mtx_unlock(&tp->tap_mtx); 42663670Snsayer s = splimp(); 42763670Snsayer if_down(ifp); 42863670Snsayer if (ifp->if_flags & IFF_RUNNING) { 42963670Snsayer /* find internet addresses and delete routes */ 43063670Snsayer struct ifaddr *ifa = NULL; 43163670Snsayer 432127098Srwatson /* In desparate need of ifaddr locking. */ 43363803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 43463670Snsayer if (ifa->ifa_addr->sa_family == AF_INET) { 43563670Snsayer rtinit(ifa, (int)RTM_DELETE, 0); 43663670Snsayer 43763670Snsayer /* remove address from interface */ 438111742Sdes bzero(ifa->ifa_addr, 43963670Snsayer sizeof(*(ifa->ifa_addr))); 440111742Sdes bzero(ifa->ifa_dstaddr, 44163670Snsayer sizeof(*(ifa->ifa_dstaddr))); 442111742Sdes bzero(ifa->ifa_netmask, 44363670Snsayer sizeof(*(ifa->ifa_netmask))); 44463670Snsayer } 44563670Snsayer } 44663670Snsayer 44763670Snsayer ifp->if_flags &= ~IFF_RUNNING; 44863670Snsayer } 44963670Snsayer splx(s); 450127098Srwatson } else 451127098Srwatson mtx_unlock(&tp->tap_mtx); 45263670Snsayer 45396122Salfred funsetown(&tp->tap_sigio); 454122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 45563670Snsayer 456127098Srwatson mtx_lock(&tp->tap_mtx); 45763670Snsayer tp->tap_flags &= ~TAP_OPEN; 45863670Snsayer tp->tap_pid = 0; 459127098Srwatson mtx_unlock(&tp->tap_mtx); 46063670Snsayer 461121816Sbrooks TAPDEBUG("%s is closed. minor = %#x\n", 462121816Sbrooks ifp->if_xname, minor(dev)); 46363670Snsayer 46463670Snsayer return (0); 46563670Snsayer} /* tapclose */ 46663670Snsayer 46763670Snsayer 46863670Snsayer/* 46963670Snsayer * tapifinit 47063670Snsayer * 47163670Snsayer * network interface initialization function 47263670Snsayer */ 47363670Snsayerstatic void 47463670Snsayertapifinit(xtp) 47563670Snsayer void *xtp; 47663670Snsayer{ 47763670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 47863670Snsayer struct ifnet *ifp = &tp->tap_if; 47963670Snsayer 480121816Sbrooks TAPDEBUG("initializing %s\n", ifp->if_xname); 48163670Snsayer 48263670Snsayer ifp->if_flags |= IFF_RUNNING; 48363670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 48463670Snsayer 48563670Snsayer /* attempt to start output */ 48663670Snsayer tapifstart(ifp); 48763670Snsayer} /* tapifinit */ 48863670Snsayer 48963670Snsayer 49063670Snsayer/* 49163670Snsayer * tapifioctl 49263670Snsayer * 49363670Snsayer * Process an ioctl request on network interface 49463670Snsayer */ 495105228Sphkstatic int 49663670Snsayertapifioctl(ifp, cmd, data) 49763670Snsayer struct ifnet *ifp; 49863670Snsayer u_long cmd; 49963670Snsayer caddr_t data; 50063670Snsayer{ 501111742Sdes struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 50263670Snsayer struct ifstat *ifs = NULL; 50363670Snsayer int s, dummy; 50463670Snsayer 50563670Snsayer switch (cmd) { 50663670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 50763670Snsayer case SIOCADDMULTI: 50863670Snsayer case SIOCDELMULTI: 50983043Sbrooks break; 51063670Snsayer 51163670Snsayer case SIOCGIFSTATUS: 51263670Snsayer s = splimp(); 51363670Snsayer ifs = (struct ifstat *)data; 51463670Snsayer dummy = strlen(ifs->ascii); 515127098Srwatson mtx_lock(&tp->tap_mtx); 51663670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 51763670Snsayer snprintf(ifs->ascii + dummy, 51863670Snsayer sizeof(ifs->ascii) - dummy, 51963670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 520127098Srwatson mtx_unlock(&tp->tap_mtx); 52163670Snsayer splx(s); 52283043Sbrooks break; 52363670Snsayer 52463670Snsayer default: 525106939Ssam s = splimp(); 526106939Ssam dummy = ether_ioctl(ifp, cmd, data); 527106939Ssam splx(s); 528106939Ssam return (dummy); 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 54163670Snsayertapifstart(ifp) 54263670Snsayer struct ifnet *ifp; 54363670Snsayer{ 54463670Snsayer struct tap_softc *tp = ifp->if_softc; 54563670Snsayer int s; 54663670Snsayer 547121816Sbrooks TAPDEBUG("%s starting\n", ifp->if_xname); 54863670Snsayer 54963803Snsayer /* 55063803Snsayer * do not junk pending output if we are in VMnet mode. 55163803Snsayer * XXX: can this do any harm because of queue overflow? 55263803Snsayer */ 55363803Snsayer 554127098Srwatson mtx_lock(&tp->tap_mtx); 555111742Sdes if (((tp->tap_flags & TAP_VMNET) == 0) && 55663803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 55763670Snsayer struct mbuf *m = NULL; 55863670Snsayer 559127098Srwatson mtx_unlock(&tp->tap_mtx); 560127098Srwatson 561127098Srwatson /* Unlocked read. */ 562121816Sbrooks TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 563121816Sbrooks tp->tap_flags); 56463670Snsayer 56563670Snsayer s = splimp(); 56663670Snsayer do { 56763670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 56863670Snsayer if (m != NULL) 56963670Snsayer m_freem(m); 57063670Snsayer ifp->if_oerrors ++; 57163670Snsayer } while (m != NULL); 57263670Snsayer splx(s); 57363670Snsayer 57463670Snsayer return; 57563670Snsayer } 576127098Srwatson mtx_unlock(&tp->tap_mtx); 57763670Snsayer 57863670Snsayer s = splimp(); 57963670Snsayer ifp->if_flags |= IFF_OACTIVE; 58063670Snsayer 58163670Snsayer if (ifp->if_snd.ifq_len != 0) { 582127098Srwatson mtx_lock(&tp->tap_mtx); 58363670Snsayer if (tp->tap_flags & TAP_RWAIT) { 58463670Snsayer tp->tap_flags &= ~TAP_RWAIT; 585111748Sdes wakeup(tp); 58663670Snsayer } 58763670Snsayer 588127098Srwatson if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) { 589127098Srwatson mtx_unlock(&tp->tap_mtx); 59095883Salfred pgsigio(&tp->tap_sigio, SIGIO, 0); 591127098Srwatson } else 592127098Srwatson mtx_unlock(&tp->tap_mtx); 59363670Snsayer 594122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 59563670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 59663670Snsayer } 59763670Snsayer 59863670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 59963670Snsayer splx(s); 60063670Snsayer} /* tapifstart */ 60163670Snsayer 60263670Snsayer 60363670Snsayer/* 60463670Snsayer * tapioctl 60563670Snsayer * 60663670Snsayer * the cdevsw interface is now pretty minimal 60763670Snsayer */ 60863670Snsayerstatic int 60983366Sjuliantapioctl(dev, cmd, data, flag, td) 610130585Sphk struct cdev *dev; 61163670Snsayer u_long cmd; 61263670Snsayer caddr_t data; 61363670Snsayer int flag; 61483366Sjulian struct thread *td; 61563670Snsayer{ 61663670Snsayer struct tap_softc *tp = dev->si_drv1; 61763670Snsayer struct ifnet *ifp = &tp->tap_if; 618111742Sdes struct tapinfo *tapp = NULL; 61963670Snsayer int s; 620102052Ssobomax int f; 62163670Snsayer 62263670Snsayer switch (cmd) { 623111742Sdes case TAPSIFINFO: 62463670Snsayer s = splimp(); 625111742Sdes tapp = (struct tapinfo *)data; 626111742Sdes ifp->if_mtu = tapp->mtu; 627111742Sdes ifp->if_type = tapp->type; 628111742Sdes ifp->if_baudrate = tapp->baudrate; 62963670Snsayer splx(s); 630111742Sdes break; 63163670Snsayer 632111742Sdes case TAPGIFINFO: 633111742Sdes tapp = (struct tapinfo *)data; 634111742Sdes tapp->mtu = ifp->if_mtu; 635111742Sdes tapp->type = ifp->if_type; 636111742Sdes tapp->baudrate = ifp->if_baudrate; 637111742Sdes break; 63863670Snsayer 63963670Snsayer case TAPSDEBUG: 64063670Snsayer tapdebug = *(int *)data; 64183043Sbrooks break; 64263670Snsayer 64363670Snsayer case TAPGDEBUG: 64463670Snsayer *(int *)data = tapdebug; 64583043Sbrooks break; 64663670Snsayer 64763670Snsayer case FIONBIO: 64883043Sbrooks break; 64963670Snsayer 65063670Snsayer case FIOASYNC: 65163803Snsayer s = splimp(); 652127098Srwatson mtx_lock(&tp->tap_mtx); 65363670Snsayer if (*(int *)data) 65463670Snsayer tp->tap_flags |= TAP_ASYNC; 65563670Snsayer else 65663670Snsayer tp->tap_flags &= ~TAP_ASYNC; 657127098Srwatson mtx_unlock(&tp->tap_mtx); 65863803Snsayer splx(s); 65983043Sbrooks break; 66063670Snsayer 66163670Snsayer case FIONREAD: 66263670Snsayer s = splimp(); 66363670Snsayer if (ifp->if_snd.ifq_head) { 66463670Snsayer struct mbuf *mb = ifp->if_snd.ifq_head; 66563670Snsayer 66663803Snsayer for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 66763670Snsayer *(int *)data += mb->m_len; 66883043Sbrooks } else 66963670Snsayer *(int *)data = 0; 67063670Snsayer splx(s); 67183043Sbrooks break; 67263670Snsayer 67363670Snsayer case FIOSETOWN: 67463670Snsayer return (fsetown(*(int *)data, &tp->tap_sigio)); 67563670Snsayer 67663670Snsayer case FIOGETOWN: 677104393Struckman *(int *)data = fgetown(&tp->tap_sigio); 67863670Snsayer return (0); 67963670Snsayer 68063670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 68163670Snsayer case TIOCSPGRP: 68263670Snsayer return (fsetown(-(*(int *)data), &tp->tap_sigio)); 68363670Snsayer 68463670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 68563670Snsayer case TIOCGPGRP: 686104393Struckman *(int *)data = -fgetown(&tp->tap_sigio); 68763670Snsayer return (0); 68863670Snsayer 68963670Snsayer /* VMware/VMnet port ioctl's */ 69063670Snsayer 69163670Snsayer case SIOCGIFFLAGS: /* get ifnet flags */ 69263670Snsayer bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 69383043Sbrooks break; 69463670Snsayer 69583043Sbrooks case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 696102052Ssobomax f = *(int *)data; 69763670Snsayer f &= 0x0fff; 69863670Snsayer f &= ~IFF_CANTCHANGE; 69963670Snsayer f |= IFF_UP; 70063670Snsayer 70163670Snsayer s = splimp(); 70263670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 70363670Snsayer splx(s); 70483043Sbrooks break; 70563670Snsayer 70663861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 70763670Snsayer case SIOCGIFADDR: 708127165Srwatson mtx_lock(&tp->tap_mtx); 70963861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 710127165Srwatson mtx_unlock(&tp->tap_mtx); 71183043Sbrooks break; 71263670Snsayer 71363861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 714127165Srwatson mtx_lock(&tp->tap_mtx); 71563861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 716127165Srwatson mtx_unlock(&tp->tap_mtx); 71783043Sbrooks break; 71863670Snsayer 71963670Snsayer default: 72063670Snsayer return (ENOTTY); 72163670Snsayer } 72263670Snsayer return (0); 72363670Snsayer} /* tapioctl */ 72463670Snsayer 72563670Snsayer 72663670Snsayer/* 72763670Snsayer * tapread 72863670Snsayer * 72963670Snsayer * the cdevsw read interface - reads a packet at a time, or at 73063670Snsayer * least as much of a packet as can be read 73163670Snsayer */ 73263670Snsayerstatic int 73363670Snsayertapread(dev, uio, flag) 734130585Sphk struct cdev *dev; 73563670Snsayer struct uio *uio; 73663670Snsayer int flag; 73763670Snsayer{ 73863670Snsayer struct tap_softc *tp = dev->si_drv1; 73963670Snsayer struct ifnet *ifp = &tp->tap_if; 74090227Sdillon struct mbuf *m = NULL; 74163670Snsayer int error = 0, len, s; 74263670Snsayer 743121816Sbrooks TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev)); 74463670Snsayer 745127098Srwatson mtx_lock(&tp->tap_mtx); 74663670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 747127098Srwatson mtx_unlock(&tp->tap_mtx); 748127098Srwatson 749127098Srwatson /* Unlocked read. */ 750121816Sbrooks TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 751121816Sbrooks ifp->if_xname, minor(dev), tp->tap_flags); 75263803Snsayer 75363670Snsayer return (EHOSTDOWN); 75463670Snsayer } 75563670Snsayer 75663670Snsayer tp->tap_flags &= ~TAP_RWAIT; 757127098Srwatson mtx_unlock(&tp->tap_mtx); 75863670Snsayer 75963670Snsayer /* sleep until we get a packet */ 76063670Snsayer do { 76163670Snsayer s = splimp(); 76290227Sdillon IF_DEQUEUE(&ifp->if_snd, m); 76363670Snsayer splx(s); 76463670Snsayer 76590227Sdillon if (m == NULL) { 766139207Sphk if (flag & O_NONBLOCK) 76763670Snsayer return (EWOULDBLOCK); 768111742Sdes 769127098Srwatson mtx_lock(&tp->tap_mtx); 77063670Snsayer tp->tap_flags |= TAP_RWAIT; 771127098Srwatson mtx_unlock(&tp->tap_mtx); 772111748Sdes error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); 77363670Snsayer if (error) 77463670Snsayer return (error); 77563670Snsayer } 77690227Sdillon } while (m == NULL); 77763670Snsayer 77863670Snsayer /* feed packet to bpf */ 779106939Ssam BPF_MTAP(ifp, m); 78063670Snsayer 78163670Snsayer /* xfer packet to user space */ 78290227Sdillon while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 78390227Sdillon len = min(uio->uio_resid, m->m_len); 78463670Snsayer if (len == 0) 78563670Snsayer break; 78663670Snsayer 787111741Sdes error = uiomove(mtod(m, void *), len, uio); 78890227Sdillon m = m_free(m); 78963670Snsayer } 79063670Snsayer 79190227Sdillon if (m != NULL) { 792121816Sbrooks TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 793121816Sbrooks minor(dev)); 79490227Sdillon m_freem(m); 79563670Snsayer } 79663670Snsayer 79763670Snsayer return (error); 79863670Snsayer} /* tapread */ 79963670Snsayer 80063670Snsayer 80163670Snsayer/* 80263670Snsayer * tapwrite 80363670Snsayer * 80463670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 80563670Snsayer */ 80663670Snsayerstatic int 80763670Snsayertapwrite(dev, uio, flag) 808130585Sphk struct cdev *dev; 80963670Snsayer struct uio *uio; 81063670Snsayer int flag; 81163670Snsayer{ 81263670Snsayer struct tap_softc *tp = dev->si_drv1; 81363670Snsayer struct ifnet *ifp = &tp->tap_if; 814137101Sglebius struct mbuf *m; 815137101Sglebius int error = 0; 81663670Snsayer 817121816Sbrooks TAPDEBUG("%s writting, minor = %#x\n", 818121816Sbrooks ifp->if_xname, minor(dev)); 81963670Snsayer 82063670Snsayer if (uio->uio_resid == 0) 82163670Snsayer return (0); 82263670Snsayer 82363670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 824121816Sbrooks TAPDEBUG("%s invalid packet len = %d, minor = %#x\n", 825121816Sbrooks ifp->if_xname, uio->uio_resid, minor(dev)); 82663803Snsayer 82763670Snsayer return (EIO); 82863670Snsayer } 82963670Snsayer 830145883Semax if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, ETHER_ALIGN)) == NULL) { 83163670Snsayer ifp->if_ierrors ++; 83263670Snsayer return (error); 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 85383366Sjuliantappoll(dev, events, td) 854130585Sphk struct cdev *dev; 85563670Snsayer int events; 85683366Sjulian struct thread *td; 85763670Snsayer{ 85863670Snsayer struct tap_softc *tp = dev->si_drv1; 85963670Snsayer struct ifnet *ifp = &tp->tap_if; 860111742Sdes int s, revents = 0; 86163670Snsayer 862121816Sbrooks TAPDEBUG("%s polling, minor = %#x\n", 863121816Sbrooks ifp->if_xname, minor(dev)); 86463670Snsayer 86563670Snsayer s = splimp(); 86663670Snsayer if (events & (POLLIN | POLLRDNORM)) { 86763670Snsayer if (ifp->if_snd.ifq_len > 0) { 868121816Sbrooks TAPDEBUG("%s have data in queue. len = %d, " \ 869121816Sbrooks "minor = %#x\n", ifp->if_xname, 87083043Sbrooks ifp->if_snd.ifq_len, minor(dev)); 87163803Snsayer 87263670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 87383043Sbrooks } else { 874121816Sbrooks TAPDEBUG("%s waiting for data, minor = %#x\n", 875121816Sbrooks ifp->if_xname, minor(dev)); 87663803Snsayer 87783805Sjhb selrecord(td, &tp->tap_rsel); 87863670Snsayer } 87963670Snsayer } 88063670Snsayer 88163670Snsayer if (events & (POLLOUT | POLLWRNORM)) 88263670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 88363670Snsayer 88463670Snsayer splx(s); 88563670Snsayer return (revents); 88663670Snsayer} /* tappoll */ 887