if_tap.c revision 121816
1184610Salfred/* 2184610Salfred * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com> 3184610Salfred * All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 1. Redistributions of source code must retain the above copyright 9184610Salfred * notice, this list of conditions and the following disclaimer. 10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer in the 12184610Salfred * documentation and/or other materials provided with the distribution. 13184610Salfred * 14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24184610Salfred * SUCH DAMAGE. 25184610Salfred * 26184610Salfred * BASED ON: 27184610Salfred * ------------------------------------------------------------------------- 28184610Salfred * 29194230Sthompsa * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> 30194230Sthompsa * Nottingham University 1987. 31184610Salfred */ 32246122Shselasky 33188942Sthompsa/* 34246122Shselasky * $FreeBSD: head/sys/net/if_tap.c 121816 2003-10-31 18:32:15Z brooks $ 35187994Salfred * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ 36184610Salfred */ 37184610Salfred 38184610Salfred#include "opt_inet.h" 39184610Salfred 40184610Salfred#include <sys/param.h> 41184610Salfred#include <sys/conf.h> 42184610Salfred#include <sys/filedesc.h> 43184610Salfred#include <sys/filio.h> 44184610Salfred#include <sys/kernel.h> 45184610Salfred#include <sys/malloc.h> 46184610Salfred#include <sys/mbuf.h> 47184610Salfred#include <sys/poll.h> 48192984Sthompsa#include <sys/proc.h> 49184610Salfred#include <sys/signalvar.h> 50184610Salfred#include <sys/socket.h> 51184610Salfred#include <sys/sockio.h> 52184610Salfred#include <sys/sysctl.h> 53184610Salfred#include <sys/systm.h> 54184610Salfred#include <sys/ttycom.h> 55184610Salfred#include <sys/uio.h> 56184610Salfred#include <sys/vnode.h> 57184610Salfred#include <machine/bus.h> /* XXX: Shouldn't really be required! */ 58184610Salfred#include <sys/rman.h> 59184610Salfred#include <sys/queue.h> 60184610Salfred 61184610Salfred#include <net/bpf.h> 62184610Salfred#include <net/ethernet.h> 63184610Salfred#include <net/if.h> 64184610Salfred#include <net/if_arp.h> 65184610Salfred#include <net/route.h> 66184610Salfred 67184610Salfred#include <netinet/in.h> 68184610Salfred 69184610Salfred#include <net/if_tapvar.h> 70184610Salfred#include <net/if_tap.h> 71184610Salfred 72184610Salfred 73184610Salfred#define CDEV_NAME "tap" 74184610Salfred#define CDEV_MAJOR 149 75184610Salfred#define TAPDEBUG if (tapdebug) printf 76184610Salfred 77184610Salfred#define TAP "tap" 78184610Salfred#define VMNET "vmnet" 79184610Salfred#define TAPMAXUNIT 0x7fff 80184610Salfred#define VMNET_DEV_MASK 0x00800000 81184610Salfred /* 0x007f00ff */ 82184610Salfred 83184610Salfred/* module */ 84184610Salfredstatic int tapmodevent(module_t, int, void *); 85184610Salfred 86184610Salfred/* device */ 87184610Salfredstatic void tapclone(void *, char *, int, dev_t *); 88184610Salfredstatic void tapcreate(dev_t); 89184610Salfred 90184610Salfred/* network interface */ 91184610Salfredstatic void tapifstart(struct ifnet *); 92184610Salfredstatic int tapifioctl(struct ifnet *, u_long, caddr_t); 93184610Salfredstatic void tapifinit(void *); 94184610Salfred 95184610Salfred/* character device */ 96184610Salfredstatic d_open_t tapopen; 97184610Salfredstatic d_close_t tapclose; 98184610Salfredstatic d_read_t tapread; 99184610Salfredstatic d_write_t tapwrite; 100184610Salfredstatic d_ioctl_t tapioctl; 101184610Salfredstatic d_poll_t tappoll; 102184610Salfred 103184610Salfredstatic struct cdevsw tap_cdevsw = { 104184610Salfred .d_open = tapopen, 105184610Salfred .d_close = tapclose, 106184610Salfred .d_read = tapread, 107184610Salfred .d_write = tapwrite, 108184610Salfred .d_ioctl = tapioctl, 109184610Salfred .d_poll = tappoll, 110184610Salfred .d_name = CDEV_NAME, 111184610Salfred .d_maj = CDEV_MAJOR, 112184610Salfred}; 113184610Salfred 114184610Salfredstatic int tapdebug = 0; /* debug flag */ 115184610Salfredstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 116184610Salfredstatic udev_t tapbasedev = NOUDEV; /* base device */ 117184610Salfredstatic struct rman tapdevunits[2]; /* device units */ 118184610Salfred#define tapunits tapdevunits 119184610Salfred#define vmnetunits (tapdevunits + 1) 120184610Salfred 121184610SalfredMALLOC_DECLARE(M_TAP); 122184610SalfredMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 123184610SalfredSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 124184610SalfredDEV_MODULE(if_tap, tapmodevent, NULL); 125184610Salfred 126184610Salfred/* 127184610Salfred * tapmodevent 128184610Salfred * 129184610Salfred * module event handler 130184610Salfred */ 131184610Salfredstatic int 132184610Salfredtapmodevent(mod, type, data) 133192925Sthompsa module_t mod; 134184610Salfred int type; 135184610Salfred void *data; 136184610Salfred{ 137184610Salfred static eventhandler_tag eh_tag = NULL; 138184610Salfred struct tap_softc *tp = NULL; 139184610Salfred struct ifnet *ifp = NULL; 140184610Salfred int error, s; 141184610Salfred 142184610Salfred switch (type) { 143184610Salfred case MOD_LOAD: 144184610Salfred /* initialize resources */ 145184610Salfred tapunits->rm_type = RMAN_ARRAY; 146184610Salfred tapunits->rm_descr = "open tap units"; 147184610Salfred vmnetunits->rm_type = RMAN_ARRAY; 148184610Salfred vmnetunits->rm_descr = "open vmnet units"; 149184610Salfred 150184610Salfred error = rman_init(tapunits); 151184610Salfred if (error != 0) 152184610Salfred goto bail; 153184610Salfred 154184610Salfred error = rman_init(vmnetunits); 155184610Salfred if (error != 0) 156184610Salfred goto bail1; 157184610Salfred 158184610Salfred error = rman_manage_region(tapunits, 0, TAPMAXUNIT); 159184610Salfred if (error != 0) 160184610Salfred goto bail2; 161208009Sthompsa 162208009Sthompsa error = rman_manage_region(vmnetunits, 0, TAPMAXUNIT); 163208009Sthompsa if (error != 0) 164184610Salfred goto bail2; 165184610Salfred 166184610Salfred /* intitialize device */ 167184610Salfred 168184610Salfred SLIST_INIT(&taphead); 169184610Salfred 170184610Salfred eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 171184610Salfred if (eh_tag == NULL) { 172184610Salfred error = ENOMEM; 173184610Salfred goto bail2; 174184610Salfred } 175184610Salfred 176184610Salfred 177184610Salfred return (0); 178184610Salfredbail2: 179184610Salfred rman_fini(vmnetunits); 180184610Salfredbail1: 181194677Sthompsa rman_fini(tapunits); 182194677Sthompsabail: 183194677Sthompsa return (error); 184194677Sthompsa 185194677Sthompsa case MOD_UNLOAD: 186194677Sthompsa SLIST_FOREACH(tp, &taphead, tap_next) 187194677Sthompsa if (tp->tap_unit != NULL) 188194677Sthompsa return (EBUSY); 189194677Sthompsa 190194677Sthompsa EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 191194677Sthompsa 192194677Sthompsa error = rman_fini(tapunits); 193194677Sthompsa KASSERT((error == 0), ("Could not fini tap units")); 194194677Sthompsa error = rman_fini(vmnetunits); 195194677Sthompsa KASSERT((error == 0), ("Could not fini vmnet units")); 196194677Sthompsa 197194677Sthompsa while ((tp = SLIST_FIRST(&taphead)) != NULL) { 198194677Sthompsa SLIST_REMOVE_HEAD(&taphead, tap_next); 199194677Sthompsa 200194677Sthompsa ifp = &tp->tap_if; 201194677Sthompsa 202194677Sthompsa TAPDEBUG("detaching %s\n", ifp->if_xname); 203194677Sthompsa 204194677Sthompsa KASSERT(!(tp->tap_flags & TAP_OPEN), 205194677Sthompsa ("%s flags is out of sync", ifp->if_xname)); 206194677Sthompsa 207194677Sthompsa /* XXX makedev check? nah.. not right now :) */ 208194677Sthompsa 209194677Sthompsa s = splimp(); 210194677Sthompsa ether_ifdetach(ifp); 211194677Sthompsa splx(s); 212194677Sthompsa 213194677Sthompsa free(tp, M_TAP); 214194677Sthompsa } 215194677Sthompsa 216194677Sthompsa if (tapbasedev != NOUDEV) 217194677Sthompsa destroy_dev(udev2dev(tapbasedev, 0)); 218194677Sthompsa 219194677Sthompsa 220194677Sthompsa break; 221194677Sthompsa 222194677Sthompsa default: 223194677Sthompsa return (EOPNOTSUPP); 224194677Sthompsa } 225194677Sthompsa 226194677Sthompsa return (0); 227194677Sthompsa} /* tapmodevent */ 228194677Sthompsa 229194677Sthompsa 230194677Sthompsa/* 231233774Shselasky * DEVFS handler 232194677Sthompsa * 233194677Sthompsa * We need to support two kind of devices - tap and vmnet 234208012Sthompsa */ 235194677Sthompsastatic void 236208012Sthompsatapclone(arg, name, namelen, dev) 237208012Sthompsa void *arg; 238223755Shselasky char *name; 239223755Shselasky int namelen; 240233774Shselasky dev_t *dev; 241194677Sthompsa{ 242194677Sthompsa int unit, minor = 0 /* XXX avoid warning */ , error; 243194677Sthompsa char *device_name = name; 244194677Sthompsa struct resource *r = NULL; 245194677Sthompsa 246194677Sthompsa if (*dev != NODEV) 247245248Shselasky return; 248245248Shselasky 249194677Sthompsa if (strcmp(device_name, TAP) == 0) { 250194230Sthompsa /* get first free tap unit */ 251 r = rman_reserve_resource(tapunits, 0, TAPMAXUNIT, 1, 252 RF_ALLOCATED | RF_ACTIVE, NULL); 253 unit = rman_get_start(r); 254 minor = unit2minor(unit); 255 } 256 else if (strcmp(device_name, VMNET) == 0) { 257 /* get first free vmnet unit */ 258 r = rman_reserve_resource(vmnetunits, 0, TAPMAXUNIT, 1, 259 RF_ALLOCATED | RF_ACTIVE, NULL); 260 unit = rman_get_start(r); 261 minor = unit2minor(unit) | VMNET_DEV_MASK; 262 } 263 264 if (r != NULL) { /* need cloning */ 265 TAPDEBUG("%s%d is available. minor = %#x\n", 266 device_name, unit, minor); 267 268 error = rman_release_resource(r); 269 KASSERT((error == 0), ("Could not release tap/vmnet unit")); 270 271 /* check if device for the unit has been created */ 272 *dev = makedev(CDEV_MAJOR, minor); 273 if ((*dev)->si_flags & SI_NAMED) { 274 TAPDEBUG("%s%d device exists. minor = %#x\n", 275 device_name, unit, minor); 276 return; /* device has been created */ 277 } 278 } else { /* try to match name/unit, first try tap then vmnet */ 279 device_name = TAP; 280 if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 281 device_name = VMNET; 282 283 if (dev_stdclone(name, NULL, device_name, &unit) != 1) 284 return; 285 286 minor = unit2minor(unit) | VMNET_DEV_MASK; 287 } else 288 minor = unit2minor(unit); 289 } 290 291 TAPDEBUG("make_dev(%s%d). minor = %#x\n", device_name, unit, minor); 292 293 *dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d", 294 device_name, unit); 295 296 if (tapbasedev == NOUDEV) 297 tapbasedev = (*dev)->si_udev; 298 else { 299 (*dev)->si_flags |= SI_CHEAPCLONE; 300 dev_depends(udev2dev(tapbasedev, 0), *dev); 301 } 302} /* tapclone */ 303 304 305/* 306 * tapcreate 307 * 308 * to create interface 309 */ 310static void 311tapcreate(dev) 312 dev_t dev; 313{ 314 struct ifnet *ifp = NULL; 315 struct tap_softc *tp = NULL; 316 unsigned short macaddr_hi; 317 int unit, s; 318 char *name = NULL; 319 320 /* allocate driver storage and create device */ 321 MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 322 SLIST_INSERT_HEAD(&taphead, tp, tap_next); 323 324 unit = dev2unit(dev) & TAPMAXUNIT; 325 326 /* select device: tap or vmnet */ 327 if (minor(dev) & VMNET_DEV_MASK) { 328 name = VMNET; 329 tp->tap_flags |= TAP_VMNET; 330 } else 331 name = TAP; 332 333 TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 334 335 if (!(dev->si_flags & SI_NAMED)) 336 dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 337 0600, "%s%d", name, unit); 338 339 /* generate fake MAC address: 00 bd xx xx xx unit_no */ 340 macaddr_hi = htons(0x00bd); 341 bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 342 bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 343 tp->arpcom.ac_enaddr[5] = (u_char)unit; 344 345 /* fill the rest and attach interface */ 346 ifp = &tp->tap_if; 347 ifp->if_softc = tp; 348 if_initname(ifp, name, unit); 349 ifp->if_init = tapifinit; 350 ifp->if_start = tapifstart; 351 ifp->if_ioctl = tapifioctl; 352 ifp->if_mtu = ETHERMTU; 353 ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 354 ifp->if_snd.ifq_maxlen = ifqmaxlen; 355 356 dev->si_drv1 = tp; 357 358 s = splimp(); 359 ether_ifattach(ifp, tp->arpcom.ac_enaddr); 360 splx(s); 361 362 tp->tap_flags |= TAP_INITED; 363 364 TAPDEBUG("interface %s is created. minor = %#x\n", 365 ifp->if_xname, minor(dev)); 366} /* tapcreate */ 367 368 369/* 370 * tapopen 371 * 372 * to open tunnel. must be superuser 373 */ 374static int 375tapopen(dev, flag, mode, td) 376 dev_t dev; 377 int flag; 378 int mode; 379 struct thread *td; 380{ 381 struct tap_softc *tp = NULL; 382 int unit, error; 383 struct resource *r = NULL; 384 385 if ((error = suser(td)) != 0) 386 return (error); 387 388 unit = dev2unit(dev) & TAPMAXUNIT; 389 390 if (minor(dev) & VMNET_DEV_MASK) 391 r = rman_reserve_resource(vmnetunits, unit, unit, 1, 392 RF_ALLOCATED | RF_ACTIVE, NULL); 393 else 394 r = rman_reserve_resource(tapunits, unit, unit, 1, 395 RF_ALLOCATED | RF_ACTIVE, NULL); 396 397 if (r == NULL) 398 return (EBUSY); 399 400 dev->si_flags &= ~SI_CHEAPCLONE; 401 402 tp = dev->si_drv1; 403 if (tp == NULL) { 404 tapcreate(dev); 405 tp = dev->si_drv1; 406 } 407 408 KASSERT(!(tp->tap_flags & TAP_OPEN), 409 ("%s flags is out of sync", tp->tap_if.if_xname)); 410 411 bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 412 413 tp->tap_unit = r; 414 tp->tap_pid = td->td_proc->p_pid; 415 tp->tap_flags |= TAP_OPEN; 416 417 TAPDEBUG("%s is open. minor = %#x\n", 418 tp->tap_if.if_xname, minor(dev)); 419 420 return (0); 421} /* tapopen */ 422 423 424/* 425 * tapclose 426 * 427 * close the device - mark i/f down & delete routing info 428 */ 429static int 430tapclose(dev, foo, bar, td) 431 dev_t dev; 432 int foo; 433 int bar; 434 struct thread *td; 435{ 436 int s, error; 437 struct tap_softc *tp = dev->si_drv1; 438 struct ifnet *ifp = &tp->tap_if; 439 440 KASSERT((tp->tap_unit != NULL), 441 ("%s is not open", ifp->if_xname)); 442 443 /* junk all pending output */ 444 IF_DRAIN(&ifp->if_snd); 445 446 /* 447 * do not bring the interface down, and do not anything with 448 * interface, if we are in VMnet mode. just close the device. 449 */ 450 451 if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 452 s = splimp(); 453 if_down(ifp); 454 if (ifp->if_flags & IFF_RUNNING) { 455 /* find internet addresses and delete routes */ 456 struct ifaddr *ifa = NULL; 457 458 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 459 if (ifa->ifa_addr->sa_family == AF_INET) { 460 rtinit(ifa, (int)RTM_DELETE, 0); 461 462 /* remove address from interface */ 463 bzero(ifa->ifa_addr, 464 sizeof(*(ifa->ifa_addr))); 465 bzero(ifa->ifa_dstaddr, 466 sizeof(*(ifa->ifa_dstaddr))); 467 bzero(ifa->ifa_netmask, 468 sizeof(*(ifa->ifa_netmask))); 469 } 470 } 471 472 ifp->if_flags &= ~IFF_RUNNING; 473 } 474 splx(s); 475 } 476 477 funsetown(&tp->tap_sigio); 478 selwakeup(&tp->tap_rsel); 479 480 tp->tap_flags &= ~TAP_OPEN; 481 tp->tap_pid = 0; 482 error = rman_release_resource(tp->tap_unit); 483 KASSERT((error == 0), 484 ("%s could not release unit", ifp->if_xname)); 485 tp->tap_unit = NULL; 486 487 TAPDEBUG("%s is closed. minor = %#x\n", 488 ifp->if_xname, minor(dev)); 489 490 return (0); 491} /* tapclose */ 492 493 494/* 495 * tapifinit 496 * 497 * network interface initialization function 498 */ 499static void 500tapifinit(xtp) 501 void *xtp; 502{ 503 struct tap_softc *tp = (struct tap_softc *)xtp; 504 struct ifnet *ifp = &tp->tap_if; 505 506 TAPDEBUG("initializing %s\n", ifp->if_xname); 507 508 ifp->if_flags |= IFF_RUNNING; 509 ifp->if_flags &= ~IFF_OACTIVE; 510 511 /* attempt to start output */ 512 tapifstart(ifp); 513} /* tapifinit */ 514 515 516/* 517 * tapifioctl 518 * 519 * Process an ioctl request on network interface 520 */ 521static int 522tapifioctl(ifp, cmd, data) 523 struct ifnet *ifp; 524 u_long cmd; 525 caddr_t data; 526{ 527 struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 528 struct ifstat *ifs = NULL; 529 int s, dummy; 530 531 switch (cmd) { 532 case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 533 case SIOCADDMULTI: 534 case SIOCDELMULTI: 535 break; 536 537 case SIOCGIFSTATUS: 538 s = splimp(); 539 ifs = (struct ifstat *)data; 540 dummy = strlen(ifs->ascii); 541 if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 542 snprintf(ifs->ascii + dummy, 543 sizeof(ifs->ascii) - dummy, 544 "\tOpened by PID %d\n", tp->tap_pid); 545 splx(s); 546 break; 547 548 default: 549 s = splimp(); 550 dummy = ether_ioctl(ifp, cmd, data); 551 splx(s); 552 return (dummy); 553 } 554 555 return (0); 556} /* tapifioctl */ 557 558 559/* 560 * tapifstart 561 * 562 * queue packets from higher level ready to put out 563 */ 564static void 565tapifstart(ifp) 566 struct ifnet *ifp; 567{ 568 struct tap_softc *tp = ifp->if_softc; 569 int s; 570 571 TAPDEBUG("%s starting\n", ifp->if_xname); 572 573 /* 574 * do not junk pending output if we are in VMnet mode. 575 * XXX: can this do any harm because of queue overflow? 576 */ 577 578 if (((tp->tap_flags & TAP_VMNET) == 0) && 579 ((tp->tap_flags & TAP_READY) != TAP_READY)) { 580 struct mbuf *m = NULL; 581 582 TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 583 tp->tap_flags); 584 585 s = splimp(); 586 do { 587 IF_DEQUEUE(&ifp->if_snd, m); 588 if (m != NULL) 589 m_freem(m); 590 ifp->if_oerrors ++; 591 } while (m != NULL); 592 splx(s); 593 594 return; 595 } 596 597 s = splimp(); 598 ifp->if_flags |= IFF_OACTIVE; 599 600 if (ifp->if_snd.ifq_len != 0) { 601 if (tp->tap_flags & TAP_RWAIT) { 602 tp->tap_flags &= ~TAP_RWAIT; 603 wakeup(tp); 604 } 605 606 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) 607 pgsigio(&tp->tap_sigio, SIGIO, 0); 608 609 selwakeup(&tp->tap_rsel); 610 ifp->if_opackets ++; /* obytes are counted in ether_output */ 611 } 612 613 ifp->if_flags &= ~IFF_OACTIVE; 614 splx(s); 615} /* tapifstart */ 616 617 618/* 619 * tapioctl 620 * 621 * the cdevsw interface is now pretty minimal 622 */ 623static int 624tapioctl(dev, cmd, data, flag, td) 625 dev_t dev; 626 u_long cmd; 627 caddr_t data; 628 int flag; 629 struct thread *td; 630{ 631 struct tap_softc *tp = dev->si_drv1; 632 struct ifnet *ifp = &tp->tap_if; 633 struct tapinfo *tapp = NULL; 634 int s; 635 int f; 636 637 switch (cmd) { 638 case TAPSIFINFO: 639 s = splimp(); 640 tapp = (struct tapinfo *)data; 641 ifp->if_mtu = tapp->mtu; 642 ifp->if_type = tapp->type; 643 ifp->if_baudrate = tapp->baudrate; 644 splx(s); 645 break; 646 647 case TAPGIFINFO: 648 tapp = (struct tapinfo *)data; 649 tapp->mtu = ifp->if_mtu; 650 tapp->type = ifp->if_type; 651 tapp->baudrate = ifp->if_baudrate; 652 break; 653 654 case TAPSDEBUG: 655 tapdebug = *(int *)data; 656 break; 657 658 case TAPGDEBUG: 659 *(int *)data = tapdebug; 660 break; 661 662 case FIONBIO: 663 break; 664 665 case FIOASYNC: 666 s = splimp(); 667 if (*(int *)data) 668 tp->tap_flags |= TAP_ASYNC; 669 else 670 tp->tap_flags &= ~TAP_ASYNC; 671 splx(s); 672 break; 673 674 case FIONREAD: 675 s = splimp(); 676 if (ifp->if_snd.ifq_head) { 677 struct mbuf *mb = ifp->if_snd.ifq_head; 678 679 for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 680 *(int *)data += mb->m_len; 681 } else 682 *(int *)data = 0; 683 splx(s); 684 break; 685 686 case FIOSETOWN: 687 return (fsetown(*(int *)data, &tp->tap_sigio)); 688 689 case FIOGETOWN: 690 *(int *)data = fgetown(&tp->tap_sigio); 691 return (0); 692 693 /* this is deprecated, FIOSETOWN should be used instead */ 694 case TIOCSPGRP: 695 return (fsetown(-(*(int *)data), &tp->tap_sigio)); 696 697 /* this is deprecated, FIOGETOWN should be used instead */ 698 case TIOCGPGRP: 699 *(int *)data = -fgetown(&tp->tap_sigio); 700 return (0); 701 702 /* VMware/VMnet port ioctl's */ 703 704 case SIOCGIFFLAGS: /* get ifnet flags */ 705 bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 706 break; 707 708 case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 709 f = *(int *)data; 710 f &= 0x0fff; 711 f &= ~IFF_CANTCHANGE; 712 f |= IFF_UP; 713 714 s = splimp(); 715 ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 716 splx(s); 717 break; 718 719 case OSIOCGIFADDR: /* get MAC address of the remote side */ 720 case SIOCGIFADDR: 721 bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 722 break; 723 724 case SIOCSIFADDR: /* set MAC address of the remote side */ 725 bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 726 break; 727 728 default: 729 return (ENOTTY); 730 } 731 return (0); 732} /* tapioctl */ 733 734 735/* 736 * tapread 737 * 738 * the cdevsw read interface - reads a packet at a time, or at 739 * least as much of a packet as can be read 740 */ 741static int 742tapread(dev, uio, flag) 743 dev_t dev; 744 struct uio *uio; 745 int flag; 746{ 747 struct tap_softc *tp = dev->si_drv1; 748 struct ifnet *ifp = &tp->tap_if; 749 struct mbuf *m = NULL; 750 int error = 0, len, s; 751 752 TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev)); 753 754 if ((tp->tap_flags & TAP_READY) != TAP_READY) { 755 TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 756 ifp->if_xname, minor(dev), tp->tap_flags); 757 758 return (EHOSTDOWN); 759 } 760 761 tp->tap_flags &= ~TAP_RWAIT; 762 763 /* sleep until we get a packet */ 764 do { 765 s = splimp(); 766 IF_DEQUEUE(&ifp->if_snd, m); 767 splx(s); 768 769 if (m == NULL) { 770 if (flag & IO_NDELAY) 771 return (EWOULDBLOCK); 772 773 tp->tap_flags |= TAP_RWAIT; 774 error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); 775 if (error) 776 return (error); 777 } 778 } while (m == NULL); 779 780 /* feed packet to bpf */ 781 BPF_MTAP(ifp, m); 782 783 /* xfer packet to user space */ 784 while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 785 len = min(uio->uio_resid, m->m_len); 786 if (len == 0) 787 break; 788 789 error = uiomove(mtod(m, void *), len, uio); 790 m = m_free(m); 791 } 792 793 if (m != NULL) { 794 TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 795 minor(dev)); 796 m_freem(m); 797 } 798 799 return (error); 800} /* tapread */ 801 802 803/* 804 * tapwrite 805 * 806 * the cdevsw write interface - an atomic write is a packet - or else! 807 */ 808static int 809tapwrite(dev, uio, flag) 810 dev_t dev; 811 struct uio *uio; 812 int flag; 813{ 814 struct tap_softc *tp = dev->si_drv1; 815 struct ifnet *ifp = &tp->tap_if; 816 struct mbuf *top = NULL, **mp = NULL, *m = NULL; 817 int error = 0, tlen, mlen; 818 819 TAPDEBUG("%s writting, minor = %#x\n", 820 ifp->if_xname, minor(dev)); 821 822 if (uio->uio_resid == 0) 823 return (0); 824 825 if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 826 TAPDEBUG("%s invalid packet len = %d, minor = %#x\n", 827 ifp->if_xname, uio->uio_resid, minor(dev)); 828 829 return (EIO); 830 } 831 tlen = uio->uio_resid; 832 833 /* get a header mbuf */ 834 MGETHDR(m, M_DONTWAIT, MT_DATA); 835 if (m == NULL) 836 return (ENOBUFS); 837 mlen = MHLEN; 838 839 top = 0; 840 mp = ⊤ 841 while ((error == 0) && (uio->uio_resid > 0)) { 842 m->m_len = min(mlen, uio->uio_resid); 843 error = uiomove(mtod(m, void *), m->m_len, uio); 844 *mp = m; 845 mp = &m->m_next; 846 if (uio->uio_resid > 0) { 847 MGET(m, M_DONTWAIT, MT_DATA); 848 if (m == NULL) { 849 error = ENOBUFS; 850 break; 851 } 852 mlen = MLEN; 853 } 854 } 855 if (error) { 856 ifp->if_ierrors ++; 857 if (top) 858 m_freem(top); 859 return (error); 860 } 861 862 top->m_pkthdr.len = tlen; 863 top->m_pkthdr.rcvif = ifp; 864 865 /* Pass packet up to parent. */ 866 (*ifp->if_input)(ifp, top); 867 ifp->if_ipackets ++; /* ibytes are counted in parent */ 868 869 return (0); 870} /* tapwrite */ 871 872 873/* 874 * tappoll 875 * 876 * the poll interface, this is only useful on reads 877 * really. the write detect always returns true, write never blocks 878 * anyway, it either accepts the packet or drops it 879 */ 880static int 881tappoll(dev, events, td) 882 dev_t dev; 883 int events; 884 struct thread *td; 885{ 886 struct tap_softc *tp = dev->si_drv1; 887 struct ifnet *ifp = &tp->tap_if; 888 int s, revents = 0; 889 890 TAPDEBUG("%s polling, minor = %#x\n", 891 ifp->if_xname, minor(dev)); 892 893 s = splimp(); 894 if (events & (POLLIN | POLLRDNORM)) { 895 if (ifp->if_snd.ifq_len > 0) { 896 TAPDEBUG("%s have data in queue. len = %d, " \ 897 "minor = %#x\n", ifp->if_xname, 898 ifp->if_snd.ifq_len, minor(dev)); 899 900 revents |= (events & (POLLIN | POLLRDNORM)); 901 } else { 902 TAPDEBUG("%s waiting for data, minor = %#x\n", 903 ifp->if_xname, minor(dev)); 904 905 selrecord(td, &tp->tap_rsel); 906 } 907 } 908 909 if (events & (POLLOUT | POLLWRNORM)) 910 revents |= (events & (POLLOUT | POLLWRNORM)); 911 912 splx(s); 913 return (revents); 914} /* tappoll */ 915