if_tap.c revision 121816
1/* 2 * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * BASED ON: 27 * ------------------------------------------------------------------------- 28 * 29 * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> 30 * Nottingham University 1987. 31 */ 32 33/* 34 * $FreeBSD: head/sys/net/if_tap.c 121816 2003-10-31 18:32:15Z brooks $ 35 * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ 36 */ 37 38#include "opt_inet.h" 39 40#include <sys/param.h> 41#include <sys/conf.h> 42#include <sys/filedesc.h> 43#include <sys/filio.h> 44#include <sys/kernel.h> 45#include <sys/malloc.h> 46#include <sys/mbuf.h> 47#include <sys/poll.h> 48#include <sys/proc.h> 49#include <sys/signalvar.h> 50#include <sys/socket.h> 51#include <sys/sockio.h> 52#include <sys/sysctl.h> 53#include <sys/systm.h> 54#include <sys/ttycom.h> 55#include <sys/uio.h> 56#include <sys/vnode.h> 57#include <machine/bus.h> /* XXX: Shouldn't really be required! */ 58#include <sys/rman.h> 59#include <sys/queue.h> 60 61#include <net/bpf.h> 62#include <net/ethernet.h> 63#include <net/if.h> 64#include <net/if_arp.h> 65#include <net/route.h> 66 67#include <netinet/in.h> 68 69#include <net/if_tapvar.h> 70#include <net/if_tap.h> 71 72 73#define CDEV_NAME "tap" 74#define CDEV_MAJOR 149 75#define TAPDEBUG if (tapdebug) printf 76 77#define TAP "tap" 78#define VMNET "vmnet" 79#define TAPMAXUNIT 0x7fff 80#define VMNET_DEV_MASK 0x00800000 81 /* 0x007f00ff */ 82 83/* module */ 84static int tapmodevent(module_t, int, void *); 85 86/* device */ 87static void tapclone(void *, char *, int, dev_t *); 88static void tapcreate(dev_t); 89 90/* network interface */ 91static void tapifstart(struct ifnet *); 92static int tapifioctl(struct ifnet *, u_long, caddr_t); 93static void tapifinit(void *); 94 95/* character device */ 96static d_open_t tapopen; 97static d_close_t tapclose; 98static d_read_t tapread; 99static d_write_t tapwrite; 100static d_ioctl_t tapioctl; 101static d_poll_t tappoll; 102 103static struct cdevsw tap_cdevsw = { 104 .d_open = tapopen, 105 .d_close = tapclose, 106 .d_read = tapread, 107 .d_write = tapwrite, 108 .d_ioctl = tapioctl, 109 .d_poll = tappoll, 110 .d_name = CDEV_NAME, 111 .d_maj = CDEV_MAJOR, 112}; 113 114static int tapdebug = 0; /* debug flag */ 115static SLIST_HEAD(, tap_softc) taphead; /* first device */ 116static udev_t tapbasedev = NOUDEV; /* base device */ 117static struct rman tapdevunits[2]; /* device units */ 118#define tapunits tapdevunits 119#define vmnetunits (tapdevunits + 1) 120 121MALLOC_DECLARE(M_TAP); 122MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 123SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 124DEV_MODULE(if_tap, tapmodevent, NULL); 125 126/* 127 * tapmodevent 128 * 129 * module event handler 130 */ 131static int 132tapmodevent(mod, type, data) 133 module_t mod; 134 int type; 135 void *data; 136{ 137 static eventhandler_tag eh_tag = NULL; 138 struct tap_softc *tp = NULL; 139 struct ifnet *ifp = NULL; 140 int error, s; 141 142 switch (type) { 143 case MOD_LOAD: 144 /* initialize resources */ 145 tapunits->rm_type = RMAN_ARRAY; 146 tapunits->rm_descr = "open tap units"; 147 vmnetunits->rm_type = RMAN_ARRAY; 148 vmnetunits->rm_descr = "open vmnet units"; 149 150 error = rman_init(tapunits); 151 if (error != 0) 152 goto bail; 153 154 error = rman_init(vmnetunits); 155 if (error != 0) 156 goto bail1; 157 158 error = rman_manage_region(tapunits, 0, TAPMAXUNIT); 159 if (error != 0) 160 goto bail2; 161 162 error = rman_manage_region(vmnetunits, 0, TAPMAXUNIT); 163 if (error != 0) 164 goto bail2; 165 166 /* intitialize device */ 167 168 SLIST_INIT(&taphead); 169 170 eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 171 if (eh_tag == NULL) { 172 error = ENOMEM; 173 goto bail2; 174 } 175 176 177 return (0); 178bail2: 179 rman_fini(vmnetunits); 180bail1: 181 rman_fini(tapunits); 182bail: 183 return (error); 184 185 case MOD_UNLOAD: 186 SLIST_FOREACH(tp, &taphead, tap_next) 187 if (tp->tap_unit != NULL) 188 return (EBUSY); 189 190 EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 191 192 error = rman_fini(tapunits); 193 KASSERT((error == 0), ("Could not fini tap units")); 194 error = rman_fini(vmnetunits); 195 KASSERT((error == 0), ("Could not fini vmnet units")); 196 197 while ((tp = SLIST_FIRST(&taphead)) != NULL) { 198 SLIST_REMOVE_HEAD(&taphead, tap_next); 199 200 ifp = &tp->tap_if; 201 202 TAPDEBUG("detaching %s\n", ifp->if_xname); 203 204 KASSERT(!(tp->tap_flags & TAP_OPEN), 205 ("%s flags is out of sync", ifp->if_xname)); 206 207 /* XXX makedev check? nah.. not right now :) */ 208 209 s = splimp(); 210 ether_ifdetach(ifp); 211 splx(s); 212 213 free(tp, M_TAP); 214 } 215 216 if (tapbasedev != NOUDEV) 217 destroy_dev(udev2dev(tapbasedev, 0)); 218 219 220 break; 221 222 default: 223 return (EOPNOTSUPP); 224 } 225 226 return (0); 227} /* tapmodevent */ 228 229 230/* 231 * DEVFS handler 232 * 233 * We need to support two kind of devices - tap and vmnet 234 */ 235static void 236tapclone(arg, name, namelen, dev) 237 void *arg; 238 char *name; 239 int namelen; 240 dev_t *dev; 241{ 242 int unit, minor = 0 /* XXX avoid warning */ , error; 243 char *device_name = name; 244 struct resource *r = NULL; 245 246 if (*dev != NODEV) 247 return; 248 249 if (strcmp(device_name, TAP) == 0) { 250 /* 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