if_tap.c revision 93752
1113288Smdodd/* 2113288Smdodd * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com> 3113288Smdodd * All rights reserved. 4113288Smdodd * 5113288Smdodd * Redistribution and use in source and binary forms, with or without 6113288Smdodd * modification, are permitted provided that the following conditions 7113288Smdodd * are met: 8113288Smdodd * 1. Redistributions of source code must retain the above copyright 9113288Smdodd * notice, this list of conditions and the following disclaimer. 10113288Smdodd * 2. Redistributions in binary form must reproduce the above copyright 11113288Smdodd * notice, this list of conditions and the following disclaimer in the 12113288Smdodd * documentation and/or other materials provided with the distribution. 13113288Smdodd * 14113288Smdodd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15113288Smdodd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16113288Smdodd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17113288Smdodd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18113288Smdodd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19113288Smdodd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20113288Smdodd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21113288Smdodd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22113288Smdodd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23113288Smdodd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24113288Smdodd * SUCH DAMAGE. 25113288Smdodd * 26113288Smdodd * BASED ON: 27113288Smdodd * ------------------------------------------------------------------------- 28113288Smdodd * 29113288Smdodd * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> 30113288Smdodd * Nottingham University 1987. 31113288Smdodd */ 32113288Smdodd 33113288Smdodd/* 34113288Smdodd * $FreeBSD: head/sys/net/if_tap.c 93752 2002-04-04 06:03:17Z luigi $ 35113288Smdodd * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ 36113288Smdodd */ 37113288Smdodd 38113288Smdodd#include "opt_inet.h" 39113288Smdodd 40113288Smdodd#include <sys/param.h> 41113288Smdodd#include <sys/conf.h> 42113288Smdodd#include <sys/filedesc.h> 43113288Smdodd#include <sys/filio.h> 44113288Smdodd#include <sys/kernel.h> 45113288Smdodd#include <sys/malloc.h> 46113288Smdodd#include <sys/mbuf.h> 47113288Smdodd#include <sys/poll.h> 48113288Smdodd#include <sys/proc.h> 49188945Sthompsa#include <sys/signalvar.h> 50113288Smdodd#include <sys/socket.h> 51113288Smdodd#include <sys/sockio.h> 52113288Smdodd#include <sys/sysctl.h> 53113288Smdodd#include <sys/systm.h> 54113288Smdodd#include <sys/ttycom.h> 55113288Smdodd#include <sys/uio.h> 56113288Smdodd#include <sys/vnode.h> 57113288Smdodd#include <machine/bus.h> /* XXX: Shouldn't really be required! */ 58113288Smdodd#include <sys/rman.h> 59126774Sdwmalone#include <sys/queue.h> 60113288Smdodd 61113288Smdodd#include <net/bpf.h> 62113288Smdodd#include <net/ethernet.h> 63113288Smdodd#include <net/if.h> 64113288Smdodd#include <net/if_arp.h> 65113288Smdodd#include <net/route.h> 66113288Smdodd 67113309Smdodd#include <netinet/in.h> 68113309Smdodd 69113309Smdodd#include <net/if_tapvar.h> 70113288Smdodd#include <net/if_tap.h> 71113288Smdodd 72113288Smdodd 73113288Smdodd#define CDEV_NAME "tap" 74113288Smdodd#define CDEV_MAJOR 149 75113288Smdodd#define TAPDEBUG if (tapdebug) printf 76113288Smdodd 77113288Smdodd#define TAP "tap" 78113288Smdodd#define VMNET "vmnet" 79113288Smdodd#define TAPMAXUNIT 0x7fff 80113288Smdodd#define VMNET_DEV_MASK 0x00800000 81113288Smdodd /* 0x007f00ff */ 82113288Smdodd 83113288Smdodd/* module */ 84126774Sdwmalonestatic int tapmodevent(module_t, int, void *); 85113288Smdodd 86113288Smdodd/* device */ 87113288Smdoddstatic void tapclone(void *, char *, int, dev_t *); 88113288Smdoddstatic void tapcreate(dev_t); 89113288Smdodd 90113288Smdodd/* network interface */ 91113288Smdoddstatic void tapifstart(struct ifnet *); 92113288Smdoddstatic int tapifioctl(struct ifnet *, u_long, caddr_t); 93113288Smdoddstatic void tapifinit(void *); 94171101Simp 95126774Sdwmalone/* character device */ 96126774Sdwmalonestatic d_open_t tapopen; 97113309Smdoddstatic d_close_t tapclose; 98113288Smdoddstatic d_read_t tapread; 99113288Smdoddstatic d_write_t tapwrite; 100113288Smdoddstatic d_ioctl_t tapioctl; 101113288Smdoddstatic d_poll_t tappoll; 102113288Smdodd 103113288Smdoddstatic struct cdevsw tap_cdevsw = { 104113288Smdodd /* open */ tapopen, 105113288Smdodd /* close */ tapclose, 106113309Smdodd /* read */ tapread, 107171101Simp /* write */ tapwrite, 108113288Smdodd /* ioctl */ tapioctl, 109113288Smdodd /* poll */ tappoll, 110113288Smdodd /* mmap */ nommap, 111113288Smdodd /* startegy */ nostrategy, 112113288Smdodd /* dev name */ CDEV_NAME, 113113288Smdodd /* dev major */ CDEV_MAJOR, 114113288Smdodd /* dump */ nodump, 115113309Smdodd /* psize */ nopsize, 116113309Smdodd /* flags */ 0, 117113309Smdodd}; 118113288Smdodd 119113288Smdoddstatic int tapdebug = 0; /* debug flag */ 120113288Smdoddstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 121113288Smdoddstatic udev_t tapbasedev = NOUDEV; /* base device */ 122113288Smdoddstatic struct rman tapdevunits[2]; /* device units */ 123113288Smdodd#define tapunits tapdevunits 124113288Smdodd#define vmnetunits (tapdevunits + 1) 125113288Smdodd 126113288SmdoddMALLOC_DECLARE(M_TAP); 127171101SimpMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 128171101SimpSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 129171101SimpDEV_MODULE(if_tap, tapmodevent, NULL); 130113288Smdodd 131113288Smdodd/* 132113288Smdodd * tapmodevent 133113288Smdodd * 134113288Smdodd * module event handler 135113288Smdodd */ 136113288Smdoddstatic int 137113288Smdoddtapmodevent(mod, type, data) 138113288Smdodd module_t mod; 139113288Smdodd int type; 140113288Smdodd void *data; 141113288Smdodd{ 142113288Smdodd static eventhandler_tag eh_tag = NULL; 143113288Smdodd struct tap_softc *tp = NULL; 144113288Smdodd struct ifnet *ifp = NULL; 145171101Simp int error, s; 146113288Smdodd 147113288Smdodd switch (type) { 148113288Smdodd case MOD_LOAD: 149113288Smdodd /* initialize resources */ 150113288Smdodd tapunits->rm_type = RMAN_ARRAY; 151113288Smdodd tapunits->rm_descr = "open tap units"; 152113288Smdodd vmnetunits->rm_type = RMAN_ARRAY; 153113288Smdodd vmnetunits->rm_descr = "open vmnet units"; 154113288Smdodd 155113288Smdodd error = rman_init(tapunits); 156187994Salfred if (error != 0) 157113288Smdodd goto bail; 158113288Smdodd 159113288Smdodd error = rman_init(vmnetunits); 160113288Smdodd if (error != 0) 161113288Smdodd goto bail1; 162113288Smdodd 163126774Sdwmalone error = rman_manage_region(tapunits, 0, TAPMAXUNIT); 164113288Smdodd if (error != 0) 165113288Smdodd goto bail2; 166126774Sdwmalone 167113288Smdodd error = rman_manage_region(vmnetunits, 0, TAPMAXUNIT); 168113288Smdodd if (error != 0) 169113288Smdodd goto bail2; 170113288Smdodd 171113288Smdodd /* intitialize device */ 172113288Smdodd 173113288Smdodd SLIST_INIT(&taphead); 174113288Smdodd 175126774Sdwmalone eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 176126774Sdwmalone if (eh_tag == NULL) { 177126774Sdwmalone error = ENOMEM; 178126774Sdwmalone goto bail2; 179113288Smdodd } 180113288Smdodd 181113288Smdodd if (!devfs_present) { 182113309Smdodd error = cdevsw_add(&tap_cdevsw); 183113309Smdodd if (error != 0) { 184113288Smdodd EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 185113288Smdodd goto bail2; 186113288Smdodd } 187113288Smdodd } 188113288Smdodd 189113288Smdodd return (0); 190113288Smdoddbail2: 191113288Smdodd rman_fini(vmnetunits); 192113288Smdoddbail1: 193113288Smdodd rman_fini(tapunits); 194113288Smdoddbail: 195113288Smdodd return (error); 196113288Smdodd 197113288Smdodd case MOD_UNLOAD: 198113288Smdodd SLIST_FOREACH(tp, &taphead, tap_next) 199113288Smdodd if (tp->tap_unit != NULL) 200113288Smdodd return (EBUSY); 201113288Smdodd 202113288Smdodd EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 203113288Smdodd 204113288Smdodd error = rman_fini(tapunits); 205113288Smdodd KASSERT((error == 0), ("Could not fini tap units")); 206113288Smdodd error = rman_fini(vmnetunits); 207113288Smdodd KASSERT((error == 0), ("Could not fini vmnet units")); 208113309Smdodd 209113309Smdodd while ((tp = SLIST_FIRST(&taphead)) != NULL) { 210113309Smdodd SLIST_REMOVE_HEAD(&taphead, tap_next); 211113328Smdodd 212113309Smdodd ifp = &tp->tap_if; 213113288Smdodd 214113309Smdodd TAPDEBUG("detaching %s%d\n", ifp->if_name,ifp->if_unit); 215113309Smdodd 216113309Smdodd KASSERT(!(tp->tap_flags & TAP_OPEN), 217113309Smdodd ("%s%d flags is out of sync", ifp->if_name, 218113309Smdodd ifp->if_unit)); 219113309Smdodd 220113309Smdodd /* XXX makedev check? nah.. not right now :) */ 221113309Smdodd 222113309Smdodd s = splimp(); 223113309Smdodd ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); 224113309Smdodd splx(s); 225113288Smdodd 226113309Smdodd free(tp, M_TAP); 227113309Smdodd } 228113309Smdodd 229113309Smdodd if (tapbasedev != NOUDEV) 230113288Smdodd destroy_dev(udev2dev(tapbasedev, 0)); 231113288Smdodd 232113288Smdodd if (!devfs_present) 233113288Smdodd cdevsw_remove(&tap_cdevsw); 234113288Smdodd 235113288Smdodd break; 236113288Smdodd 237113288Smdodd default: 238113288Smdodd return (EOPNOTSUPP); 239113288Smdodd } 240113288Smdodd 241113288Smdodd return (0); 242113288Smdodd} /* tapmodevent */ 243113288Smdodd 244113288Smdodd 245113288Smdodd/* 246113288Smdodd * DEVFS handler 247113288Smdodd * 248113309Smdodd * We need to support two kind of devices - tap and vmnet 249171101Simp */ 250113288Smdoddstatic void 251113288Smdoddtapclone(arg, name, namelen, dev) 252113288Smdodd void *arg; 253113288Smdodd char *name; 254113288Smdodd int namelen; 255113288Smdodd dev_t *dev; 256113288Smdodd{ 257113288Smdodd int unit, minor = 0 /* XXX avoid warning */ , error; 258113288Smdodd char *device_name = name; 259113288Smdodd struct resource *r = NULL; 260113288Smdodd 261113288Smdodd if (*dev != NODEV) 262113288Smdodd return; 263113288Smdodd 264113288Smdodd if (strcmp(device_name, TAP) == 0) { 265113288Smdodd /* get first free tap unit */ 266113288Smdodd r = rman_reserve_resource(tapunits, 0, TAPMAXUNIT, 1, 267113288Smdodd RF_ALLOCATED | RF_ACTIVE, NULL); 268113288Smdodd unit = rman_get_start(r); 269113288Smdodd minor = unit2minor(unit); 270113309Smdodd } 271126774Sdwmalone else if (strcmp(device_name, VMNET) == 0) { 272113288Smdodd /* get first free vmnet unit */ 273113288Smdodd r = rman_reserve_resource(vmnetunits, 0, TAPMAXUNIT, 1, 274113288Smdodd RF_ALLOCATED | RF_ACTIVE, NULL); 275113288Smdodd unit = rman_get_start(r); 276113288Smdodd minor = unit2minor(unit) | VMNET_DEV_MASK; 277113288Smdodd } 278113288Smdodd 279113288Smdodd if (r != NULL) { /* need cloning */ 280113288Smdodd TAPDEBUG("%s%d is available. minor = %#x\n", 281113288Smdodd device_name, unit, minor); 282113288Smdodd 283113288Smdodd error = rman_release_resource(r); 284113288Smdodd KASSERT((error == 0), ("Could not release tap/vmnet unit")); 285113288Smdodd 286113288Smdodd /* check if device for the unit has been created */ 287113288Smdodd *dev = makedev(CDEV_MAJOR, minor); 288113288Smdodd if ((*dev)->si_flags & SI_NAMED) { 289113288Smdodd TAPDEBUG("%s%d device exists. minor = %#x\n", 290113288Smdodd device_name, unit, minor); 291113288Smdodd return; /* device has been created */ 292113288Smdodd } 293113288Smdodd } else { /* try to match name/unit, first try tap then vmnet */ 294113288Smdodd device_name = TAP; 295113288Smdodd if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 296113309Smdodd device_name = VMNET; 297113309Smdodd 298113288Smdodd if (dev_stdclone(name, NULL, device_name, &unit) != 1) 299113288Smdodd return; 300113288Smdodd 301113288Smdodd minor = unit2minor(unit) | VMNET_DEV_MASK; 302113288Smdodd } else 303113288Smdodd minor = unit2minor(unit); 304113288Smdodd } 305113288Smdodd 306113288Smdodd TAPDEBUG("make_dev(%s%d). minor = %#x\n", device_name, unit, minor); 307113288Smdodd 308113288Smdodd *dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d", 309113288Smdodd device_name, unit); 310113288Smdodd 311113288Smdodd if (tapbasedev == NOUDEV) 312113288Smdodd tapbasedev = (*dev)->si_udev; 313113288Smdodd else { 314113288Smdodd (*dev)->si_flags |= SI_CHEAPCLONE; 315113288Smdodd dev_depends(udev2dev(tapbasedev, 0), *dev); 316113288Smdodd } 317113288Smdodd} /* tapclone */ 318113288Smdodd 319113288Smdodd 320113288Smdodd/* 321113288Smdodd * tapcreate 322113288Smdodd * 323113288Smdodd * to create interface 324113309Smdodd */ 325113288Smdoddstatic void 326113288Smdoddtapcreate(dev) 327113288Smdodd dev_t dev; 328113288Smdodd{ 329113288Smdodd struct ifnet *ifp = NULL; 330113309Smdodd struct tap_softc *tp = NULL; 331113288Smdodd unsigned short macaddr_hi; 332113288Smdodd int unit, s; 333113288Smdodd char *name = NULL; 334113288Smdodd 335113288Smdodd /* allocate driver storage and create device */ 336113309Smdodd MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 337113309Smdodd SLIST_INSERT_HEAD(&taphead, tp, tap_next); 338113309Smdodd 339113309Smdodd unit = dev2unit(dev) & TAPMAXUNIT; 340113309Smdodd 341113309Smdodd /* select device: tap or vmnet */ 342113309Smdodd if (minor(dev) & VMNET_DEV_MASK) { 343113309Smdodd name = VMNET; 344113309Smdodd tp->tap_flags |= TAP_VMNET; 345113309Smdodd } else 346113309Smdodd name = TAP; 347113309Smdodd 348113309Smdodd TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 349113309Smdodd 350113309Smdodd if (!(dev->si_flags & SI_NAMED)) 351113288Smdodd dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 352113288Smdodd 0600, "%s%d", name, unit); 353113288Smdodd 354113288Smdodd /* generate fake MAC address: 00 bd xx xx xx unit_no */ 355113288Smdodd macaddr_hi = htons(0x00bd); 356113288Smdodd bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 357113288Smdodd bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 358113288Smdodd tp->arpcom.ac_enaddr[5] = (u_char)unit; 359113288Smdodd 360113288Smdodd /* fill the rest and attach interface */ 361113288Smdodd ifp = &tp->tap_if; 362113288Smdodd ifp->if_softc = tp; 363113288Smdodd ifp->if_unit = unit; 364113288Smdodd ifp->if_name = name; 365113288Smdodd ifp->if_init = tapifinit; 366113288Smdodd ifp->if_output = ether_output; 367113288Smdodd ifp->if_start = tapifstart; 368113288Smdodd ifp->if_ioctl = tapifioctl; 369113288Smdodd ifp->if_mtu = ETHERMTU; 370113288Smdodd ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 371126774Sdwmalone ifp->if_snd.ifq_maxlen = ifqmaxlen; 372113288Smdodd 373113288Smdodd dev->si_drv1 = tp; 374113288Smdodd 375126774Sdwmalone s = splimp(); 376126774Sdwmalone ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 377113288Smdodd splx(s); 378113288Smdodd 379126774Sdwmalone tp->tap_flags |= TAP_INITED; 380113288Smdodd 381113288Smdodd TAPDEBUG("interface %s%d is created. minor = %#x\n", 382113288Smdodd ifp->if_name, ifp->if_unit, minor(dev)); 383113288Smdodd} /* tapcreate */ 384113288Smdodd 385126774Sdwmalone 386126774Sdwmalone/* 387113288Smdodd * tapopen 388113288Smdodd * 389113288Smdodd * to open tunnel. must be superuser 390113288Smdodd */ 391113288Smdoddstatic int 392113288Smdoddtapopen(dev, flag, mode, td) 393113288Smdodd dev_t dev; 394113288Smdodd int flag; 395113288Smdodd int mode; 396113288Smdodd struct thread *td; 397113288Smdodd{ 398113288Smdodd struct tap_softc *tp = NULL; 399113288Smdodd int unit, error; 400113288Smdodd struct resource *r = NULL; 401113288Smdodd 402113288Smdodd if ((error = suser(td)) != 0) 403113288Smdodd return (error); 404113288Smdodd 405113288Smdodd unit = dev2unit(dev) & TAPMAXUNIT; 406113288Smdodd 407113288Smdodd if (minor(dev) & VMNET_DEV_MASK) 408113288Smdodd r = rman_reserve_resource(vmnetunits, unit, unit, 1, 409113288Smdodd RF_ALLOCATED | RF_ACTIVE, NULL); 410113288Smdodd else 411113288Smdodd r = rman_reserve_resource(tapunits, unit, unit, 1, 412113288Smdodd RF_ALLOCATED | RF_ACTIVE, NULL); 413113288Smdodd 414113288Smdodd if (r == NULL) 415113288Smdodd return (EBUSY); 416113288Smdodd 417113288Smdodd dev->si_flags &= ~SI_CHEAPCLONE; 418113288Smdodd 419113288Smdodd tp = dev->si_drv1; 420113288Smdodd if (tp == NULL) { 421113288Smdodd tapcreate(dev); 422113328Smdodd tp = dev->si_drv1; 423113328Smdodd } 424113288Smdodd 425113288Smdodd KASSERT(!(tp->tap_flags & TAP_OPEN), 426113288Smdodd ("%s%d flags is out of sync", tp->tap_if.if_name, unit)); 427113288Smdodd 428113288Smdodd bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 429113288Smdodd 430113288Smdodd tp->tap_unit = r; 431113288Smdodd tp->tap_pid = td->td_proc->p_pid; 432113288Smdodd tp->tap_flags |= TAP_OPEN; 433113288Smdodd 434113288Smdodd TAPDEBUG("%s%d is open. minor = %#x\n", 435113288Smdodd tp->tap_if.if_name, unit, minor(dev)); 436113288Smdodd 437113288Smdodd return (0); 438113288Smdodd} /* tapopen */ 439113288Smdodd 440113288Smdodd 441113288Smdodd/* 442113288Smdodd * tapclose 443113288Smdodd * 444113288Smdodd * close the device - mark i/f down & delete routing info 445113288Smdodd */ 446113288Smdoddstatic int 447113288Smdoddtapclose(dev, foo, bar, td) 448113288Smdodd dev_t dev; 449113288Smdodd int foo; 450113288Smdodd int bar; 451113288Smdodd struct thread *td; 452113288Smdodd{ 453113288Smdodd int s, error; 454113288Smdodd struct tap_softc *tp = dev->si_drv1; 455113288Smdodd struct ifnet *ifp = &tp->tap_if; 456113288Smdodd 457113288Smdodd KASSERT((tp->tap_unit != NULL), 458113288Smdodd ("%s%d is not open", ifp->if_name, ifp->if_unit)); 459113288Smdodd 460113288Smdodd /* junk all pending output */ 461113288Smdodd IF_DRAIN(&ifp->if_snd); 462113288Smdodd 463113288Smdodd /* 464113288Smdodd * do not bring the interface down, and do not anything with 465113288Smdodd * interface, if we are in VMnet mode. just close the device. 466113288Smdodd */ 467113288Smdodd 468113288Smdodd if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 469113288Smdodd s = splimp(); 470113288Smdodd if_down(ifp); 471113288Smdodd if (ifp->if_flags & IFF_RUNNING) { 472113288Smdodd /* find internet addresses and delete routes */ 473113288Smdodd struct ifaddr *ifa = NULL; 474113288Smdodd 475113288Smdodd TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 476113288Smdodd if (ifa->ifa_addr->sa_family == AF_INET) { 477113288Smdodd rtinit(ifa, (int)RTM_DELETE, 0); 478113288Smdodd 479113288Smdodd /* remove address from interface */ 480113288Smdodd bzero(ifa->ifa_addr, 481113288Smdodd sizeof(*(ifa->ifa_addr))); 482113288Smdodd bzero(ifa->ifa_dstaddr, 483113288Smdodd sizeof(*(ifa->ifa_dstaddr))); 484113288Smdodd bzero(ifa->ifa_netmask, 485113288Smdodd sizeof(*(ifa->ifa_netmask))); 486113288Smdodd } 487113288Smdodd } 488113288Smdodd 489113288Smdodd ifp->if_flags &= ~IFF_RUNNING; 490113288Smdodd } 491113288Smdodd splx(s); 492113288Smdodd } 493113288Smdodd 494113288Smdodd funsetown(tp->tap_sigio); 495113288Smdodd selwakeup(&tp->tap_rsel); 496113288Smdodd 497113288Smdodd tp->tap_flags &= ~TAP_OPEN; 498 tp->tap_pid = 0; 499 error = rman_release_resource(tp->tap_unit); 500 KASSERT((error == 0), 501 ("%s%d could not release unit", ifp->if_name, ifp->if_unit)); 502 tp->tap_unit = NULL; 503 504 TAPDEBUG("%s%d is closed. minor = %#x\n", 505 ifp->if_name, ifp->if_unit, minor(dev)); 506 507 return (0); 508} /* tapclose */ 509 510 511/* 512 * tapifinit 513 * 514 * network interface initialization function 515 */ 516static void 517tapifinit(xtp) 518 void *xtp; 519{ 520 struct tap_softc *tp = (struct tap_softc *)xtp; 521 struct ifnet *ifp = &tp->tap_if; 522 523 TAPDEBUG("initializing %s%d\n", ifp->if_name, ifp->if_unit); 524 525 ifp->if_flags |= IFF_RUNNING; 526 ifp->if_flags &= ~IFF_OACTIVE; 527 528 /* attempt to start output */ 529 tapifstart(ifp); 530} /* tapifinit */ 531 532 533/* 534 * tapifioctl 535 * 536 * Process an ioctl request on network interface 537 */ 538int 539tapifioctl(ifp, cmd, data) 540 struct ifnet *ifp; 541 u_long cmd; 542 caddr_t data; 543{ 544 struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 545 struct ifstat *ifs = NULL; 546 int s, dummy; 547 548 switch (cmd) { 549 case SIOCSIFADDR: 550 case SIOCGIFADDR: 551 case SIOCSIFMTU: 552 s = splimp(); 553 dummy = ether_ioctl(ifp, cmd, data); 554 splx(s); 555 return (dummy); 556 557 case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 558 case SIOCADDMULTI: 559 case SIOCDELMULTI: 560 break; 561 562 case SIOCGIFSTATUS: 563 s = splimp(); 564 ifs = (struct ifstat *)data; 565 dummy = strlen(ifs->ascii); 566 if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 567 snprintf(ifs->ascii + dummy, 568 sizeof(ifs->ascii) - dummy, 569 "\tOpened by PID %d\n", tp->tap_pid); 570 splx(s); 571 break; 572 573 default: 574 return (EINVAL); 575 } 576 577 return (0); 578} /* tapifioctl */ 579 580 581/* 582 * tapifstart 583 * 584 * queue packets from higher level ready to put out 585 */ 586static void 587tapifstart(ifp) 588 struct ifnet *ifp; 589{ 590 struct tap_softc *tp = ifp->if_softc; 591 int s; 592 593 TAPDEBUG("%s%d starting\n", ifp->if_name, ifp->if_unit); 594 595 /* 596 * do not junk pending output if we are in VMnet mode. 597 * XXX: can this do any harm because of queue overflow? 598 */ 599 600 if (((tp->tap_flags & TAP_VMNET) == 0) && 601 ((tp->tap_flags & TAP_READY) != TAP_READY)) { 602 struct mbuf *m = NULL; 603 604 TAPDEBUG("%s%d not ready, tap_flags = 0x%x\n", ifp->if_name, 605 ifp->if_unit, tp->tap_flags); 606 607 s = splimp(); 608 do { 609 IF_DEQUEUE(&ifp->if_snd, m); 610 if (m != NULL) 611 m_freem(m); 612 ifp->if_oerrors ++; 613 } while (m != NULL); 614 splx(s); 615 616 return; 617 } 618 619 s = splimp(); 620 ifp->if_flags |= IFF_OACTIVE; 621 622 if (ifp->if_snd.ifq_len != 0) { 623 if (tp->tap_flags & TAP_RWAIT) { 624 tp->tap_flags &= ~TAP_RWAIT; 625 wakeup((caddr_t)tp); 626 } 627 628 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) 629 pgsigio(tp->tap_sigio, SIGIO, 0); 630 631 selwakeup(&tp->tap_rsel); 632 ifp->if_opackets ++; /* obytes are counted in ether_output */ 633 } 634 635 ifp->if_flags &= ~IFF_OACTIVE; 636 splx(s); 637} /* tapifstart */ 638 639 640/* 641 * tapioctl 642 * 643 * the cdevsw interface is now pretty minimal 644 */ 645static int 646tapioctl(dev, cmd, data, flag, td) 647 dev_t dev; 648 u_long cmd; 649 caddr_t data; 650 int flag; 651 struct thread *td; 652{ 653 struct tap_softc *tp = dev->si_drv1; 654 struct ifnet *ifp = &tp->tap_if; 655 struct tapinfo *tapp = NULL; 656 int s; 657 short f; 658 659 switch (cmd) { 660 case TAPSIFINFO: 661 s = splimp(); 662 tapp = (struct tapinfo *)data; 663 ifp->if_mtu = tapp->mtu; 664 ifp->if_type = tapp->type; 665 ifp->if_baudrate = tapp->baudrate; 666 splx(s); 667 break; 668 669 case TAPGIFINFO: 670 tapp = (struct tapinfo *)data; 671 tapp->mtu = ifp->if_mtu; 672 tapp->type = ifp->if_type; 673 tapp->baudrate = ifp->if_baudrate; 674 break; 675 676 case TAPSDEBUG: 677 tapdebug = *(int *)data; 678 break; 679 680 case TAPGDEBUG: 681 *(int *)data = tapdebug; 682 break; 683 684 case FIONBIO: 685 break; 686 687 case FIOASYNC: 688 s = splimp(); 689 if (*(int *)data) 690 tp->tap_flags |= TAP_ASYNC; 691 else 692 tp->tap_flags &= ~TAP_ASYNC; 693 splx(s); 694 break; 695 696 case FIONREAD: 697 s = splimp(); 698 if (ifp->if_snd.ifq_head) { 699 struct mbuf *mb = ifp->if_snd.ifq_head; 700 701 for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 702 *(int *)data += mb->m_len; 703 } else 704 *(int *)data = 0; 705 splx(s); 706 break; 707 708 case FIOSETOWN: 709 return (fsetown(*(int *)data, &tp->tap_sigio)); 710 711 case FIOGETOWN: 712 *(int *)data = fgetown(tp->tap_sigio); 713 return (0); 714 715 /* this is deprecated, FIOSETOWN should be used instead */ 716 case TIOCSPGRP: 717 return (fsetown(-(*(int *)data), &tp->tap_sigio)); 718 719 /* this is deprecated, FIOGETOWN should be used instead */ 720 case TIOCGPGRP: 721 *(int *)data = -fgetown(tp->tap_sigio); 722 return (0); 723 724 /* VMware/VMnet port ioctl's */ 725 726 case SIOCGIFFLAGS: /* get ifnet flags */ 727 bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 728 break; 729 730 case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 731 f = *(short *)data; 732 f &= 0x0fff; 733 f &= ~IFF_CANTCHANGE; 734 f |= IFF_UP; 735 736 s = splimp(); 737 ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 738 splx(s); 739 break; 740 741 case OSIOCGIFADDR: /* get MAC address of the remote side */ 742 case SIOCGIFADDR: 743 bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 744 break; 745 746 case SIOCSIFADDR: /* set MAC address of the remote side */ 747 bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 748 break; 749 750 default: 751 return (ENOTTY); 752 } 753 return (0); 754} /* tapioctl */ 755 756 757/* 758 * tapread 759 * 760 * the cdevsw read interface - reads a packet at a time, or at 761 * least as much of a packet as can be read 762 */ 763static int 764tapread(dev, uio, flag) 765 dev_t dev; 766 struct uio *uio; 767 int flag; 768{ 769 struct tap_softc *tp = dev->si_drv1; 770 struct ifnet *ifp = &tp->tap_if; 771 struct mbuf *m = NULL; 772 int error = 0, len, s; 773 774 TAPDEBUG("%s%d reading, minor = %#x\n", 775 ifp->if_name, ifp->if_unit, minor(dev)); 776 777 if ((tp->tap_flags & TAP_READY) != TAP_READY) { 778 TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n", 779 ifp->if_name, ifp->if_unit, minor(dev), tp->tap_flags); 780 781 return (EHOSTDOWN); 782 } 783 784 tp->tap_flags &= ~TAP_RWAIT; 785 786 /* sleep until we get a packet */ 787 do { 788 s = splimp(); 789 IF_DEQUEUE(&ifp->if_snd, m); 790 splx(s); 791 792 if (m == NULL) { 793 if (flag & IO_NDELAY) 794 return (EWOULDBLOCK); 795 796 tp->tap_flags |= TAP_RWAIT; 797 error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0); 798 if (error) 799 return (error); 800 } 801 } while (m == NULL); 802 803 /* feed packet to bpf */ 804 if (ifp->if_bpf != NULL) 805 bpf_mtap(ifp, m); 806 807 /* xfer packet to user space */ 808 while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 809 len = min(uio->uio_resid, m->m_len); 810 if (len == 0) 811 break; 812 813 error = uiomove(mtod(m, caddr_t), len, uio); 814 m = m_free(m); 815 } 816 817 if (m != NULL) { 818 TAPDEBUG("%s%d dropping mbuf, minor = %#x\n", ifp->if_name, 819 ifp->if_unit, minor(dev)); 820 m_freem(m); 821 } 822 823 return (error); 824} /* tapread */ 825 826 827/* 828 * tapwrite 829 * 830 * the cdevsw write interface - an atomic write is a packet - or else! 831 */ 832static int 833tapwrite(dev, uio, flag) 834 dev_t dev; 835 struct uio *uio; 836 int flag; 837{ 838 struct tap_softc *tp = dev->si_drv1; 839 struct ifnet *ifp = &tp->tap_if; 840 struct mbuf *top = NULL, **mp = NULL, *m = NULL; 841 struct ether_header *eh = NULL; 842 int error = 0, tlen, mlen; 843 844 TAPDEBUG("%s%d writting, minor = %#x\n", 845 ifp->if_name, ifp->if_unit, minor(dev)); 846 847 if (uio->uio_resid == 0) 848 return (0); 849 850 if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 851 TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n", 852 ifp->if_name, ifp->if_unit, uio->uio_resid, minor(dev)); 853 854 return (EIO); 855 } 856 tlen = uio->uio_resid; 857 858 /* get a header mbuf */ 859 MGETHDR(m, M_DONTWAIT, MT_DATA); 860 if (m == NULL) 861 return (ENOBUFS); 862 mlen = MHLEN; 863 864 top = 0; 865 mp = ⊤ 866 while ((error == 0) && (uio->uio_resid > 0)) { 867 m->m_len = min(mlen, uio->uio_resid); 868 error = uiomove(mtod(m, caddr_t), m->m_len, uio); 869 *mp = m; 870 mp = &m->m_next; 871 if (uio->uio_resid > 0) { 872 MGET(m, M_DONTWAIT, MT_DATA); 873 if (m == NULL) { 874 error = ENOBUFS; 875 break; 876 } 877 mlen = MLEN; 878 } 879 } 880 if (error) { 881 ifp->if_ierrors ++; 882 if (top) 883 m_freem(top); 884 return (error); 885 } 886 887 top->m_pkthdr.len = tlen; 888 top->m_pkthdr.rcvif = ifp; 889 890 /* 891 * Ethernet bridge and bpf are handled in ether_input 892 * 893 * adjust mbuf and give packet to the ether_input 894 */ 895 896 eh = mtod(top, struct ether_header *); 897 m_adj(top, sizeof(struct ether_header)); 898 ether_input(ifp, eh, top); 899 ifp->if_ipackets ++; /* ibytes are counted in ether_input */ 900 901 return (0); 902} /* tapwrite */ 903 904 905/* 906 * tappoll 907 * 908 * the poll interface, this is only useful on reads 909 * really. the write detect always returns true, write never blocks 910 * anyway, it either accepts the packet or drops it 911 */ 912static int 913tappoll(dev, events, td) 914 dev_t dev; 915 int events; 916 struct thread *td; 917{ 918 struct tap_softc *tp = dev->si_drv1; 919 struct ifnet *ifp = &tp->tap_if; 920 int s, revents = 0; 921 922 TAPDEBUG("%s%d polling, minor = %#x\n", 923 ifp->if_name, ifp->if_unit, minor(dev)); 924 925 s = splimp(); 926 if (events & (POLLIN | POLLRDNORM)) { 927 if (ifp->if_snd.ifq_len > 0) { 928 TAPDEBUG("%s%d have data in queue. len = %d, " \ 929 "minor = %#x\n", ifp->if_name, ifp->if_unit, 930 ifp->if_snd.ifq_len, minor(dev)); 931 932 revents |= (events & (POLLIN | POLLRDNORM)); 933 } else { 934 TAPDEBUG("%s%d waiting for data, minor = %#x\n", 935 ifp->if_name, ifp->if_unit, minor(dev)); 936 937 selrecord(td, &tp->tap_rsel); 938 } 939 } 940 941 if (events & (POLLOUT | POLLWRNORM)) 942 revents |= (events & (POLLOUT | POLLWRNORM)); 943 944 splx(s); 945 return (revents); 946} /* tappoll */ 947