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: src/sys/net/if_tap.c,v 1.3.2.3 2002/04/14 21:41:48 luigi Exp $ 35 * $DragonFly: src/sys/net/tap/if_tap.c,v 1.20 2005/06/14 18:37:26 joerg Exp $ 36 * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ 37 */ 38 39 #include "opt_inet.h" 40 41 #include <sys/param.h> 42 #include <sys/conf.h> 43 #include <sys/filedesc.h> 44 #include <sys/filio.h> 45 #include <sys/kernel.h> 46 #include <sys/malloc.h> 47 #include <sys/mbuf.h> 48 #include <sys/poll.h> 49 #include <sys/proc.h> 50 #include <sys/signalvar.h> 51 #include <sys/socket.h> 52 #include <sys/sockio.h> 53 #include <sys/sysctl.h> 54 #include <sys/systm.h> 55 #include <sys/thread2.h> 56 #include <sys/ttycom.h> 57 #include <sys/uio.h> 58 #include <sys/vnode.h> 59 60 #include <net/bpf.h> 61 #include <net/ethernet.h> 62 #include <net/if.h> 63 #include <net/ifq_var.h> 64 #include <net/if_arp.h> 65 #include <net/route.h> 66 67 #include <netinet/in.h> 68 69 #include "if_tapvar.h" 70 #include "if_tap.h" 71 72 73 #define CDEV_NAME "tap" 74 #define CDEV_MAJOR 149 75 #define TAPDEBUG if (tapdebug) if_printf 76 77 #define TAP "tap" 78 #define VMNET "vmnet" 79 #define VMNET_DEV_MASK 0x00010000 80 81 /* module */ 82 static int tapmodevent (module_t, int, void *); 83 84 /* device */ 85 static void tapcreate (dev_t); 86 87 /* network interface */ 88 static void tapifstart (struct ifnet *); 89 static int tapifioctl (struct ifnet *, u_long, caddr_t, 90 struct ucred *); 91 static void tapifinit (void *); 92 93 /* character device */ 94 static d_open_t tapopen; 95 static d_close_t tapclose; 96 static d_read_t tapread; 97 static d_write_t tapwrite; 98 static d_ioctl_t tapioctl; 99 static d_poll_t tappoll; 100 101 static struct cdevsw tap_cdevsw = { 102 /* dev name */ CDEV_NAME, 103 /* dev major */ CDEV_MAJOR, 104 /* flags */ 0, 105 /* port */ NULL, 106 /* clone */ NULL, 107 108 /* open */ tapopen, 109 /* close */ tapclose, 110 /* read */ tapread, 111 /* write */ tapwrite, 112 /* ioctl */ tapioctl, 113 /* poll */ tappoll, 114 /* mmap */ nommap, 115 /* startegy */ nostrategy, 116 /* dump */ nodump, 117 /* psize */ nopsize 118 }; 119 120 static int taprefcnt = 0; /* module ref. counter */ 121 static int taplastunit = -1; /* max. open unit number */ 122 static int tapdebug = 0; /* debug flag */ 123 124 MALLOC_DECLARE(M_TAP); 125 MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 126 SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 127 DEV_MODULE(if_tap, tapmodevent, NULL); 128 129 /* 130 * tapmodevent 131 * 132 * module event handler 133 */ 134 static int 135 tapmodevent(mod, type, data) 136 module_t mod; 137 int type; 138 void *data; 139 { 140 static int attached = 0; 141 struct ifnet *ifp = NULL; 142 int unit; 143 144 switch (type) { 145 case MOD_LOAD: 146 if (attached) 147 return (EEXIST); 148 149 cdevsw_add(&tap_cdevsw, 0, 0); 150 attached = 1; 151 break; 152 153 case MOD_UNLOAD: 154 if (taprefcnt > 0) 155 return (EBUSY); 156 157 cdevsw_remove(&tap_cdevsw, 0, 0); 158 159 /* XXX: maintain tap ifs in a local list */ 160 unit = 0; 161 while (unit <= taplastunit) { 162 crit_enter(); 163 TAILQ_FOREACH(ifp, &ifnet, if_link) 164 if ((strcmp(ifp->if_dname, TAP) == 0) || 165 (strcmp(ifp->if_dname, VMNET) == 0)) 166 if (ifp->if_dunit == unit) 167 break; 168 crit_exit(); 169 170 if (ifp != NULL) { 171 struct tap_softc *tp = ifp->if_softc; 172 173 TAPDEBUG(ifp, "detached. minor = %#x, " \ 174 "taplastunit = %d\n", 175 minor(tp->tap_dev), taplastunit); 176 177 crit_enter(); 178 ether_ifdetach(ifp); 179 crit_exit(); 180 destroy_dev(tp->tap_dev); 181 free(tp, M_TAP); 182 } 183 else 184 unit ++; 185 } 186 187 attached = 0; 188 break; 189 190 default: 191 return (EOPNOTSUPP); 192 } 193 194 return (0); 195 } /* tapmodevent */ 196 197 198 /* 199 * tapcreate 200 * 201 * to create interface 202 */ 203 static void 204 tapcreate(dev) 205 dev_t dev; 206 { 207 struct ifnet *ifp = NULL; 208 struct tap_softc *tp = NULL; 209 uint8_t ether_addr[ETHER_ADDR_LEN]; 210 int unit; 211 char *name = NULL; 212 213 /* allocate driver storage and create device */ 214 MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK); 215 bzero(tp, sizeof(*tp)); 216 217 /* select device: tap or vmnet */ 218 if (minor(dev) & VMNET_DEV_MASK) { 219 name = VMNET; 220 unit = lminor(dev) & 0xff; 221 tp->tap_flags |= TAP_VMNET; 222 } 223 else { 224 name = TAP; 225 unit = lminor(dev); 226 } 227 228 tp->tap_dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 229 0600, "%s%d", name, unit); 230 tp->tap_dev->si_drv1 = dev->si_drv1 = tp; 231 reference_dev(tp->tap_dev); /* so we can destroy it later */ 232 233 /* generate fake MAC address: 00 bd xx xx xx unit_no */ 234 ether_addr[0] = 0x00; 235 ether_addr[1] = 0xbd; 236 bcopy(&ticks, ether_addr, 4); 237 ether_addr[5] = (u_char)unit; 238 239 /* fill the rest and attach interface */ 240 ifp = &tp->tap_if; 241 ifp->if_softc = tp; 242 243 if_initname(ifp, name, unit); 244 if (unit > taplastunit) 245 taplastunit = unit; 246 247 ifp->if_init = tapifinit; 248 ifp->if_start = tapifstart; 249 ifp->if_ioctl = tapifioctl; 250 ifp->if_mtu = ETHERMTU; 251 ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 252 ifq_set_maxlen(&ifp->if_snd, ifqmaxlen); 253 ifq_set_ready(&ifp->if_snd); 254 255 ether_ifattach(ifp, ether_addr); 256 257 tp->tap_flags |= TAP_INITED; 258 259 TAPDEBUG(ifp, "created. minor = %#x\n", minor(tp->tap_dev)); 260 } /* tapcreate */ 261 262 263 /* 264 * tapopen 265 * 266 * to open tunnel. must be superuser 267 */ 268 static int 269 tapopen(dev_t dev, int flag, int mode, d_thread_t *td) 270 { 271 struct tap_softc *tp = NULL; 272 int error; 273 274 if ((error = suser(td)) != 0) 275 return (error); 276 277 tp = dev->si_drv1; 278 if (tp == NULL) { 279 tapcreate(dev); 280 tp = dev->si_drv1; 281 } 282 283 if (tp->tap_flags & TAP_OPEN) 284 return (EBUSY); 285 286 bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 287 288 tp->tap_td = td; 289 tp->tap_flags |= TAP_OPEN; 290 taprefcnt ++; 291 292 TAPDEBUG(&tp->arpcom.ac_if, 293 "opened. minor = %#x, refcnt = %d, taplastunit = %d\n", 294 minor(tp->tap_dev), taprefcnt, taplastunit); 295 296 return (0); 297 } /* tapopen */ 298 299 300 /* 301 * tapclose 302 * 303 * close the device - mark i/f down & delete routing info 304 */ 305 static int 306 tapclose(dev_t dev, int foo, int bar, d_thread_t *td) 307 { 308 struct tap_softc *tp = dev->si_drv1; 309 struct ifnet *ifp = &tp->tap_if; 310 311 /* junk all pending output */ 312 313 crit_enter(); 314 ifq_purge(&ifp->if_snd); 315 crit_exit(); 316 317 /* 318 * do not bring the interface down, and do not anything with 319 * interface, if we are in VMnet mode. just close the device. 320 */ 321 322 if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 323 crit_enter(); 324 if_down(ifp); 325 if (ifp->if_flags & IFF_RUNNING) { 326 /* find internet addresses and delete routes */ 327 struct ifaddr *ifa = NULL; 328 329 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 330 if (ifa->ifa_addr->sa_family == AF_INET) { 331 rtinit(ifa, (int)RTM_DELETE, 0); 332 333 /* remove address from interface */ 334 bzero(ifa->ifa_addr, 335 sizeof(*(ifa->ifa_addr))); 336 bzero(ifa->ifa_dstaddr, 337 sizeof(*(ifa->ifa_dstaddr))); 338 bzero(ifa->ifa_netmask, 339 sizeof(*(ifa->ifa_netmask))); 340 } 341 } 342 343 ifp->if_flags &= ~IFF_RUNNING; 344 } 345 crit_exit(); 346 } 347 348 funsetown(tp->tap_sigio); 349 selwakeup(&tp->tap_rsel); 350 351 tp->tap_flags &= ~TAP_OPEN; 352 tp->tap_td = NULL; 353 354 taprefcnt --; 355 if (taprefcnt < 0) { 356 taprefcnt = 0; 357 if_printf(ifp, "minor = %#x, refcnt = %d is out of sync. " 358 "set refcnt to 0\n", minor(tp->tap_dev), taprefcnt); 359 } 360 361 TAPDEBUG(ifp, "closed. minor = %#x, refcnt = %d, taplastunit = %d\n", 362 minor(tp->tap_dev), taprefcnt, taplastunit); 363 364 return (0); 365 } /* tapclose */ 366 367 368 /* 369 * tapifinit 370 * 371 * network interface initialization function 372 */ 373 static void 374 tapifinit(xtp) 375 void *xtp; 376 { 377 struct tap_softc *tp = (struct tap_softc *)xtp; 378 struct ifnet *ifp = &tp->tap_if; 379 380 TAPDEBUG(ifp, "initializing, minor = %#x\n", minor(tp->tap_dev)); 381 382 ifp->if_flags |= IFF_RUNNING; 383 ifp->if_flags &= ~IFF_OACTIVE; 384 385 /* attempt to start output */ 386 tapifstart(ifp); 387 } /* tapifinit */ 388 389 390 /* 391 * tapifioctl 392 * 393 * Process an ioctl request on network interface 394 */ 395 int 396 tapifioctl(ifp, cmd, data, cr) 397 struct ifnet *ifp; 398 u_long cmd; 399 caddr_t data; 400 struct ucred *cr; 401 { 402 struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 403 struct ifstat *ifs = NULL; 404 int dummy; 405 406 switch (cmd) { 407 case SIOCSIFADDR: 408 case SIOCGIFADDR: 409 case SIOCSIFMTU: 410 crit_enter(); 411 dummy = ether_ioctl(ifp, cmd, data); 412 crit_exit(); 413 return (dummy); 414 415 case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 416 case SIOCADDMULTI: 417 case SIOCDELMULTI: 418 break; 419 420 case SIOCGIFSTATUS: 421 crit_enter(); 422 ifs = (struct ifstat *)data; 423 dummy = strlen(ifs->ascii); 424 if (tp->tap_td != NULL && dummy < sizeof(ifs->ascii)) { 425 if (tp->tap_td->td_proc) { 426 snprintf(ifs->ascii + dummy, 427 sizeof(ifs->ascii) - dummy, 428 "\tOpened by pid %d\n", 429 (int)tp->tap_td->td_proc->p_pid); 430 } else { 431 snprintf(ifs->ascii + dummy, 432 sizeof(ifs->ascii) - dummy, 433 "\tOpened by td %p\n", tp->tap_td); 434 } 435 } 436 crit_exit(); 437 break; 438 439 default: 440 return (EINVAL); 441 } 442 443 return (0); 444 } /* tapifioctl */ 445 446 447 /* 448 * tapifstart 449 * 450 * queue packets from higher level ready to put out 451 */ 452 static void 453 tapifstart(ifp) 454 struct ifnet *ifp; 455 { 456 struct tap_softc *tp = ifp->if_softc; 457 458 TAPDEBUG(ifp, "starting, minor = %#x\n", minor(tp->tap_dev)); 459 460 /* 461 * do not junk pending output if we are in VMnet mode. 462 * XXX: can this do any harm because of queue overflow? 463 */ 464 465 if (((tp->tap_flags & TAP_VMNET) == 0) && 466 ((tp->tap_flags & TAP_READY) != TAP_READY)) { 467 TAPDEBUG(ifp, "not ready. minor = %#x, tap_flags = 0x%x\n", 468 minor(tp->tap_dev), tp->tap_flags); 469 470 crit_enter(); 471 ifq_purge(&ifp->if_snd); 472 crit_exit(); 473 return; 474 } 475 476 crit_enter(); 477 478 ifp->if_flags |= IFF_OACTIVE; 479 480 if (!ifq_is_empty(&ifp->if_snd)) { 481 if (tp->tap_flags & TAP_RWAIT) { 482 tp->tap_flags &= ~TAP_RWAIT; 483 wakeup((caddr_t)tp); 484 } 485 486 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) 487 pgsigio(tp->tap_sigio, SIGIO, 0); 488 489 selwakeup(&tp->tap_rsel); 490 ifp->if_opackets ++; /* obytes are counted in ether_output */ 491 } 492 493 ifp->if_flags &= ~IFF_OACTIVE; 494 495 crit_exit(); 496 } /* tapifstart */ 497 498 499 /* 500 * tapioctl 501 * 502 * the cdevsw interface is now pretty minimal 503 */ 504 static int 505 tapioctl(dev_t dev, u_long cmd, caddr_t data, int flag, d_thread_t *td) 506 { 507 struct tap_softc *tp = dev->si_drv1; 508 struct ifnet *ifp = &tp->tap_if; 509 struct tapinfo *tapp = NULL; 510 struct mbuf *mb; 511 512 switch (cmd) { 513 case TAPSIFINFO: 514 crit_enter(); 515 tapp = (struct tapinfo *)data; 516 ifp->if_mtu = tapp->mtu; 517 ifp->if_type = tapp->type; 518 ifp->if_baudrate = tapp->baudrate; 519 crit_exit(); 520 break; 521 522 case TAPGIFINFO: 523 tapp = (struct tapinfo *)data; 524 tapp->mtu = ifp->if_mtu; 525 tapp->type = ifp->if_type; 526 tapp->baudrate = ifp->if_baudrate; 527 break; 528 529 case TAPSDEBUG: 530 tapdebug = *(int *)data; 531 break; 532 533 case TAPGDEBUG: 534 *(int *)data = tapdebug; 535 break; 536 537 case FIONBIO: 538 break; 539 540 case FIOASYNC: 541 crit_enter(); 542 if (*(int *)data) 543 tp->tap_flags |= TAP_ASYNC; 544 else 545 tp->tap_flags &= ~TAP_ASYNC; 546 crit_exit(); 547 break; 548 549 case FIONREAD: 550 crit_enter(); 551 *(int *)data = 0; 552 if ((mb = ifq_poll(&ifp->if_snd)) != NULL) { 553 for(; mb != NULL; mb = mb->m_next) 554 *(int *)data += mb->m_len; 555 } 556 crit_exit(); 557 break; 558 559 case FIOSETOWN: 560 return (fsetown(*(int *)data, &tp->tap_sigio)); 561 562 case FIOGETOWN: 563 *(int *)data = fgetown(tp->tap_sigio); 564 return (0); 565 566 /* this is deprecated, FIOSETOWN should be used instead */ 567 case TIOCSPGRP: 568 return (fsetown(-(*(int *)data), &tp->tap_sigio)); 569 570 /* this is deprecated, FIOGETOWN should be used instead */ 571 case TIOCGPGRP: 572 *(int *)data = -fgetown(tp->tap_sigio); 573 return (0); 574 575 /* VMware/VMnet port ioctl's */ 576 577 case SIOCGIFFLAGS: /* get ifnet flags */ 578 bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 579 break; 580 581 case VMIO_SIOCSIFFLAGS: { /* VMware/VMnet SIOCSIFFLAGS */ 582 short f = *(short *)data; 583 584 f &= 0x0fff; 585 f &= ~IFF_CANTCHANGE; 586 f |= IFF_UP; 587 588 crit_enter(); 589 ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 590 crit_exit(); 591 } break; 592 593 case OSIOCGIFADDR: /* get MAC address of the remote side */ 594 case SIOCGIFADDR: 595 bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 596 break; 597 598 case SIOCSIFADDR: /* set MAC address of the remote side */ 599 bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 600 break; 601 602 default: 603 return (ENOTTY); 604 } 605 return (0); 606 } /* tapioctl */ 607 608 609 /* 610 * tapread 611 * 612 * the cdevsw read interface - reads a packet at a time, or at 613 * least as much of a packet as can be read 614 */ 615 static int 616 tapread(dev, uio, flag) 617 dev_t dev; 618 struct uio *uio; 619 int flag; 620 { 621 struct tap_softc *tp = dev->si_drv1; 622 struct ifnet *ifp = &tp->tap_if; 623 struct mbuf *m0 = NULL; 624 int error = 0, len; 625 626 TAPDEBUG(ifp, "reading, minor = %#x\n", minor(tp->tap_dev)); 627 628 if ((tp->tap_flags & TAP_READY) != TAP_READY) { 629 TAPDEBUG(ifp, "not ready. minor = %#x, tap_flags = 0x%x\n", 630 minor(tp->tap_dev), tp->tap_flags); 631 632 return (EHOSTDOWN); 633 } 634 635 tp->tap_flags &= ~TAP_RWAIT; 636 637 /* sleep until we get a packet */ 638 do { 639 crit_enter(); 640 m0 = ifq_dequeue(&ifp->if_snd); 641 crit_exit(); 642 643 if (m0 == NULL) { 644 if (flag & IO_NDELAY) 645 return (EWOULDBLOCK); 646 647 tp->tap_flags |= TAP_RWAIT; 648 error = tsleep((caddr_t)tp, PCATCH, "taprd", 0); 649 if (error) 650 return (error); 651 } 652 } while (m0 == NULL); 653 654 BPF_MTAP(ifp, m0); 655 656 /* xfer packet to user space */ 657 while ((m0 != NULL) && (uio->uio_resid > 0) && (error == 0)) { 658 len = min(uio->uio_resid, m0->m_len); 659 if (len == 0) 660 break; 661 662 error = uiomove(mtod(m0, caddr_t), len, uio); 663 m0 = m_free(m0); 664 } 665 666 if (m0 != NULL) { 667 TAPDEBUG(ifp, "dropping mbuf, minor = %#x\n", 668 minor(tp->tap_dev)); 669 m_freem(m0); 670 } 671 672 return (error); 673 } /* tapread */ 674 675 676 /* 677 * tapwrite 678 * 679 * the cdevsw write interface - an atomic write is a packet - or else! 680 */ 681 static int 682 tapwrite(dev, uio, flag) 683 dev_t dev; 684 struct uio *uio; 685 int flag; 686 { 687 struct tap_softc *tp = dev->si_drv1; 688 struct ifnet *ifp = &tp->tap_if; 689 struct mbuf *top = NULL, **mp = NULL, *m = NULL; 690 int error = 0, tlen, mlen; 691 692 TAPDEBUG(ifp, "writting, minor = %#x\n", minor(tp->tap_dev)); 693 694 if (uio->uio_resid == 0) 695 return (0); 696 697 if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 698 TAPDEBUG(ifp, "invalid packet len = %d, minor = %#x\n", 699 uio->uio_resid, minor(tp->tap_dev)); 700 701 return (EIO); 702 } 703 tlen = uio->uio_resid; 704 705 /* get a header mbuf */ 706 MGETHDR(m, MB_DONTWAIT, MT_DATA); 707 if (m == NULL) 708 return (ENOBUFS); 709 mlen = MHLEN; 710 711 top = 0; 712 mp = ⊤ 713 while ((error == 0) && (uio->uio_resid > 0)) { 714 m->m_len = min(mlen, uio->uio_resid); 715 error = uiomove(mtod(m, caddr_t), m->m_len, uio); 716 *mp = m; 717 mp = &m->m_next; 718 if (uio->uio_resid > 0) { 719 MGET(m, MB_DONTWAIT, MT_DATA); 720 if (m == NULL) { 721 error = ENOBUFS; 722 break; 723 } 724 mlen = MLEN; 725 } 726 } 727 if (error) { 728 ifp->if_ierrors ++; 729 if (top) 730 m_freem(top); 731 return (error); 732 } 733 734 top->m_pkthdr.len = tlen; 735 top->m_pkthdr.rcvif = ifp; 736 737 /* 738 * Ethernet bridge and bpf are handled in ether_input 739 * 740 * adjust mbuf and give packet to the ether_input 741 */ 742 743 (*ifp->if_input)(ifp, top); 744 ifp->if_ipackets ++; /* ibytes are counted in ether_input */ 745 746 return (0); 747 } /* tapwrite */ 748 749 750 /* 751 * tappoll 752 * 753 * the poll interface, this is only useful on reads 754 * really. the write detect always returns true, write never blocks 755 * anyway, it either accepts the packet or drops it 756 */ 757 static int 758 tappoll(dev_t dev, int events, d_thread_t *td) 759 { 760 struct tap_softc *tp = dev->si_drv1; 761 struct ifnet *ifp = &tp->tap_if; 762 int revents = 0; 763 764 TAPDEBUG(ifp, "polling, minor = %#x\n", minor(tp->tap_dev)); 765 766 crit_enter(); 767 768 if (events & (POLLIN | POLLRDNORM)) { 769 if (!ifq_is_empty(&ifp->if_snd)) { 770 TAPDEBUG(ifp, 771 "has data in queue. minor = %#x\n", 772 minor(tp->tap_dev)); 773 774 revents |= (events & (POLLIN | POLLRDNORM)); 775 } 776 else { 777 TAPDEBUG(ifp, "waiting for data, minor = %#x\n", 778 minor(tp->tap_dev)); 779 780 selrecord(td, &tp->tap_rsel); 781 } 782 } 783 784 if (events & (POLLOUT | POLLWRNORM)) 785 revents |= (events & (POLLOUT | POLLWRNORM)); 786 787 crit_exit(); 788 return (revents); 789 } /* tappoll */ 790