if_tap.c revision 144389
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 144389 2005-03-31 12:19:44Z phk $ 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 */ 11983043Sbrooksstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 120126077Sphkstatic struct clonedevs *tapclones; 12163670Snsayer 12263670SnsayerMALLOC_DECLARE(M_TAP); 12363670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 12463670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 12563670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL); 12663670Snsayer 12763670Snsayer/* 12863670Snsayer * tapmodevent 12963670Snsayer * 13063670Snsayer * module event handler 13163670Snsayer */ 13263670Snsayerstatic int 13363670Snsayertapmodevent(mod, type, data) 13463670Snsayer module_t mod; 13563670Snsayer int type; 13663670Snsayer void *data; 13763670Snsayer{ 13883043Sbrooks static eventhandler_tag eh_tag = NULL; 13983043Sbrooks struct tap_softc *tp = NULL; 14083043Sbrooks struct ifnet *ifp = NULL; 141126077Sphk int s; 14263670Snsayer 14363670Snsayer switch (type) { 14463670Snsayer case MOD_LOAD: 14563670Snsayer 14683043Sbrooks /* intitialize device */ 14783043Sbrooks 148127003Srwatson mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF); 14983043Sbrooks SLIST_INIT(&taphead); 15083043Sbrooks 151126845Sphk clone_setup(&tapclones); 15271602Sphk eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 153127003Srwatson if (eh_tag == NULL) { 154127170Srwatson clone_cleanup(&tapclones); 155127003Srwatson mtx_destroy(&tapmtx); 156126077Sphk return (ENOMEM); 157127003Srwatson } 15883043Sbrooks return (0); 15963670Snsayer 16083043Sbrooks case MOD_UNLOAD: 161127003Srwatson /* 162127003Srwatson * The EBUSY algorithm here can't quite atomically 163127003Srwatson * guarantee that this is race-free since we have to 164127003Srwatson * release the tap mtx to deregister the clone handler. 165127003Srwatson */ 166127003Srwatson mtx_lock(&tapmtx); 167127003Srwatson SLIST_FOREACH(tp, &taphead, tap_next) { 168127098Srwatson mtx_lock(&tp->tap_mtx); 169127003Srwatson if (tp->tap_flags & TAP_OPEN) { 170127098Srwatson mtx_unlock(&tp->tap_mtx); 171127003Srwatson mtx_unlock(&tapmtx); 17283043Sbrooks return (EBUSY); 173127003Srwatson } 174127098Srwatson mtx_unlock(&tp->tap_mtx); 175127003Srwatson } 176127003Srwatson mtx_unlock(&tapmtx); 17783043Sbrooks 17871602Sphk EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 17963670Snsayer 180127003Srwatson mtx_lock(&tapmtx); 18183043Sbrooks while ((tp = SLIST_FIRST(&taphead)) != NULL) { 18283043Sbrooks SLIST_REMOVE_HEAD(&taphead, tap_next); 183127003Srwatson mtx_unlock(&tapmtx); 18483043Sbrooks 18583043Sbrooks ifp = &tp->tap_if; 18683043Sbrooks 187121816Sbrooks TAPDEBUG("detaching %s\n", ifp->if_xname); 18883043Sbrooks 189127098Srwatson /* Unlocked read. */ 190121816Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 191121816Sbrooks ("%s flags is out of sync", ifp->if_xname)); 19283043Sbrooks 193126077Sphk destroy_dev(tp->tap_dev); 19463670Snsayer s = splimp(); 195106939Ssam ether_ifdetach(ifp); 19663670Snsayer splx(s); 19763670Snsayer 198127098Srwatson mtx_destroy(&tp->tap_mtx); 19993752Sluigi free(tp, M_TAP); 200127003Srwatson mtx_lock(&tapmtx); 20183043Sbrooks } 202127003Srwatson mtx_unlock(&tapmtx); 203126077Sphk clone_cleanup(&tapclones); 20463670Snsayer 205135354Srwatson mtx_destroy(&tapmtx); 206135354Srwatson 20783043Sbrooks break; 20863670Snsayer 20963670Snsayer default: 21063670Snsayer return (EOPNOTSUPP); 21163670Snsayer } 21263670Snsayer 21363670Snsayer return (0); 21463670Snsayer} /* tapmodevent */ 21563670Snsayer 21663670Snsayer 21763670Snsayer/* 21871602Sphk * DEVFS handler 21971602Sphk * 22071602Sphk * We need to support two kind of devices - tap and vmnet 22171602Sphk */ 22271602Sphkstatic void 22371602Sphktapclone(arg, name, namelen, dev) 22471602Sphk void *arg; 22571602Sphk char *name; 22671602Sphk int namelen; 227130585Sphk struct cdev **dev; 22871602Sphk{ 229126077Sphk u_int extra; 230126077Sphk int i, unit; 23183043Sbrooks char *device_name = name; 23271602Sphk 233130640Sphk if (*dev != NULL) 23471602Sphk return; 23571602Sphk 236126077Sphk device_name = TAP; 237126077Sphk extra = 0; 238126077Sphk if (strcmp(name, TAP) == 0) { 239126077Sphk unit = -1; 240126077Sphk } else if (strcmp(name, VMNET) == 0) { 241126077Sphk device_name = VMNET; 242126077Sphk extra = VMNET_DEV_MASK; 243126077Sphk unit = -1; 244126077Sphk } else if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 245126077Sphk device_name = VMNET; 246126077Sphk extra = VMNET_DEV_MASK; 247126077Sphk if (dev_stdclone(name, NULL, device_name, &unit) != 1) 248126077Sphk return; 24983043Sbrooks } 25071602Sphk 251126077Sphk /* find any existing device, or allocate new unit number */ 252126077Sphk i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra); 253126077Sphk if (i) { 254126796Sphk *dev = make_dev(&tap_cdevsw, unit2minor(unit | extra), 255126077Sphk UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit); 256144389Sphk if (*dev != NULL) { 257144389Sphk dev_ref(*dev); 258126077Sphk (*dev)->si_flags |= SI_CHEAPCLONE; 259144389Sphk } 26071602Sphk } 26171602Sphk} /* tapclone */ 26271602Sphk 26371602Sphk 26471602Sphk/* 26563670Snsayer * tapcreate 26663670Snsayer * 26763670Snsayer * to create interface 26863670Snsayer */ 26963670Snsayerstatic void 27063670Snsayertapcreate(dev) 271130585Sphk struct cdev *dev; 27263670Snsayer{ 27363670Snsayer struct ifnet *ifp = NULL; 27463670Snsayer struct tap_softc *tp = NULL; 27563670Snsayer unsigned short macaddr_hi; 27663803Snsayer int unit, s; 27763670Snsayer char *name = NULL; 27863670Snsayer 279126077Sphk dev->si_flags &= ~SI_CHEAPCLONE; 280126077Sphk 28163670Snsayer /* allocate driver storage and create device */ 282111119Simp MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 283127098Srwatson mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF); 284127003Srwatson mtx_lock(&tapmtx); 28583043Sbrooks SLIST_INSERT_HEAD(&taphead, tp, tap_next); 286127003Srwatson mtx_unlock(&tapmtx); 28763670Snsayer 288126796Sphk unit = dev2unit(dev); 28983043Sbrooks 29063670Snsayer /* select device: tap or vmnet */ 291126796Sphk if (unit & VMNET_DEV_MASK) { 29263670Snsayer name = VMNET; 29363803Snsayer tp->tap_flags |= TAP_VMNET; 29483043Sbrooks } else 29563670Snsayer name = TAP; 29663670Snsayer 297126796Sphk unit &= TAPMAXUNIT; 298126796Sphk 29983043Sbrooks TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 30083043Sbrooks 30163670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 30263670Snsayer macaddr_hi = htons(0x00bd); 30363670Snsayer bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 30463670Snsayer bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 30563670Snsayer tp->arpcom.ac_enaddr[5] = (u_char)unit; 30663670Snsayer 307111742Sdes /* fill the rest and attach interface */ 30863670Snsayer ifp = &tp->tap_if; 30963670Snsayer ifp->if_softc = tp; 310121816Sbrooks if_initname(ifp, name, unit); 31163670Snsayer ifp->if_init = tapifinit; 31263670Snsayer ifp->if_start = tapifstart; 31363670Snsayer ifp->if_ioctl = tapifioctl; 31463670Snsayer ifp->if_mtu = ETHERMTU; 31563670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 31663670Snsayer ifp->if_snd.ifq_maxlen = ifqmaxlen; 31763670Snsayer 31883043Sbrooks dev->si_drv1 = tp; 319126077Sphk tp->tap_dev = dev; 32083043Sbrooks 32163803Snsayer s = splimp(); 322106939Ssam ether_ifattach(ifp, tp->arpcom.ac_enaddr); 32363803Snsayer splx(s); 32463670Snsayer 325127098Srwatson mtx_lock(&tp->tap_mtx); 32663803Snsayer tp->tap_flags |= TAP_INITED; 327127098Srwatson mtx_unlock(&tp->tap_mtx); 32863803Snsayer 329121816Sbrooks TAPDEBUG("interface %s is created. minor = %#x\n", 330121816Sbrooks ifp->if_xname, minor(dev)); 33163670Snsayer} /* tapcreate */ 33263670Snsayer 33363670Snsayer 33463670Snsayer/* 335111742Sdes * tapopen 33663670Snsayer * 33763670Snsayer * to open tunnel. must be superuser 33863670Snsayer */ 33963670Snsayerstatic int 34083366Sjuliantapopen(dev, flag, mode, td) 341130585Sphk struct cdev *dev; 34263670Snsayer int flag; 34363670Snsayer int mode; 34483366Sjulian struct thread *td; 34563670Snsayer{ 34663670Snsayer struct tap_softc *tp = NULL; 347133460Semax struct ifnet *ifp = NULL; 348133460Semax int error, s; 34963670Snsayer 35093593Sjhb if ((error = suser(td)) != 0) 35163670Snsayer return (error); 35263670Snsayer 353126796Sphk if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT) 354126796Sphk return (ENXIO); 35583043Sbrooks 356127165Srwatson /* 357127165Srwatson * XXXRW: Non-atomic test-and-set of si_drv1. Currently protected 358127165Srwatson * by Giant, but the race actually exists under memory pressure as 359127165Srwatson * well even when running with Giant, as malloc() may sleep. 360127165Srwatson */ 36163670Snsayer tp = dev->si_drv1; 36263670Snsayer if (tp == NULL) { 36363670Snsayer tapcreate(dev); 36463670Snsayer tp = dev->si_drv1; 36563670Snsayer } 36663670Snsayer 367127165Srwatson mtx_lock(&tp->tap_mtx); 368127165Srwatson if (tp->tap_flags & TAP_OPEN) { 369127165Srwatson mtx_unlock(&tp->tap_mtx); 370127165Srwatson return (EBUSY); 371127165Srwatson } 37263670Snsayer 37363861Snsayer bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 37483366Sjulian tp->tap_pid = td->td_proc->p_pid; 37563670Snsayer tp->tap_flags |= TAP_OPEN; 376133460Semax ifp = &tp->tap_if; 377127098Srwatson mtx_unlock(&tp->tap_mtx); 37863670Snsayer 379133460Semax s = splimp(); 380133460Semax ifp->if_flags |= IFF_RUNNING; 381133460Semax ifp->if_flags &= ~IFF_OACTIVE; 382133460Semax splx(s); 38363670Snsayer 384133460Semax TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev)); 385133460Semax 38663670Snsayer return (0); 38763670Snsayer} /* tapopen */ 38863670Snsayer 38963670Snsayer 39063670Snsayer/* 39163670Snsayer * tapclose 39263670Snsayer * 39363670Snsayer * close the device - mark i/f down & delete routing info 39463670Snsayer */ 39563670Snsayerstatic int 39683366Sjuliantapclose(dev, foo, bar, td) 397130585Sphk struct cdev *dev; 39863670Snsayer int foo; 39963670Snsayer int bar; 40083366Sjulian struct thread *td; 40163670Snsayer{ 40263670Snsayer struct tap_softc *tp = dev->si_drv1; 40363670Snsayer struct ifnet *ifp = &tp->tap_if; 404126077Sphk int s; 40563670Snsayer 40663670Snsayer /* junk all pending output */ 40783043Sbrooks IF_DRAIN(&ifp->if_snd); 40863670Snsayer 40963803Snsayer /* 41063803Snsayer * do not bring the interface down, and do not anything with 41163803Snsayer * interface, if we are in VMnet mode. just close the device. 41263803Snsayer */ 41363803Snsayer 414127098Srwatson mtx_lock(&tp->tap_mtx); 41563803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 416127098Srwatson mtx_unlock(&tp->tap_mtx); 41763670Snsayer s = splimp(); 41863670Snsayer if_down(ifp); 41963670Snsayer if (ifp->if_flags & IFF_RUNNING) { 42063670Snsayer /* find internet addresses and delete routes */ 42163670Snsayer struct ifaddr *ifa = NULL; 42263670Snsayer 423127098Srwatson /* In desparate need of ifaddr locking. */ 42463803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 42563670Snsayer if (ifa->ifa_addr->sa_family == AF_INET) { 42663670Snsayer rtinit(ifa, (int)RTM_DELETE, 0); 42763670Snsayer 42863670Snsayer /* remove address from interface */ 429111742Sdes bzero(ifa->ifa_addr, 43063670Snsayer sizeof(*(ifa->ifa_addr))); 431111742Sdes bzero(ifa->ifa_dstaddr, 43263670Snsayer sizeof(*(ifa->ifa_dstaddr))); 433111742Sdes bzero(ifa->ifa_netmask, 43463670Snsayer sizeof(*(ifa->ifa_netmask))); 43563670Snsayer } 43663670Snsayer } 43763670Snsayer 43863670Snsayer ifp->if_flags &= ~IFF_RUNNING; 43963670Snsayer } 44063670Snsayer splx(s); 441127098Srwatson } else 442127098Srwatson mtx_unlock(&tp->tap_mtx); 44363670Snsayer 44496122Salfred funsetown(&tp->tap_sigio); 445122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 44663670Snsayer 447127098Srwatson mtx_lock(&tp->tap_mtx); 44863670Snsayer tp->tap_flags &= ~TAP_OPEN; 44963670Snsayer tp->tap_pid = 0; 450127098Srwatson mtx_unlock(&tp->tap_mtx); 45163670Snsayer 452121816Sbrooks TAPDEBUG("%s is closed. minor = %#x\n", 453121816Sbrooks ifp->if_xname, minor(dev)); 45463670Snsayer 45563670Snsayer return (0); 45663670Snsayer} /* tapclose */ 45763670Snsayer 45863670Snsayer 45963670Snsayer/* 46063670Snsayer * tapifinit 46163670Snsayer * 46263670Snsayer * network interface initialization function 46363670Snsayer */ 46463670Snsayerstatic void 46563670Snsayertapifinit(xtp) 46663670Snsayer void *xtp; 46763670Snsayer{ 46863670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 46963670Snsayer struct ifnet *ifp = &tp->tap_if; 47063670Snsayer 471121816Sbrooks TAPDEBUG("initializing %s\n", ifp->if_xname); 47263670Snsayer 47363670Snsayer ifp->if_flags |= IFF_RUNNING; 47463670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 47563670Snsayer 47663670Snsayer /* attempt to start output */ 47763670Snsayer tapifstart(ifp); 47863670Snsayer} /* tapifinit */ 47963670Snsayer 48063670Snsayer 48163670Snsayer/* 48263670Snsayer * tapifioctl 48363670Snsayer * 48463670Snsayer * Process an ioctl request on network interface 48563670Snsayer */ 486105228Sphkstatic int 48763670Snsayertapifioctl(ifp, cmd, data) 48863670Snsayer struct ifnet *ifp; 48963670Snsayer u_long cmd; 49063670Snsayer caddr_t data; 49163670Snsayer{ 492111742Sdes struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 49363670Snsayer struct ifstat *ifs = NULL; 49463670Snsayer int s, dummy; 49563670Snsayer 49663670Snsayer switch (cmd) { 49763670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 49863670Snsayer case SIOCADDMULTI: 49963670Snsayer case SIOCDELMULTI: 50083043Sbrooks break; 50163670Snsayer 50263670Snsayer case SIOCGIFSTATUS: 50363670Snsayer s = splimp(); 50463670Snsayer ifs = (struct ifstat *)data; 50563670Snsayer dummy = strlen(ifs->ascii); 506127098Srwatson mtx_lock(&tp->tap_mtx); 50763670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 50863670Snsayer snprintf(ifs->ascii + dummy, 50963670Snsayer sizeof(ifs->ascii) - dummy, 51063670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 511127098Srwatson mtx_unlock(&tp->tap_mtx); 51263670Snsayer splx(s); 51383043Sbrooks break; 51463670Snsayer 51563670Snsayer default: 516106939Ssam s = splimp(); 517106939Ssam dummy = ether_ioctl(ifp, cmd, data); 518106939Ssam splx(s); 519106939Ssam return (dummy); 52063670Snsayer } 52163670Snsayer 52263670Snsayer return (0); 52363670Snsayer} /* tapifioctl */ 52463670Snsayer 52563670Snsayer 52663670Snsayer/* 527111742Sdes * tapifstart 528111742Sdes * 52963670Snsayer * queue packets from higher level ready to put out 53063670Snsayer */ 53163670Snsayerstatic void 53263670Snsayertapifstart(ifp) 53363670Snsayer struct ifnet *ifp; 53463670Snsayer{ 53563670Snsayer struct tap_softc *tp = ifp->if_softc; 53663670Snsayer int s; 53763670Snsayer 538121816Sbrooks TAPDEBUG("%s starting\n", ifp->if_xname); 53963670Snsayer 54063803Snsayer /* 54163803Snsayer * do not junk pending output if we are in VMnet mode. 54263803Snsayer * XXX: can this do any harm because of queue overflow? 54363803Snsayer */ 54463803Snsayer 545127098Srwatson mtx_lock(&tp->tap_mtx); 546111742Sdes if (((tp->tap_flags & TAP_VMNET) == 0) && 54763803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 54863670Snsayer struct mbuf *m = NULL; 54963670Snsayer 550127098Srwatson mtx_unlock(&tp->tap_mtx); 551127098Srwatson 552127098Srwatson /* Unlocked read. */ 553121816Sbrooks TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 554121816Sbrooks tp->tap_flags); 55563670Snsayer 55663670Snsayer s = splimp(); 55763670Snsayer do { 55863670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 55963670Snsayer if (m != NULL) 56063670Snsayer m_freem(m); 56163670Snsayer ifp->if_oerrors ++; 56263670Snsayer } while (m != NULL); 56363670Snsayer splx(s); 56463670Snsayer 56563670Snsayer return; 56663670Snsayer } 567127098Srwatson mtx_unlock(&tp->tap_mtx); 56863670Snsayer 56963670Snsayer s = splimp(); 57063670Snsayer ifp->if_flags |= IFF_OACTIVE; 57163670Snsayer 57263670Snsayer if (ifp->if_snd.ifq_len != 0) { 573127098Srwatson mtx_lock(&tp->tap_mtx); 57463670Snsayer if (tp->tap_flags & TAP_RWAIT) { 57563670Snsayer tp->tap_flags &= ~TAP_RWAIT; 576111748Sdes wakeup(tp); 57763670Snsayer } 57863670Snsayer 579127098Srwatson if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) { 580127098Srwatson mtx_unlock(&tp->tap_mtx); 58195883Salfred pgsigio(&tp->tap_sigio, SIGIO, 0); 582127098Srwatson } else 583127098Srwatson mtx_unlock(&tp->tap_mtx); 58463670Snsayer 585122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 58663670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 58763670Snsayer } 58863670Snsayer 58963670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 59063670Snsayer splx(s); 59163670Snsayer} /* tapifstart */ 59263670Snsayer 59363670Snsayer 59463670Snsayer/* 59563670Snsayer * tapioctl 59663670Snsayer * 59763670Snsayer * the cdevsw interface is now pretty minimal 59863670Snsayer */ 59963670Snsayerstatic int 60083366Sjuliantapioctl(dev, cmd, data, flag, td) 601130585Sphk struct cdev *dev; 60263670Snsayer u_long cmd; 60363670Snsayer caddr_t data; 60463670Snsayer int flag; 60583366Sjulian struct thread *td; 60663670Snsayer{ 60763670Snsayer struct tap_softc *tp = dev->si_drv1; 60863670Snsayer struct ifnet *ifp = &tp->tap_if; 609111742Sdes struct tapinfo *tapp = NULL; 61063670Snsayer int s; 611102052Ssobomax int f; 61263670Snsayer 61363670Snsayer switch (cmd) { 614111742Sdes case TAPSIFINFO: 61563670Snsayer s = splimp(); 616111742Sdes tapp = (struct tapinfo *)data; 617111742Sdes ifp->if_mtu = tapp->mtu; 618111742Sdes ifp->if_type = tapp->type; 619111742Sdes ifp->if_baudrate = tapp->baudrate; 62063670Snsayer splx(s); 621111742Sdes break; 62263670Snsayer 623111742Sdes case TAPGIFINFO: 624111742Sdes tapp = (struct tapinfo *)data; 625111742Sdes tapp->mtu = ifp->if_mtu; 626111742Sdes tapp->type = ifp->if_type; 627111742Sdes tapp->baudrate = ifp->if_baudrate; 628111742Sdes break; 62963670Snsayer 63063670Snsayer case TAPSDEBUG: 63163670Snsayer tapdebug = *(int *)data; 63283043Sbrooks break; 63363670Snsayer 63463670Snsayer case TAPGDEBUG: 63563670Snsayer *(int *)data = tapdebug; 63683043Sbrooks break; 63763670Snsayer 63863670Snsayer case FIONBIO: 63983043Sbrooks break; 64063670Snsayer 64163670Snsayer case FIOASYNC: 64263803Snsayer s = splimp(); 643127098Srwatson mtx_lock(&tp->tap_mtx); 64463670Snsayer if (*(int *)data) 64563670Snsayer tp->tap_flags |= TAP_ASYNC; 64663670Snsayer else 64763670Snsayer tp->tap_flags &= ~TAP_ASYNC; 648127098Srwatson mtx_unlock(&tp->tap_mtx); 64963803Snsayer splx(s); 65083043Sbrooks break; 65163670Snsayer 65263670Snsayer case FIONREAD: 65363670Snsayer s = splimp(); 65463670Snsayer if (ifp->if_snd.ifq_head) { 65563670Snsayer struct mbuf *mb = ifp->if_snd.ifq_head; 65663670Snsayer 65763803Snsayer for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 65863670Snsayer *(int *)data += mb->m_len; 65983043Sbrooks } else 66063670Snsayer *(int *)data = 0; 66163670Snsayer splx(s); 66283043Sbrooks break; 66363670Snsayer 66463670Snsayer case FIOSETOWN: 66563670Snsayer return (fsetown(*(int *)data, &tp->tap_sigio)); 66663670Snsayer 66763670Snsayer case FIOGETOWN: 668104393Struckman *(int *)data = fgetown(&tp->tap_sigio); 66963670Snsayer return (0); 67063670Snsayer 67163670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 67263670Snsayer case TIOCSPGRP: 67363670Snsayer return (fsetown(-(*(int *)data), &tp->tap_sigio)); 67463670Snsayer 67563670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 67663670Snsayer case TIOCGPGRP: 677104393Struckman *(int *)data = -fgetown(&tp->tap_sigio); 67863670Snsayer return (0); 67963670Snsayer 68063670Snsayer /* VMware/VMnet port ioctl's */ 68163670Snsayer 68263670Snsayer case SIOCGIFFLAGS: /* get ifnet flags */ 68363670Snsayer bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 68483043Sbrooks break; 68563670Snsayer 68683043Sbrooks case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 687102052Ssobomax f = *(int *)data; 68863670Snsayer f &= 0x0fff; 68963670Snsayer f &= ~IFF_CANTCHANGE; 69063670Snsayer f |= IFF_UP; 69163670Snsayer 69263670Snsayer s = splimp(); 69363670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 69463670Snsayer splx(s); 69583043Sbrooks break; 69663670Snsayer 69763861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 69863670Snsayer case SIOCGIFADDR: 699127165Srwatson mtx_lock(&tp->tap_mtx); 70063861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 701127165Srwatson mtx_unlock(&tp->tap_mtx); 70283043Sbrooks break; 70363670Snsayer 70463861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 705127165Srwatson mtx_lock(&tp->tap_mtx); 70663861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 707127165Srwatson mtx_unlock(&tp->tap_mtx); 70883043Sbrooks break; 70963670Snsayer 71063670Snsayer default: 71163670Snsayer return (ENOTTY); 71263670Snsayer } 71363670Snsayer return (0); 71463670Snsayer} /* tapioctl */ 71563670Snsayer 71663670Snsayer 71763670Snsayer/* 71863670Snsayer * tapread 71963670Snsayer * 72063670Snsayer * the cdevsw read interface - reads a packet at a time, or at 72163670Snsayer * least as much of a packet as can be read 72263670Snsayer */ 72363670Snsayerstatic int 72463670Snsayertapread(dev, uio, flag) 725130585Sphk struct cdev *dev; 72663670Snsayer struct uio *uio; 72763670Snsayer int flag; 72863670Snsayer{ 72963670Snsayer struct tap_softc *tp = dev->si_drv1; 73063670Snsayer struct ifnet *ifp = &tp->tap_if; 73190227Sdillon struct mbuf *m = NULL; 73263670Snsayer int error = 0, len, s; 73363670Snsayer 734121816Sbrooks TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev)); 73563670Snsayer 736127098Srwatson mtx_lock(&tp->tap_mtx); 73763670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 738127098Srwatson mtx_unlock(&tp->tap_mtx); 739127098Srwatson 740127098Srwatson /* Unlocked read. */ 741121816Sbrooks TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 742121816Sbrooks ifp->if_xname, minor(dev), tp->tap_flags); 74363803Snsayer 74463670Snsayer return (EHOSTDOWN); 74563670Snsayer } 74663670Snsayer 74763670Snsayer tp->tap_flags &= ~TAP_RWAIT; 748127098Srwatson mtx_unlock(&tp->tap_mtx); 74963670Snsayer 75063670Snsayer /* sleep until we get a packet */ 75163670Snsayer do { 75263670Snsayer s = splimp(); 75390227Sdillon IF_DEQUEUE(&ifp->if_snd, m); 75463670Snsayer splx(s); 75563670Snsayer 75690227Sdillon if (m == NULL) { 757139207Sphk if (flag & O_NONBLOCK) 75863670Snsayer return (EWOULDBLOCK); 759111742Sdes 760127098Srwatson mtx_lock(&tp->tap_mtx); 76163670Snsayer tp->tap_flags |= TAP_RWAIT; 762127098Srwatson mtx_unlock(&tp->tap_mtx); 763111748Sdes error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); 76463670Snsayer if (error) 76563670Snsayer return (error); 76663670Snsayer } 76790227Sdillon } while (m == NULL); 76863670Snsayer 76963670Snsayer /* feed packet to bpf */ 770106939Ssam BPF_MTAP(ifp, m); 77163670Snsayer 77263670Snsayer /* xfer packet to user space */ 77390227Sdillon while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 77490227Sdillon len = min(uio->uio_resid, m->m_len); 77563670Snsayer if (len == 0) 77663670Snsayer break; 77763670Snsayer 778111741Sdes error = uiomove(mtod(m, void *), len, uio); 77990227Sdillon m = m_free(m); 78063670Snsayer } 78163670Snsayer 78290227Sdillon if (m != NULL) { 783121816Sbrooks TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 784121816Sbrooks minor(dev)); 78590227Sdillon m_freem(m); 78663670Snsayer } 78763670Snsayer 78863670Snsayer return (error); 78963670Snsayer} /* tapread */ 79063670Snsayer 79163670Snsayer 79263670Snsayer/* 79363670Snsayer * tapwrite 79463670Snsayer * 79563670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 79663670Snsayer */ 79763670Snsayerstatic int 79863670Snsayertapwrite(dev, uio, flag) 799130585Sphk struct cdev *dev; 80063670Snsayer struct uio *uio; 80163670Snsayer int flag; 80263670Snsayer{ 80363670Snsayer struct tap_softc *tp = dev->si_drv1; 80463670Snsayer struct ifnet *ifp = &tp->tap_if; 805137101Sglebius struct mbuf *m; 806137101Sglebius int error = 0; 80763670Snsayer 808121816Sbrooks TAPDEBUG("%s writting, minor = %#x\n", 809121816Sbrooks ifp->if_xname, minor(dev)); 81063670Snsayer 81163670Snsayer if (uio->uio_resid == 0) 81263670Snsayer return (0); 81363670Snsayer 81463670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 815121816Sbrooks TAPDEBUG("%s invalid packet len = %d, minor = %#x\n", 816121816Sbrooks ifp->if_xname, uio->uio_resid, minor(dev)); 81763803Snsayer 81863670Snsayer return (EIO); 81963670Snsayer } 82063670Snsayer 821137101Sglebius if ((m = m_uiotombuf(uio, M_DONTWAIT, 0)) == NULL) { 82263670Snsayer ifp->if_ierrors ++; 82363670Snsayer return (error); 82463670Snsayer } 82563670Snsayer 826137101Sglebius m->m_pkthdr.rcvif = ifp; 827111742Sdes 828106939Ssam /* Pass packet up to parent. */ 829137101Sglebius (*ifp->if_input)(ifp, m); 830106939Ssam ifp->if_ipackets ++; /* ibytes are counted in parent */ 83163670Snsayer 83263670Snsayer return (0); 83363670Snsayer} /* tapwrite */ 83463670Snsayer 83563670Snsayer 83663670Snsayer/* 83763670Snsayer * tappoll 83863670Snsayer * 83963670Snsayer * the poll interface, this is only useful on reads 84063670Snsayer * really. the write detect always returns true, write never blocks 84163670Snsayer * anyway, it either accepts the packet or drops it 84263670Snsayer */ 84363670Snsayerstatic int 84483366Sjuliantappoll(dev, events, td) 845130585Sphk struct cdev *dev; 84663670Snsayer int events; 84783366Sjulian struct thread *td; 84863670Snsayer{ 84963670Snsayer struct tap_softc *tp = dev->si_drv1; 85063670Snsayer struct ifnet *ifp = &tp->tap_if; 851111742Sdes int s, revents = 0; 85263670Snsayer 853121816Sbrooks TAPDEBUG("%s polling, minor = %#x\n", 854121816Sbrooks ifp->if_xname, minor(dev)); 85563670Snsayer 85663670Snsayer s = splimp(); 85763670Snsayer if (events & (POLLIN | POLLRDNORM)) { 85863670Snsayer if (ifp->if_snd.ifq_len > 0) { 859121816Sbrooks TAPDEBUG("%s have data in queue. len = %d, " \ 860121816Sbrooks "minor = %#x\n", ifp->if_xname, 86183043Sbrooks ifp->if_snd.ifq_len, minor(dev)); 86263803Snsayer 86363670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 86483043Sbrooks } else { 865121816Sbrooks TAPDEBUG("%s waiting for data, minor = %#x\n", 866121816Sbrooks ifp->if_xname, minor(dev)); 86763803Snsayer 86883805Sjhb selrecord(td, &tp->tap_rsel); 86963670Snsayer } 87063670Snsayer } 87163670Snsayer 87263670Snsayer if (events & (POLLOUT | POLLWRNORM)) 87363670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 87463670Snsayer 87563670Snsayer splx(s); 87663670Snsayer return (revents); 87763670Snsayer} /* tappoll */ 878