if_tun.c revision 56410
1/* $NetBSD: if_tun.c,v 1.14 1994/06/29 06:36:25 cgd Exp $ */ 2 3/* 4 * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> 5 * Nottingham University 1987. 6 * 7 * This source may be freely distributed, however I would be interested 8 * in any changes that are made. 9 * 10 * This driver takes packets off the IP i/f and hands them up to a 11 * user process to have its wicked way with. This driver has it's 12 * roots in a similar driver written by Phil Cockcroft (formerly) at 13 * UCL. This driver is based much more on read/write/poll mode of 14 * operation though. 15 * 16 * $FreeBSD: head/sys/net/if_tun.c 56410 2000-01-23 01:47:12Z brian $ 17 */ 18 19#include "opt_atalk.h" 20#include "opt_inet.h" 21#include "opt_inet6.h" 22#include "opt_ipx.h" 23 24#include <sys/param.h> 25#include <sys/proc.h> 26#include <sys/systm.h> 27#include <sys/mbuf.h> 28#include <sys/socket.h> 29#include <sys/filio.h> 30#include <sys/sockio.h> 31#include <sys/ttycom.h> 32#include <sys/poll.h> 33#include <sys/signalvar.h> 34#include <sys/filedesc.h> 35#include <sys/kernel.h> 36#include <sys/sysctl.h> 37#include <sys/conf.h> 38#include <sys/uio.h> 39#include <sys/vnode.h> 40#include <sys/malloc.h> 41 42#include <net/if.h> 43#include <net/netisr.h> 44#include <net/route.h> 45 46#ifdef INET 47#include <netinet/in.h> 48#include <netinet/in_var.h> 49#endif 50 51#ifdef INET6 52#include <netinet6/in6.h> 53#include <netinet6/in6_var.h> 54#endif 55 56#ifdef NS 57/* This will never be defined by config(8), or for the if_tun module ! */ 58#include <netns/ns.h> 59#include <netns/ns_if.h> 60#endif 61 62#ifdef IPX 63#include <netipx/ipx.h> 64#include <netipx/ipx_if.h> 65#endif 66 67#ifdef NETATALK 68#include <netatalk/at.h> 69#include <netatalk/at_var.h> 70#endif 71 72#include <net/bpf.h> 73 74#include <net/if_tunvar.h> 75#include <net/if_tun.h> 76 77static MALLOC_DEFINE(M_TUN, "tun", "Tunnel Interface"); 78 79static void tunattach __P((void *)); 80PSEUDO_SET(tunattach, if_tun); 81 82static void tuncreate __P((dev_t dev)); 83 84#define TUNDEBUG if (tundebug) printf 85static int tundebug = 0; 86SYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, ""); 87 88static int tunoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *, 89 struct rtentry *rt)); 90static int tunifioctl __P((struct ifnet *, u_long, caddr_t)); 91static int tuninit __P((struct ifnet *)); 92 93static d_open_t tunopen; 94static d_close_t tunclose; 95static d_read_t tunread; 96static d_write_t tunwrite; 97static d_ioctl_t tunioctl; 98static d_poll_t tunpoll; 99 100#define CDEV_MAJOR 52 101static struct cdevsw tun_cdevsw = { 102 /* open */ tunopen, 103 /* close */ tunclose, 104 /* read */ tunread, 105 /* write */ tunwrite, 106 /* ioctl */ tunioctl, 107 /* poll */ tunpoll, 108 /* mmap */ nommap, 109 /* strategy */ nostrategy, 110 /* name */ "tun", 111 /* maj */ CDEV_MAJOR, 112 /* dump */ nodump, 113 /* psize */ nopsize, 114 /* flags */ 0, 115 /* bmaj */ -1 116}; 117 118static void 119tunattach(dummy) 120 void *dummy; 121{ 122 123 cdevsw_add(&tun_cdevsw); 124} 125 126static void 127tuncreate(dev) 128 dev_t dev; 129{ 130 struct tun_softc *sc; 131 struct ifnet *ifp; 132 133 dev = make_dev(&tun_cdevsw, minor(dev), 134 UID_UUCP, GID_DIALER, 0600, "tun%d", lminor(dev)); 135 136 MALLOC(sc, struct tun_softc *, sizeof(*sc), M_TUN, M_WAITOK); 137 bzero(sc, sizeof *sc); 138 sc->tun_flags = TUN_INITED; 139 140 ifp = &sc->tun_if; 141 ifp->if_unit = lminor(dev); 142 ifp->if_name = "tun"; 143 ifp->if_mtu = TUNMTU; 144 ifp->if_ioctl = tunifioctl; 145 ifp->if_output = tunoutput; 146 ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 147 ifp->if_snd.ifq_maxlen = ifqmaxlen; 148 ifp->if_softc = sc; 149 if_attach(ifp); 150 bpfattach(ifp, DLT_NULL, sizeof(u_int)); 151 dev->si_drv1 = sc; 152} 153 154/* 155 * tunnel open - must be superuser & the device must be 156 * configured in 157 */ 158static int 159tunopen(dev, flag, mode, p) 160 dev_t dev; 161 int flag, mode; 162 struct proc *p; 163{ 164 struct ifnet *ifp; 165 struct tun_softc *tp; 166 register int error; 167 168 error = suser(p); 169 if (error) 170 return (error); 171 172 tp = dev->si_drv1; 173 if (!tp) { 174 tuncreate(dev); 175 tp = dev->si_drv1; 176 } 177 if (tp->tun_flags & TUN_OPEN) 178 return EBUSY; 179 tp->tun_pid = p->p_pid; 180 ifp = &tp->tun_if; 181 tp->tun_flags |= TUN_OPEN; 182 TUNDEBUG("%s%d: open\n", ifp->if_name, ifp->if_unit); 183 return (0); 184} 185 186/* 187 * tunclose - close the device - mark i/f down & delete 188 * routing info 189 */ 190static int 191tunclose(dev, foo, bar, p) 192 dev_t dev; 193 int foo; 194 int bar; 195 struct proc *p; 196{ 197 register int s; 198 struct tun_softc *tp; 199 struct ifnet *ifp; 200 struct mbuf *m; 201 202 tp = dev->si_drv1; 203 ifp = &tp->tun_if; 204 205 tp->tun_flags &= ~TUN_OPEN; 206 tp->tun_pid = 0; 207 208 /* 209 * junk all pending output 210 */ 211 do { 212 s = splimp(); 213 IF_DEQUEUE(&ifp->if_snd, m); 214 splx(s); 215 if (m) 216 m_freem(m); 217 } while (m); 218 219 if (ifp->if_flags & IFF_UP) { 220 s = splimp(); 221 if_down(ifp); 222 splx(s); 223 } 224 225 if (ifp->if_flags & IFF_RUNNING) { 226 register struct ifaddr *ifa; 227 228 s = splimp(); 229 /* find internet addresses and delete routes */ 230 for (ifa = ifp->if_addrhead.tqh_first; ifa; 231 ifa = ifa->ifa_link.tqe_next) 232 if (ifa->ifa_addr->sa_family == AF_INET) 233 rtinit(ifa, (int)RTM_DELETE, 234 tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0); 235 ifp->if_flags &= ~IFF_RUNNING; 236 splx(s); 237 } 238 239 funsetown(tp->tun_sigio); 240 selwakeup(&tp->tun_rsel); 241 242 TUNDEBUG ("%s%d: closed\n", ifp->if_name, ifp->if_unit); 243 return (0); 244} 245 246static int 247tuninit(ifp) 248 struct ifnet *ifp; 249{ 250 struct tun_softc *tp = ifp->if_softc; 251 register struct ifaddr *ifa; 252 253 TUNDEBUG("%s%d: tuninit\n", ifp->if_name, ifp->if_unit); 254 255 ifp->if_flags |= IFF_UP | IFF_RUNNING; 256 getmicrotime(&ifp->if_lastchange); 257 258 for (ifa = ifp->if_addrhead.tqh_first; ifa; 259 ifa = ifa->ifa_link.tqe_next) { 260#ifdef INET 261 if (ifa->ifa_addr->sa_family == AF_INET) { 262 struct sockaddr_in *si; 263 264 si = (struct sockaddr_in *)ifa->ifa_addr; 265 if (si && si->sin_addr.s_addr) 266 tp->tun_flags |= TUN_IASET; 267 268 si = (struct sockaddr_in *)ifa->ifa_dstaddr; 269 if (si && si->sin_addr.s_addr) 270 tp->tun_flags |= TUN_DSTADDR; 271 } 272#endif 273 } 274 return 0; 275} 276 277/* 278 * Process an ioctl request. 279 */ 280int 281tunifioctl(ifp, cmd, data) 282 struct ifnet *ifp; 283 u_long cmd; 284 caddr_t data; 285{ 286 struct ifreq *ifr = (struct ifreq *)data; 287 struct tun_softc *tp = ifp->if_softc; 288 struct ifstat *ifs; 289 int error = 0, s; 290 291 s = splimp(); 292 switch(cmd) { 293 case SIOCGIFSTATUS: 294 ifs = (struct ifstat *)data; 295 if (tp->tun_pid) 296 sprintf(ifs->ascii + strlen(ifs->ascii), 297 "\tOpened by PID %d\n", tp->tun_pid); 298 return(0); 299 case SIOCSIFADDR: 300 tuninit(ifp); 301 TUNDEBUG("%s%d: address set\n", 302 ifp->if_name, ifp->if_unit); 303 break; 304 case SIOCSIFDSTADDR: 305 tuninit(ifp); 306 TUNDEBUG("%s%d: destination address set\n", 307 ifp->if_name, ifp->if_unit); 308 break; 309 case SIOCSIFMTU: 310 ifp->if_mtu = ifr->ifr_mtu; 311 TUNDEBUG("%s%d: mtu set\n", 312 ifp->if_name, ifp->if_unit); 313 break; 314 case SIOCADDMULTI: 315 case SIOCDELMULTI: 316 break; 317 318 319 default: 320 error = EINVAL; 321 } 322 splx(s); 323 return (error); 324} 325 326/* 327 * tunoutput - queue packets from higher level ready to put out. 328 */ 329int 330tunoutput(ifp, m0, dst, rt) 331 struct ifnet *ifp; 332 struct mbuf *m0; 333 struct sockaddr *dst; 334 struct rtentry *rt; 335{ 336 struct tun_softc *tp = ifp->if_softc; 337 int s; 338 339 TUNDEBUG ("%s%d: tunoutput\n", ifp->if_name, ifp->if_unit); 340 341 if ((tp->tun_flags & TUN_READY) != TUN_READY) { 342 TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name, 343 ifp->if_unit, tp->tun_flags); 344 m_freem (m0); 345 return EHOSTDOWN; 346 } 347 348 /* BPF write needs to be handled specially */ 349 if (dst->sa_family == AF_UNSPEC) { 350 dst->sa_family = *(mtod(m0, int *)); 351 m0->m_len -= sizeof(int); 352 m0->m_pkthdr.len -= sizeof(int); 353 m0->m_data += sizeof(int); 354 } 355 356 if (ifp->if_bpf) { 357 /* 358 * We need to prepend the address family as 359 * a four byte field. Cons up a dummy header 360 * to pacify bpf. This is safe because bpf 361 * will only read from the mbuf (i.e., it won't 362 * try to free it or keep a pointer to it). 363 */ 364 struct mbuf m; 365 u_int af = dst->sa_family; 366 367 m.m_next = m0; 368 m.m_len = 4; 369 m.m_data = (char *)⁡ 370 371 bpf_mtap(ifp, &m); 372 } 373 374 /* prepend sockaddr? this may abort if the mbuf allocation fails */ 375 if (tp->tun_flags & TUN_LMODE) { 376 /* allocate space for sockaddr */ 377 M_PREPEND(m0, dst->sa_len, M_DONTWAIT); 378 379 /* if allocation failed drop packet */ 380 if (m0 == NULL){ 381 s = splimp(); /* spl on queue manipulation */ 382 IF_DROP(&ifp->if_snd); 383 splx(s); 384 ifp->if_oerrors++; 385 return (ENOBUFS); 386 } else { 387 bcopy(dst, m0->m_data, dst->sa_len); 388 } 389 } 390 391 if (tp->tun_flags & TUN_IFHEAD) { 392 /* Prepend the address family */ 393 M_PREPEND(m0, 4, M_DONTWAIT); 394 395 /* if allocation failed drop packet */ 396 if (m0 == NULL){ 397 s = splimp(); /* spl on queue manipulation */ 398 IF_DROP(&ifp->if_snd); 399 splx(s); 400 ifp->if_oerrors++; 401 return ENOBUFS; 402 } else 403 *(u_int32_t *)m0->m_data = htonl(dst->sa_family); 404 } else { 405#ifdef INET 406 if (dst->sa_family != AF_INET) 407#endif 408 { 409 m_freem(m0); 410 return EAFNOSUPPORT; 411 } 412 } 413 414 s = splimp(); 415 if (IF_QFULL(&ifp->if_snd)) { 416 IF_DROP(&ifp->if_snd); 417 m_freem(m0); 418 splx(s); 419 ifp->if_collisions++; 420 return ENOBUFS; 421 } 422 ifp->if_obytes += m0->m_pkthdr.len; 423 IF_ENQUEUE(&ifp->if_snd, m0); 424 splx(s); 425 ifp->if_opackets++; 426 427 if (tp->tun_flags & TUN_RWAIT) { 428 tp->tun_flags &= ~TUN_RWAIT; 429 wakeup((caddr_t)tp); 430 } 431 if (tp->tun_flags & TUN_ASYNC && tp->tun_sigio) 432 pgsigio(tp->tun_sigio, SIGIO, 0); 433 selwakeup(&tp->tun_rsel); 434 return 0; 435} 436 437/* 438 * the cdevsw interface is now pretty minimal. 439 */ 440static int 441tunioctl(dev, cmd, data, flag, p) 442 dev_t dev; 443 u_long cmd; 444 caddr_t data; 445 int flag; 446 struct proc *p; 447{ 448 int s; 449 struct tun_softc *tp = dev->si_drv1; 450 struct tuninfo *tunp; 451 452 switch (cmd) { 453 case TUNSIFINFO: 454 tunp = (struct tuninfo *)data; 455 if (tunp->mtu < IF_MINMTU) 456 return (EINVAL); 457 tp->tun_if.if_mtu = tunp->mtu; 458 tp->tun_if.if_type = tunp->type; 459 tp->tun_if.if_baudrate = tunp->baudrate; 460 break; 461 case TUNGIFINFO: 462 tunp = (struct tuninfo *)data; 463 tunp->mtu = tp->tun_if.if_mtu; 464 tunp->type = tp->tun_if.if_type; 465 tunp->baudrate = tp->tun_if.if_baudrate; 466 break; 467 case TUNSDEBUG: 468 tundebug = *(int *)data; 469 break; 470 case TUNGDEBUG: 471 *(int *)data = tundebug; 472 break; 473 case TUNSLMODE: 474 if (*(int *)data) { 475 tp->tun_flags |= TUN_LMODE; 476 tp->tun_flags &= ~TUN_IFHEAD; 477 } else 478 tp->tun_flags &= ~TUN_LMODE; 479 break; 480 case TUNSIFHEAD: 481 if (*(int *)data) { 482 tp->tun_flags |= TUN_IFHEAD; 483 tp->tun_flags &= ~TUN_LMODE; 484 } else 485 tp->tun_flags &= ~TUN_IFHEAD; 486 break; 487 case TUNGIFHEAD: 488 *(int *)data = (tp->tun_flags & TUN_IFHEAD) ? 1 : 0; 489 break; 490 case TUNSIFMODE: 491 /* deny this if UP */ 492 if (tp->tun_if.if_flags & IFF_UP) 493 return(EBUSY); 494 495 switch (*(int *)data) { 496 case IFF_POINTOPOINT: 497 tp->tun_if.if_flags |= IFF_POINTOPOINT; 498 tp->tun_if.if_flags &= ~IFF_BROADCAST; 499 break; 500 case IFF_BROADCAST: 501 tp->tun_if.if_flags &= ~IFF_POINTOPOINT; 502 tp->tun_if.if_flags |= IFF_BROADCAST; 503 break; 504 default: 505 return(EINVAL); 506 } 507 break; 508 case TUNSIFPID: 509 tp->tun_pid = curproc->p_pid; 510 break; 511 case FIONBIO: 512 break; 513 case FIOASYNC: 514 if (*(int *)data) 515 tp->tun_flags |= TUN_ASYNC; 516 else 517 tp->tun_flags &= ~TUN_ASYNC; 518 break; 519 case FIONREAD: 520 s = splimp(); 521 if (tp->tun_if.if_snd.ifq_head) { 522 struct mbuf *mb = tp->tun_if.if_snd.ifq_head; 523 for( *(int *)data = 0; mb != 0; mb = mb->m_next) 524 *(int *)data += mb->m_len; 525 } else 526 *(int *)data = 0; 527 splx(s); 528 break; 529 case FIOSETOWN: 530 return (fsetown(*(int *)data, &tp->tun_sigio)); 531 532 case FIOGETOWN: 533 *(int *)data = fgetown(tp->tun_sigio); 534 return (0); 535 536 /* This is deprecated, FIOSETOWN should be used instead. */ 537 case TIOCSPGRP: 538 return (fsetown(-(*(int *)data), &tp->tun_sigio)); 539 540 /* This is deprecated, FIOGETOWN should be used instead. */ 541 case TIOCGPGRP: 542 *(int *)data = -fgetown(tp->tun_sigio); 543 return (0); 544 545 default: 546 return (ENOTTY); 547 } 548 return (0); 549} 550 551/* 552 * The cdevsw read interface - reads a packet at a time, or at 553 * least as much of a packet as can be read. 554 */ 555static int 556tunread(dev, uio, flag) 557 dev_t dev; 558 struct uio *uio; 559 int flag; 560{ 561 struct tun_softc *tp = dev->si_drv1; 562 struct ifnet *ifp = &tp->tun_if; 563 struct mbuf *m, *m0; 564 int error=0, len, s; 565 566 TUNDEBUG ("%s%d: read\n", ifp->if_name, ifp->if_unit); 567 if ((tp->tun_flags & TUN_READY) != TUN_READY) { 568 TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name, 569 ifp->if_unit, tp->tun_flags); 570 return EHOSTDOWN; 571 } 572 573 tp->tun_flags &= ~TUN_RWAIT; 574 575 s = splimp(); 576 do { 577 IF_DEQUEUE(&ifp->if_snd, m0); 578 if (m0 == 0) { 579 if (flag & IO_NDELAY) { 580 splx(s); 581 return EWOULDBLOCK; 582 } 583 tp->tun_flags |= TUN_RWAIT; 584 if((error = tsleep((caddr_t)tp, PCATCH | (PZERO + 1), 585 "tunread", 0)) != 0) { 586 splx(s); 587 return error; 588 } 589 } 590 } while (m0 == 0); 591 splx(s); 592 593 while (m0 && uio->uio_resid > 0 && error == 0) { 594 len = min(uio->uio_resid, m0->m_len); 595 if (len == 0) 596 break; 597 error = uiomove(mtod(m0, caddr_t), len, uio); 598 MFREE(m0, m); 599 m0 = m; 600 } 601 602 if (m0) { 603 TUNDEBUG("Dropping mbuf\n"); 604 m_freem(m0); 605 } 606 return error; 607} 608 609/* 610 * the cdevsw write interface - an atomic write is a packet - or else! 611 */ 612static int 613tunwrite(dev, uio, flag) 614 dev_t dev; 615 struct uio *uio; 616 int flag; 617{ 618 struct tun_softc *tp = dev->si_drv1; 619 struct ifnet *ifp = &tp->tun_if; 620 struct mbuf *top, **mp, *m; 621 int error=0, s, tlen, mlen, isr; 622 u_int32_t family; 623 struct ifqueue *q; 624 625 TUNDEBUG("%s%d: tunwrite\n", ifp->if_name, ifp->if_unit); 626 627 if (uio->uio_resid == 0) 628 return 0; 629 630 if (uio->uio_resid < 0 || uio->uio_resid > TUNMRU) { 631 TUNDEBUG("%s%d: len=%d!\n", ifp->if_name, ifp->if_unit, 632 uio->uio_resid); 633 return EIO; 634 } 635 tlen = uio->uio_resid; 636 637 /* get a header mbuf */ 638 MGETHDR(m, M_DONTWAIT, MT_DATA); 639 if (m == NULL) 640 return ENOBUFS; 641 mlen = MHLEN; 642 643 top = 0; 644 mp = ⊤ 645 while (error == 0 && uio->uio_resid > 0) { 646 m->m_len = min(mlen, uio->uio_resid); 647 error = uiomove(mtod (m, caddr_t), m->m_len, uio); 648 *mp = m; 649 mp = &m->m_next; 650 if (uio->uio_resid > 0) { 651 MGET (m, M_DONTWAIT, MT_DATA); 652 if (m == 0) { 653 error = ENOBUFS; 654 break; 655 } 656 mlen = MLEN; 657 } 658 } 659 if (error) { 660 if (top) 661 m_freem (top); 662 return error; 663 } 664 665 top->m_pkthdr.len = tlen; 666 top->m_pkthdr.rcvif = ifp; 667 668 if (ifp->if_bpf) { 669 if (tp->tun_flags & TUN_IFHEAD) 670 /* 671 * Conveniently, we already have a 4-byte address 672 * family prepended to our packet ! 673 */ 674 bpf_mtap(ifp, top); 675 else { 676 /* 677 * We need to prepend the address family as 678 * a four byte field. Cons up a dummy header 679 * to pacify bpf. This is safe because bpf 680 * will only read from the mbuf (i.e., it won't 681 * try to free it or keep a pointer to it). 682 */ 683 struct mbuf m; 684 u_int af = AF_INET; 685 686 m.m_next = top; 687 m.m_len = 4; 688 m.m_data = (char *)⁡ 689 690 bpf_mtap(ifp, &m); 691 } 692 } 693 694 if (tp->tun_flags & TUN_IFHEAD) { 695 if (top->m_len < sizeof(family) && 696 (top = m_pullup(top, sizeof(family))) == NULL) 697 return ENOBUFS; 698 family = ntohl(*mtod(top, u_int32_t *)); 699 m_adj(top, sizeof(family)); 700 } else 701 family = AF_INET; 702 703 switch (family) { 704#ifdef INET 705 case AF_INET: 706 q = &ipintrq; 707 isr = NETISR_IP; 708 break; 709#endif 710#ifdef INET6 711 case AF_INET6: 712 q = &ip6intrq; 713 isr = NETISR_IPV6; 714 break; 715#endif 716#ifdef NS 717 case AF_NS: 718 q = &nsintrq; 719 isr = NETISR_NS; 720 break; 721#endif 722#ifdef IPX 723 case AF_IPX: 724 q = &ipxintrq; 725 isr = NETISR_IPX; 726 break; 727#endif 728#ifdef NETATALK 729 case AF_APPLETALK: 730 q = &atintrq2; 731 isr = NETISR_ATALK; 732 break; 733#endif 734 default: 735 m_freem(top); 736 return EAFNOSUPPORT; 737 } 738 739 s = splimp(); 740 if (IF_QFULL (q)) { 741 IF_DROP(q); 742 splx(s); 743 ifp->if_collisions++; 744 m_freem(top); 745 return ENOBUFS; 746 } 747 IF_ENQUEUE(q, top); 748 splx(s); 749 ifp->if_ibytes += tlen; 750 ifp->if_ipackets++; 751 schednetisr(isr); 752 753 return error; 754} 755 756/* 757 * tunpoll - the poll interface, this is only useful on reads 758 * really. The write detect always returns true, write never blocks 759 * anyway, it either accepts the packet or drops it. 760 */ 761static int 762tunpoll(dev, events, p) 763 dev_t dev; 764 int events; 765 struct proc *p; 766{ 767 int s; 768 struct tun_softc *tp = dev->si_drv1; 769 struct ifnet *ifp = &tp->tun_if; 770 int revents = 0; 771 772 s = splimp(); 773 TUNDEBUG("%s%d: tunpoll\n", ifp->if_name, ifp->if_unit); 774 775 if (events & (POLLIN | POLLRDNORM)) { 776 if (ifp->if_snd.ifq_len > 0) { 777 TUNDEBUG("%s%d: tunpoll q=%d\n", ifp->if_name, 778 ifp->if_unit, ifp->if_snd.ifq_len); 779 revents |= events & (POLLIN | POLLRDNORM); 780 } else { 781 TUNDEBUG("%s%d: tunpoll waiting\n", ifp->if_name, 782 ifp->if_unit); 783 selrecord(p, &tp->tun_rsel); 784 } 785 } 786 if (events & (POLLOUT | POLLWRNORM)) 787 revents |= events & (POLLOUT | POLLWRNORM); 788 789 splx(s); 790 return (revents); 791} 792