if_tap.c revision 111741
175584Sru/* 2151497Sru * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com> 375584Sru * All rights reserved. 475584Sru * 575584Sru * Redistribution and use in source and binary forms, with or without 675584Sru * modification, are permitted provided that the following conditions 775584Sru * are met: 875584Sru * 1. Redistributions of source code must retain the above copyright 975584Sru * notice, this list of conditions and the following disclaimer. 1075584Sru * 2. Redistributions in binary form must reproduce the above copyright 1175584Sru * notice, this list of conditions and the following disclaimer in the 1275584Sru * documentation and/or other materials provided with the distribution. 1375584Sru * 1475584Sru * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1575584Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1675584Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1775584Sru * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1875584Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1975584Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20151497Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2175584Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22151497Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23151497Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2475584Sru * SUCH DAMAGE. 2575584Sru * 2675584Sru * BASED ON: 2775584Sru * ------------------------------------------------------------------------- 2875584Sru * 2975584Sru * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> 3075584Sru * Nottingham University 1987. 3175584Sru */ 3275584Sru 3375584Sru/* 3475584Sru * $FreeBSD: head/sys/net/if_tap.c 111741 2003-03-02 15:50:23Z des $ 3575584Sru * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ 3675584Sru */ 3775584Sru 3875584Sru#include "opt_inet.h" 3975584Sru 4075584Sru#include <sys/param.h> 4175584Sru#include <sys/conf.h> 4275584Sru#include <sys/filedesc.h> 4375584Sru#include <sys/filio.h> 4475584Sru#include <sys/kernel.h> 4575584Sru#include <sys/malloc.h> 4675584Sru#include <sys/mbuf.h> 4775584Sru#include <sys/poll.h> 4875584Sru#include <sys/proc.h> 4975584Sru#include <sys/signalvar.h> 5075584Sru#include <sys/socket.h> 5175584Sru#include <sys/sockio.h> 5275584Sru#include <sys/sysctl.h> 5375584Sru#include <sys/systm.h> 5475584Sru#include <sys/ttycom.h> 5575584Sru#include <sys/uio.h> 5675584Sru#include <sys/vnode.h> 5775584Sru#include <machine/bus.h> /* XXX: Shouldn't really be required! */ 5875584Sru#include <sys/rman.h> 5975584Sru#include <sys/queue.h> 6075584Sru 6175584Sru#include <net/bpf.h> 6275584Sru#include <net/ethernet.h> 6375584Sru#include <net/if.h> 6475584Sru#include <net/if_arp.h> 6575584Sru#include <net/route.h> 6675584Sru 6775584Sru#include <netinet/in.h> 68151497Sru 6975584Sru#include <net/if_tapvar.h> 7075584Sru#include <net/if_tap.h> 7175584Sru 7275584Sru 7375584Sru#define CDEV_NAME "tap" 7475584Sru#define CDEV_MAJOR 149 7575584Sru#define TAPDEBUG if (tapdebug) printf 7675584Sru 7775584Sru#define TAP "tap" 7875584Sru#define VMNET "vmnet" 7975584Sru#define TAPMAXUNIT 0x7fff 8075584Sru#define VMNET_DEV_MASK 0x00800000 8175584Sru /* 0x007f00ff */ 8275584Sru 8375584Sru/* module */ 8475584Srustatic int tapmodevent(module_t, int, void *); 8575584Sru 8675584Sru/* device */ 8775584Srustatic void tapclone(void *, char *, int, dev_t *); 8875584Srustatic void tapcreate(dev_t); 8975584Sru 90104862Sru/* network interface */ 9175584Srustatic void tapifstart(struct ifnet *); 9275584Srustatic int tapifioctl(struct ifnet *, u_long, caddr_t); 9375584Srustatic void tapifinit(void *); 9475584Sru 9575584Sru/* character device */ 9675584Srustatic d_open_t tapopen; 9775584Srustatic d_close_t tapclose; 9875584Srustatic d_read_t tapread; 99151497Srustatic d_write_t tapwrite; 10075584Srustatic d_ioctl_t tapioctl; 10175584Srustatic d_poll_t tappoll; 102151497Sru 103151497Srustatic struct cdevsw tap_cdevsw = { 10475584Sru /* open */ tapopen, 105151497Sru /* close */ tapclose, 106151497Sru /* read */ tapread, 107151497Sru /* write */ tapwrite, 108151497Sru /* ioctl */ tapioctl, 109151497Sru /* poll */ tappoll, 110151497Sru /* mmap */ nommap, 111151497Sru /* startegy */ nostrategy, 112151497Sru /* dev name */ CDEV_NAME, 113151497Sru /* dev major */ CDEV_MAJOR, 114151497Sru /* dump */ nodump, 115151497Sru /* psize */ nopsize, 116151497Sru /* flags */ 0, 117151497Sru}; 118151497Sru 119151497Srustatic int tapdebug = 0; /* debug flag */ 120151497Srustatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 121151497Srustatic udev_t tapbasedev = NOUDEV; /* base device */ 122151497Srustatic struct rman tapdevunits[2]; /* device units */ 123151497Sru#define tapunits tapdevunits 124151497Sru#define vmnetunits (tapdevunits + 1) 125151497Sru 126151497SruMALLOC_DECLARE(M_TAP); 127151497SruMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 128151497SruSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 129151497SruDEV_MODULE(if_tap, tapmodevent, NULL); 130151497Sru 131151497Sru/* 132151497Sru * tapmodevent 133151497Sru * 134151497Sru * module event handler 135151497Sru */ 136151497Srustatic int 137151497Srutapmodevent(mod, type, data) 138151497Sru module_t mod; 139151497Sru int type; 140151497Sru void *data; 141151497Sru{ 142151497Sru static eventhandler_tag eh_tag = NULL; 143151497Sru struct tap_softc *tp = NULL; 144151497Sru struct ifnet *ifp = NULL; 145151497Sru int error, s; 14675584Sru 14775584Sru switch (type) { 14875584Sru case MOD_LOAD: 14975584Sru /* initialize resources */ 15075584Sru tapunits->rm_type = RMAN_ARRAY; 15175584Sru tapunits->rm_descr = "open tap units"; 15275584Sru vmnetunits->rm_type = RMAN_ARRAY; 15375584Sru vmnetunits->rm_descr = "open vmnet units"; 15475584Sru 15575584Sru error = rman_init(tapunits); 15675584Sru if (error != 0) 15775584Sru goto bail; 15875584Sru 15975584Sru error = rman_init(vmnetunits); 16075584Sru if (error != 0) 16175584Sru goto bail1; 16275584Sru 16375584Sru error = rman_manage_region(tapunits, 0, TAPMAXUNIT); 16475584Sru if (error != 0) 16575584Sru goto bail2; 16675584Sru 16775584Sru error = rman_manage_region(vmnetunits, 0, TAPMAXUNIT); 16875584Sru if (error != 0) 16975584Sru goto bail2; 17075584Sru 17175584Sru /* intitialize device */ 17275584Sru 17375584Sru SLIST_INIT(&taphead); 17475584Sru 17575584Sru eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 17675584Sru if (eh_tag == NULL) { 17775584Sru error = ENOMEM; 17875584Sru goto bail2; 17975584Sru } 18075584Sru 18175584Sru 18275584Sru return (0); 18375584Srubail2: 18475584Sru rman_fini(vmnetunits); 18575584Srubail1: 18675584Sru rman_fini(tapunits); 187104862Srubail: 18875584Sru return (error); 18975584Sru 19075584Sru case MOD_UNLOAD: 19175584Sru SLIST_FOREACH(tp, &taphead, tap_next) 19275584Sru if (tp->tap_unit != NULL) 19375584Sru return (EBUSY); 19475584Sru 19575584Sru EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 19675584Sru 19775584Sru error = rman_fini(tapunits); 19875584Sru KASSERT((error == 0), ("Could not fini tap units")); 19975584Sru error = rman_fini(vmnetunits); 20075584Sru KASSERT((error == 0), ("Could not fini vmnet units")); 20175584Sru 20275584Sru while ((tp = SLIST_FIRST(&taphead)) != NULL) { 20375584Sru SLIST_REMOVE_HEAD(&taphead, tap_next); 20475584Sru 20575584Sru ifp = &tp->tap_if; 20675584Sru 20775584Sru TAPDEBUG("detaching %s%d\n", ifp->if_name,ifp->if_unit); 20875584Sru 20975584Sru KASSERT(!(tp->tap_flags & TAP_OPEN), 21075584Sru ("%s%d flags is out of sync", ifp->if_name, 21175584Sru ifp->if_unit)); 21275584Sru 21375584Sru /* XXX makedev check? nah.. not right now :) */ 21475584Sru 21575584Sru s = splimp(); 21675584Sru ether_ifdetach(ifp); 21775584Sru splx(s); 21875584Sru 21975584Sru free(tp, M_TAP); 22075584Sru } 22175584Sru 22275584Sru if (tapbasedev != NOUDEV) 22375584Sru destroy_dev(udev2dev(tapbasedev, 0)); 22475584Sru 22575584Sru 22675584Sru break; 22775584Sru 228104862Sru default: 229104862Sru return (EOPNOTSUPP); 230104862Sru } 231104862Sru 23275584Sru return (0); 23375584Sru} /* tapmodevent */ 234104862Sru 23575584Sru 236151497Sru/* 23775584Sru * DEVFS handler 238151497Sru * 23975584Sru * We need to support two kind of devices - tap and vmnet 24075584Sru */ 24175584Srustatic void 24275584Srutapclone(arg, name, namelen, dev) 24375584Sru void *arg; 24475584Sru char *name; 24575584Sru int namelen; 24675584Sru dev_t *dev; 24775584Sru{ 24875584Sru int unit, minor = 0 /* XXX avoid warning */ , error; 24975584Sru char *device_name = name; 25075584Sru struct resource *r = NULL; 25175584Sru 252151497Sru if (*dev != NODEV) 253151497Sru return; 254151497Sru 255151497Sru if (strcmp(device_name, TAP) == 0) { 256151497Sru /* get first free tap unit */ 25775584Sru r = rman_reserve_resource(tapunits, 0, TAPMAXUNIT, 1, 25875584Sru RF_ALLOCATED | RF_ACTIVE, NULL); 25975584Sru unit = rman_get_start(r); 26075584Sru minor = unit2minor(unit); 26175584Sru } 26275584Sru else if (strcmp(device_name, VMNET) == 0) { 26375584Sru /* get first free vmnet unit */ 26475584Sru r = rman_reserve_resource(vmnetunits, 0, TAPMAXUNIT, 1, 265151497Sru RF_ALLOCATED | RF_ACTIVE, NULL); 26675584Sru unit = rman_get_start(r); 26775584Sru minor = unit2minor(unit) | VMNET_DEV_MASK; 26875584Sru } 26975584Sru 27075584Sru if (r != NULL) { /* need cloning */ 271151497Sru TAPDEBUG("%s%d is available. minor = %#x\n", 272151497Sru device_name, unit, minor); 273151497Sru 27475584Sru error = rman_release_resource(r); 27575584Sru KASSERT((error == 0), ("Could not release tap/vmnet unit")); 27675584Sru 27775584Sru /* check if device for the unit has been created */ 27875584Sru *dev = makedev(CDEV_MAJOR, minor); 27975584Sru if ((*dev)->si_flags & SI_NAMED) { 28075584Sru TAPDEBUG("%s%d device exists. minor = %#x\n", 28175584Sru device_name, unit, minor); 282151497Sru return; /* device has been created */ 28375584Sru } 284151497Sru } else { /* try to match name/unit, first try tap then vmnet */ 285151497Sru device_name = TAP; 286151497Sru if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 287151497Sru device_name = VMNET; 28875584Sru 289151497Sru if (dev_stdclone(name, NULL, device_name, &unit) != 1) 290151497Sru return; 291151497Sru 29275584Sru minor = unit2minor(unit) | VMNET_DEV_MASK; 293151497Sru } else 29475584Sru minor = unit2minor(unit); 29575584Sru } 29675584Sru 297151497Sru TAPDEBUG("make_dev(%s%d). minor = %#x\n", device_name, unit, minor); 298151497Sru 29975584Sru *dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d", 30075584Sru device_name, unit); 30175584Sru 30275584Sru if (tapbasedev == NOUDEV) 30375584Sru tapbasedev = (*dev)->si_udev; 30475584Sru else { 30575584Sru (*dev)->si_flags |= SI_CHEAPCLONE; 30675584Sru dev_depends(udev2dev(tapbasedev, 0), *dev); 30775584Sru } 30875584Sru} /* tapclone */ 30975584Sru 31075584Sru 31175584Sru/* 31275584Sru * tapcreate 31375584Sru * 31475584Sru * to create interface 31575584Sru */ 316104862Srustatic void 317104862Srutapcreate(dev) 318104862Sru dev_t dev; 319104862Sru{ 320104862Sru struct ifnet *ifp = NULL; 321104862Sru struct tap_softc *tp = NULL; 32275584Sru unsigned short macaddr_hi; 32375584Sru int unit, s; 32475584Sru char *name = NULL; 32575584Sru 32675584Sru /* allocate driver storage and create device */ 32775584Sru MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 32875584Sru SLIST_INSERT_HEAD(&taphead, tp, tap_next); 32975584Sru 33075584Sru unit = dev2unit(dev) & TAPMAXUNIT; 33175584Sru 33275584Sru /* select device: tap or vmnet */ 33375584Sru if (minor(dev) & VMNET_DEV_MASK) { 33475584Sru name = VMNET; 33575584Sru tp->tap_flags |= TAP_VMNET; 33679543Sru } else 33775584Sru name = TAP; 338151497Sru 33975584Sru TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 340151497Sru 34175584Sru if (!(dev->si_flags & SI_NAMED)) 34275584Sru dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 34375584Sru 0600, "%s%d", name, unit); 34475584Sru 34575584Sru /* generate fake MAC address: 00 bd xx xx xx unit_no */ 34675584Sru macaddr_hi = htons(0x00bd); 34775584Sru bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 348151497Sru bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 349151497Sru tp->arpcom.ac_enaddr[5] = (u_char)unit; 35075584Sru 351104862Sru /* fill the rest and attach interface */ 352151497Sru ifp = &tp->tap_if; 35375584Sru ifp->if_softc = tp; 35475584Sru ifp->if_unit = unit; 35575584Sru ifp->if_name = name; 35675584Sru ifp->if_init = tapifinit; 357151497Sru ifp->if_start = tapifstart; 358151497Sru ifp->if_ioctl = tapifioctl; 359151497Sru ifp->if_mtu = ETHERMTU; 36075584Sru ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 36175584Sru ifp->if_snd.ifq_maxlen = ifqmaxlen; 36275584Sru 36375584Sru dev->si_drv1 = tp; 36475584Sru 36575584Sru s = splimp(); 36675584Sru ether_ifattach(ifp, tp->arpcom.ac_enaddr); 36775584Sru splx(s); 36875584Sru 36975584Sru tp->tap_flags |= TAP_INITED; 37075584Sru 37175584Sru TAPDEBUG("interface %s%d is created. minor = %#x\n", 37275584Sru ifp->if_name, ifp->if_unit, minor(dev)); 37375584Sru} /* tapcreate */ 37475584Sru 37575584Sru 376104862Sru/* 37775584Sru * tapopen 37875584Sru * 37975584Sru * to open tunnel. must be superuser 38075584Sru */ 38175584Srustatic int 38275584Srutapopen(dev, flag, mode, td) 38375584Sru dev_t dev; 38475584Sru int flag; 38575584Sru int mode; 38675584Sru struct thread *td; 38775584Sru{ 38875584Sru struct tap_softc *tp = NULL; 38975584Sru int unit, error; 39075584Sru struct resource *r = NULL; 39175584Sru 39275584Sru if ((error = suser(td)) != 0) 39375584Sru return (error); 39475584Sru 39575584Sru unit = dev2unit(dev) & TAPMAXUNIT; 39675584Sru 39775584Sru if (minor(dev) & VMNET_DEV_MASK) 39875584Sru r = rman_reserve_resource(vmnetunits, unit, unit, 1, 39975584Sru RF_ALLOCATED | RF_ACTIVE, NULL); 40075584Sru else 40175584Sru r = rman_reserve_resource(tapunits, unit, unit, 1, 40275584Sru RF_ALLOCATED | RF_ACTIVE, NULL); 40375584Sru 40475584Sru if (r == NULL) 40575584Sru return (EBUSY); 40675584Sru 40775584Sru dev->si_flags &= ~SI_CHEAPCLONE; 40875584Sru 409104862Sru tp = dev->si_drv1; 410104862Sru if (tp == NULL) { 41175584Sru tapcreate(dev); 41275584Sru tp = dev->si_drv1; 41375584Sru } 414104862Sru 415104862Sru KASSERT(!(tp->tap_flags & TAP_OPEN), 416 ("%s%d flags is out of sync", tp->tap_if.if_name, unit)); 417 418 bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 419 420 tp->tap_unit = r; 421 tp->tap_pid = td->td_proc->p_pid; 422 tp->tap_flags |= TAP_OPEN; 423 424 TAPDEBUG("%s%d is open. minor = %#x\n", 425 tp->tap_if.if_name, unit, minor(dev)); 426 427 return (0); 428} /* tapopen */ 429 430 431/* 432 * tapclose 433 * 434 * close the device - mark i/f down & delete routing info 435 */ 436static int 437tapclose(dev, foo, bar, td) 438 dev_t dev; 439 int foo; 440 int bar; 441 struct thread *td; 442{ 443 int s, error; 444 struct tap_softc *tp = dev->si_drv1; 445 struct ifnet *ifp = &tp->tap_if; 446 447 KASSERT((tp->tap_unit != NULL), 448 ("%s%d is not open", ifp->if_name, ifp->if_unit)); 449 450 /* junk all pending output */ 451 IF_DRAIN(&ifp->if_snd); 452 453 /* 454 * do not bring the interface down, and do not anything with 455 * interface, if we are in VMnet mode. just close the device. 456 */ 457 458 if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 459 s = splimp(); 460 if_down(ifp); 461 if (ifp->if_flags & IFF_RUNNING) { 462 /* find internet addresses and delete routes */ 463 struct ifaddr *ifa = NULL; 464 465 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 466 if (ifa->ifa_addr->sa_family == AF_INET) { 467 rtinit(ifa, (int)RTM_DELETE, 0); 468 469 /* remove address from interface */ 470 bzero(ifa->ifa_addr, 471 sizeof(*(ifa->ifa_addr))); 472 bzero(ifa->ifa_dstaddr, 473 sizeof(*(ifa->ifa_dstaddr))); 474 bzero(ifa->ifa_netmask, 475 sizeof(*(ifa->ifa_netmask))); 476 } 477 } 478 479 ifp->if_flags &= ~IFF_RUNNING; 480 } 481 splx(s); 482 } 483 484 funsetown(&tp->tap_sigio); 485 selwakeup(&tp->tap_rsel); 486 487 tp->tap_flags &= ~TAP_OPEN; 488 tp->tap_pid = 0; 489 error = rman_release_resource(tp->tap_unit); 490 KASSERT((error == 0), 491 ("%s%d could not release unit", ifp->if_name, ifp->if_unit)); 492 tp->tap_unit = NULL; 493 494 TAPDEBUG("%s%d is closed. minor = %#x\n", 495 ifp->if_name, ifp->if_unit, minor(dev)); 496 497 return (0); 498} /* tapclose */ 499 500 501/* 502 * tapifinit 503 * 504 * network interface initialization function 505 */ 506static void 507tapifinit(xtp) 508 void *xtp; 509{ 510 struct tap_softc *tp = (struct tap_softc *)xtp; 511 struct ifnet *ifp = &tp->tap_if; 512 513 TAPDEBUG("initializing %s%d\n", ifp->if_name, ifp->if_unit); 514 515 ifp->if_flags |= IFF_RUNNING; 516 ifp->if_flags &= ~IFF_OACTIVE; 517 518 /* attempt to start output */ 519 tapifstart(ifp); 520} /* tapifinit */ 521 522 523/* 524 * tapifioctl 525 * 526 * Process an ioctl request on network interface 527 */ 528static int 529tapifioctl(ifp, cmd, data) 530 struct ifnet *ifp; 531 u_long cmd; 532 caddr_t data; 533{ 534 struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 535 struct ifstat *ifs = NULL; 536 int s, dummy; 537 538 switch (cmd) { 539 case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 540 case SIOCADDMULTI: 541 case SIOCDELMULTI: 542 break; 543 544 case SIOCGIFSTATUS: 545 s = splimp(); 546 ifs = (struct ifstat *)data; 547 dummy = strlen(ifs->ascii); 548 if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 549 snprintf(ifs->ascii + dummy, 550 sizeof(ifs->ascii) - dummy, 551 "\tOpened by PID %d\n", tp->tap_pid); 552 splx(s); 553 break; 554 555 default: 556 s = splimp(); 557 dummy = ether_ioctl(ifp, cmd, data); 558 splx(s); 559 return (dummy); 560 } 561 562 return (0); 563} /* tapifioctl */ 564 565 566/* 567 * tapifstart 568 * 569 * queue packets from higher level ready to put out 570 */ 571static void 572tapifstart(ifp) 573 struct ifnet *ifp; 574{ 575 struct tap_softc *tp = ifp->if_softc; 576 int s; 577 578 TAPDEBUG("%s%d starting\n", ifp->if_name, ifp->if_unit); 579 580 /* 581 * do not junk pending output if we are in VMnet mode. 582 * XXX: can this do any harm because of queue overflow? 583 */ 584 585 if (((tp->tap_flags & TAP_VMNET) == 0) && 586 ((tp->tap_flags & TAP_READY) != TAP_READY)) { 587 struct mbuf *m = NULL; 588 589 TAPDEBUG("%s%d not ready, tap_flags = 0x%x\n", ifp->if_name, 590 ifp->if_unit, tp->tap_flags); 591 592 s = splimp(); 593 do { 594 IF_DEQUEUE(&ifp->if_snd, m); 595 if (m != NULL) 596 m_freem(m); 597 ifp->if_oerrors ++; 598 } while (m != NULL); 599 splx(s); 600 601 return; 602 } 603 604 s = splimp(); 605 ifp->if_flags |= IFF_OACTIVE; 606 607 if (ifp->if_snd.ifq_len != 0) { 608 if (tp->tap_flags & TAP_RWAIT) { 609 tp->tap_flags &= ~TAP_RWAIT; 610 wakeup((caddr_t)tp); 611 } 612 613 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) 614 pgsigio(&tp->tap_sigio, SIGIO, 0); 615 616 selwakeup(&tp->tap_rsel); 617 ifp->if_opackets ++; /* obytes are counted in ether_output */ 618 } 619 620 ifp->if_flags &= ~IFF_OACTIVE; 621 splx(s); 622} /* tapifstart */ 623 624 625/* 626 * tapioctl 627 * 628 * the cdevsw interface is now pretty minimal 629 */ 630static int 631tapioctl(dev, cmd, data, flag, td) 632 dev_t dev; 633 u_long cmd; 634 caddr_t data; 635 int flag; 636 struct thread *td; 637{ 638 struct tap_softc *tp = dev->si_drv1; 639 struct ifnet *ifp = &tp->tap_if; 640 struct tapinfo *tapp = NULL; 641 int s; 642 int f; 643 644 switch (cmd) { 645 case TAPSIFINFO: 646 s = splimp(); 647 tapp = (struct tapinfo *)data; 648 ifp->if_mtu = tapp->mtu; 649 ifp->if_type = tapp->type; 650 ifp->if_baudrate = tapp->baudrate; 651 splx(s); 652 break; 653 654 case TAPGIFINFO: 655 tapp = (struct tapinfo *)data; 656 tapp->mtu = ifp->if_mtu; 657 tapp->type = ifp->if_type; 658 tapp->baudrate = ifp->if_baudrate; 659 break; 660 661 case TAPSDEBUG: 662 tapdebug = *(int *)data; 663 break; 664 665 case TAPGDEBUG: 666 *(int *)data = tapdebug; 667 break; 668 669 case FIONBIO: 670 break; 671 672 case FIOASYNC: 673 s = splimp(); 674 if (*(int *)data) 675 tp->tap_flags |= TAP_ASYNC; 676 else 677 tp->tap_flags &= ~TAP_ASYNC; 678 splx(s); 679 break; 680 681 case FIONREAD: 682 s = splimp(); 683 if (ifp->if_snd.ifq_head) { 684 struct mbuf *mb = ifp->if_snd.ifq_head; 685 686 for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 687 *(int *)data += mb->m_len; 688 } else 689 *(int *)data = 0; 690 splx(s); 691 break; 692 693 case FIOSETOWN: 694 return (fsetown(*(int *)data, &tp->tap_sigio)); 695 696 case FIOGETOWN: 697 *(int *)data = fgetown(&tp->tap_sigio); 698 return (0); 699 700 /* this is deprecated, FIOSETOWN should be used instead */ 701 case TIOCSPGRP: 702 return (fsetown(-(*(int *)data), &tp->tap_sigio)); 703 704 /* this is deprecated, FIOGETOWN should be used instead */ 705 case TIOCGPGRP: 706 *(int *)data = -fgetown(&tp->tap_sigio); 707 return (0); 708 709 /* VMware/VMnet port ioctl's */ 710 711 case SIOCGIFFLAGS: /* get ifnet flags */ 712 bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 713 break; 714 715 case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 716 f = *(int *)data; 717 f &= 0x0fff; 718 f &= ~IFF_CANTCHANGE; 719 f |= IFF_UP; 720 721 s = splimp(); 722 ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 723 splx(s); 724 break; 725 726 case OSIOCGIFADDR: /* get MAC address of the remote side */ 727 case SIOCGIFADDR: 728 bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 729 break; 730 731 case SIOCSIFADDR: /* set MAC address of the remote side */ 732 bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 733 break; 734 735 default: 736 return (ENOTTY); 737 } 738 return (0); 739} /* tapioctl */ 740 741 742/* 743 * tapread 744 * 745 * the cdevsw read interface - reads a packet at a time, or at 746 * least as much of a packet as can be read 747 */ 748static int 749tapread(dev, uio, flag) 750 dev_t dev; 751 struct uio *uio; 752 int flag; 753{ 754 struct tap_softc *tp = dev->si_drv1; 755 struct ifnet *ifp = &tp->tap_if; 756 struct mbuf *m = NULL; 757 int error = 0, len, s; 758 759 TAPDEBUG("%s%d reading, minor = %#x\n", 760 ifp->if_name, ifp->if_unit, minor(dev)); 761 762 if ((tp->tap_flags & TAP_READY) != TAP_READY) { 763 TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n", 764 ifp->if_name, ifp->if_unit, minor(dev), tp->tap_flags); 765 766 return (EHOSTDOWN); 767 } 768 769 tp->tap_flags &= ~TAP_RWAIT; 770 771 /* sleep until we get a packet */ 772 do { 773 s = splimp(); 774 IF_DEQUEUE(&ifp->if_snd, m); 775 splx(s); 776 777 if (m == NULL) { 778 if (flag & IO_NDELAY) 779 return (EWOULDBLOCK); 780 781 tp->tap_flags |= TAP_RWAIT; 782 error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0); 783 if (error) 784 return (error); 785 } 786 } while (m == NULL); 787 788 /* feed packet to bpf */ 789 BPF_MTAP(ifp, m); 790 791 /* xfer packet to user space */ 792 while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 793 len = min(uio->uio_resid, m->m_len); 794 if (len == 0) 795 break; 796 797 error = uiomove(mtod(m, void *), len, uio); 798 m = m_free(m); 799 } 800 801 if (m != NULL) { 802 TAPDEBUG("%s%d dropping mbuf, minor = %#x\n", ifp->if_name, 803 ifp->if_unit, minor(dev)); 804 m_freem(m); 805 } 806 807 return (error); 808} /* tapread */ 809 810 811/* 812 * tapwrite 813 * 814 * the cdevsw write interface - an atomic write is a packet - or else! 815 */ 816static int 817tapwrite(dev, uio, flag) 818 dev_t dev; 819 struct uio *uio; 820 int flag; 821{ 822 struct tap_softc *tp = dev->si_drv1; 823 struct ifnet *ifp = &tp->tap_if; 824 struct mbuf *top = NULL, **mp = NULL, *m = NULL; 825 int error = 0, tlen, mlen; 826 827 TAPDEBUG("%s%d writting, minor = %#x\n", 828 ifp->if_name, ifp->if_unit, minor(dev)); 829 830 if (uio->uio_resid == 0) 831 return (0); 832 833 if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 834 TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n", 835 ifp->if_name, ifp->if_unit, uio->uio_resid, minor(dev)); 836 837 return (EIO); 838 } 839 tlen = uio->uio_resid; 840 841 /* get a header mbuf */ 842 MGETHDR(m, M_DONTWAIT, MT_DATA); 843 if (m == NULL) 844 return (ENOBUFS); 845 mlen = MHLEN; 846 847 top = 0; 848 mp = ⊤ 849 while ((error == 0) && (uio->uio_resid > 0)) { 850 m->m_len = min(mlen, uio->uio_resid); 851 error = uiomove(mtod(m, void *), m->m_len, uio); 852 *mp = m; 853 mp = &m->m_next; 854 if (uio->uio_resid > 0) { 855 MGET(m, M_DONTWAIT, MT_DATA); 856 if (m == NULL) { 857 error = ENOBUFS; 858 break; 859 } 860 mlen = MLEN; 861 } 862 } 863 if (error) { 864 ifp->if_ierrors ++; 865 if (top) 866 m_freem(top); 867 return (error); 868 } 869 870 top->m_pkthdr.len = tlen; 871 top->m_pkthdr.rcvif = ifp; 872 873 /* Pass packet up to parent. */ 874 (*ifp->if_input)(ifp, top); 875 ifp->if_ipackets ++; /* ibytes are counted in parent */ 876 877 return (0); 878} /* tapwrite */ 879 880 881/* 882 * tappoll 883 * 884 * the poll interface, this is only useful on reads 885 * really. the write detect always returns true, write never blocks 886 * anyway, it either accepts the packet or drops it 887 */ 888static int 889tappoll(dev, events, td) 890 dev_t dev; 891 int events; 892 struct thread *td; 893{ 894 struct tap_softc *tp = dev->si_drv1; 895 struct ifnet *ifp = &tp->tap_if; 896 int s, revents = 0; 897 898 TAPDEBUG("%s%d polling, minor = %#x\n", 899 ifp->if_name, ifp->if_unit, minor(dev)); 900 901 s = splimp(); 902 if (events & (POLLIN | POLLRDNORM)) { 903 if (ifp->if_snd.ifq_len > 0) { 904 TAPDEBUG("%s%d have data in queue. len = %d, " \ 905 "minor = %#x\n", ifp->if_name, ifp->if_unit, 906 ifp->if_snd.ifq_len, minor(dev)); 907 908 revents |= (events & (POLLIN | POLLRDNORM)); 909 } else { 910 TAPDEBUG("%s%d waiting for data, minor = %#x\n", 911 ifp->if_name, ifp->if_unit, minor(dev)); 912 913 selrecord(td, &tp->tap_rsel); 914 } 915 } 916 917 if (events & (POLLOUT | POLLWRNORM)) 918 revents |= (events & (POLLOUT | POLLWRNORM)); 919 920 splx(s); 921 return (revents); 922} /* tappoll */ 923