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