if_tun.c revision 71946
1214152Sed/* $NetBSD: if_tun.c,v 1.14 1994/06/29 06:36:25 cgd Exp $ */ 2214152Sed 3214152Sed/* 4214152Sed * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> 5222656Sed * Nottingham University 1987. 6222656Sed * 7214152Sed * This source may be freely distributed, however I would be interested 8214152Sed * in any changes that are made. 9214152Sed * 10214152Sed * This driver takes packets off the IP i/f and hands them up to a 11214152Sed * user process to have its wicked way with. This driver has it's 12214152Sed * roots in a similar driver written by Phil Cockcroft (formerly) at 13214152Sed * UCL. This driver is based much more on read/write/poll mode of 14214152Sed * operation though. 15214152Sed * 16214152Sed * $FreeBSD: head/sys/net/if_tun.c 71946 2001-02-03 00:31:39Z brian $ 17214152Sed */ 18214152Sed 19229135Sed#include "opt_inet.h" 20214152Sed 21214152Sed#include <sys/param.h> 22229135Sed#include <sys/proc.h> 23229135Sed#include <sys/systm.h> 24229135Sed#include <sys/mbuf.h> 25214152Sed#include <sys/module.h> 26#include <sys/socket.h> 27#include <sys/filio.h> 28#include <sys/sockio.h> 29#include <sys/ttycom.h> 30#include <sys/poll.h> 31#include <sys/signalvar.h> 32#include <sys/filedesc.h> 33#include <sys/kernel.h> 34#include <sys/sysctl.h> 35#include <sys/conf.h> 36#include <sys/uio.h> 37#include <sys/vnode.h> 38#include <sys/malloc.h> 39 40#include <net/if.h> 41#include <net/if_types.h> 42#include <net/route.h> 43#include <net/intrq.h> 44 45#ifdef INET 46#include <netinet/in.h> 47#endif 48 49#include <net/bpf.h> 50 51#include <net/if_tunvar.h> 52#include <net/if_tun.h> 53 54static MALLOC_DEFINE(M_TUN, "tun", "Tunnel Interface"); 55 56static void tuncreate __P((dev_t dev)); 57 58#define TUNDEBUG if (tundebug) printf 59static int tundebug = 0; 60SYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, ""); 61 62static int tunoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *, 63 struct rtentry *rt)); 64static int tunifioctl __P((struct ifnet *, u_long, caddr_t)); 65static int tuninit __P((struct ifnet *)); 66static void tunstart __P((struct ifnet *)); 67 68static d_open_t tunopen; 69static d_close_t tunclose; 70static d_read_t tunread; 71static d_write_t tunwrite; 72static d_ioctl_t tunioctl; 73static d_poll_t tunpoll; 74 75#define CDEV_MAJOR 52 76static struct cdevsw tun_cdevsw = { 77 /* open */ tunopen, 78 /* close */ tunclose, 79 /* read */ tunread, 80 /* write */ tunwrite, 81 /* ioctl */ tunioctl, 82 /* poll */ tunpoll, 83 /* mmap */ nommap, 84 /* strategy */ nostrategy, 85 /* name */ "tun", 86 /* maj */ CDEV_MAJOR, 87 /* dump */ nodump, 88 /* psize */ nopsize, 89 /* flags */ 0, 90 /* bmaj */ -1 91}; 92 93static void tun_clone __P((void *arg, char *name, int namelen, dev_t *dev)); 94 95static void 96tun_clone(arg, name, namelen, dev) 97 void *arg; 98 char *name; 99 int namelen; 100 dev_t *dev; 101{ 102 int u; 103 104 if (*dev != NODEV) 105 return; 106 if (dev_stdclone(name, NULL, "tun", &u) != 1) 107 return; 108 *dev = make_dev(&tun_cdevsw, unit2minor(u), 109 UID_ROOT, GID_WHEEL, 0600, "tun%d", u); 110 111} 112 113static int 114tun_modevent(module_t mod, int type, void *data) 115{ 116 switch (type) { 117 case MOD_LOAD: 118 EVENTHANDLER_REGISTER(dev_clone, tun_clone, 0, 1000); 119 cdevsw_add(&tun_cdevsw); 120 break; 121 case MOD_UNLOAD: 122 printf("if_tun module unload - not possible for this module type\n"); 123 return EINVAL; 124 } 125 return 0; 126} 127 128static moduledata_t tun_mod = { 129 "if_tun", 130 tun_modevent, 131 0 132}; 133 134DECLARE_MODULE(if_tun, tun_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 135 136static void 137tunstart(ifp) 138 struct ifnet *ifp; 139{ 140 struct tun_softc *tp = ifp->if_softc; 141 142 if (tp->tun_flags & TUN_RWAIT) { 143 tp->tun_flags &= ~TUN_RWAIT; 144 wakeup((caddr_t)tp); 145 } 146 if (tp->tun_flags & TUN_ASYNC && tp->tun_sigio) 147 pgsigio(tp->tun_sigio, SIGIO, 0); 148 selwakeup(&tp->tun_rsel); 149} 150 151static void 152tuncreate(dev) 153 dev_t dev; 154{ 155 struct tun_softc *sc; 156 struct ifnet *ifp; 157 158 dev = make_dev(&tun_cdevsw, minor(dev), 159 UID_UUCP, GID_DIALER, 0600, "tun%d", dev2unit(dev)); 160 161 MALLOC(sc, struct tun_softc *, sizeof(*sc), M_TUN, M_WAITOK | M_ZERO); 162 sc->tun_flags = TUN_INITED; 163 164 ifp = &sc->tun_if; 165 ifp->if_unit = dev2unit(dev); 166 ifp->if_name = "tun"; 167 ifp->if_mtu = TUNMTU; 168 ifp->if_ioctl = tunifioctl; 169 ifp->if_output = tunoutput; 170 ifp->if_start = tunstart; 171 ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 172 ifp->if_type = IFT_PPP; 173 ifp->if_snd.ifq_maxlen = ifqmaxlen; 174 ifp->if_softc = sc; 175 if_attach(ifp); 176 bpfattach(ifp, DLT_NULL, sizeof(u_int)); 177 dev->si_drv1 = sc; 178} 179 180/* 181 * tunnel open - must be superuser & the device must be 182 * configured in 183 */ 184static int 185tunopen(dev, flag, mode, p) 186 dev_t dev; 187 int flag, mode; 188 struct proc *p; 189{ 190 struct ifnet *ifp; 191 struct tun_softc *tp; 192 193 tp = dev->si_drv1; 194 if (!tp) { 195 tuncreate(dev); 196 tp = dev->si_drv1; 197 } 198 if (tp->tun_flags & TUN_OPEN) 199 return EBUSY; 200 tp->tun_pid = p->p_pid; 201 ifp = &tp->tun_if; 202 tp->tun_flags |= TUN_OPEN; 203 TUNDEBUG("%s%d: open\n", ifp->if_name, ifp->if_unit); 204 return (0); 205} 206 207/* 208 * tunclose - close the device - mark i/f down & delete 209 * routing info 210 */ 211static int 212tunclose(dev, foo, bar, p) 213 dev_t dev; 214 int foo; 215 int bar; 216 struct proc *p; 217{ 218 register int s; 219 struct tun_softc *tp; 220 struct ifnet *ifp; 221 222 tp = dev->si_drv1; 223 ifp = &tp->tun_if; 224 225 tp->tun_flags &= ~TUN_OPEN; 226 tp->tun_pid = 0; 227 228 /* 229 * junk all pending output 230 */ 231 IF_DRAIN(&ifp->if_snd); 232 233 if (ifp->if_flags & IFF_UP) { 234 s = splimp(); 235 if_down(ifp); 236 splx(s); 237 } 238 239 if (ifp->if_flags & IFF_RUNNING) { 240 register struct ifaddr *ifa; 241 242 s = splimp(); 243 /* find internet addresses and delete routes */ 244 for (ifa = ifp->if_addrhead.tqh_first; ifa; 245 ifa = ifa->ifa_link.tqe_next) 246 if (ifa->ifa_addr->sa_family == AF_INET) 247 rtinit(ifa, (int)RTM_DELETE, 248 tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0); 249 ifp->if_flags &= ~IFF_RUNNING; 250 splx(s); 251 } 252 253 funsetown(tp->tun_sigio); 254 selwakeup(&tp->tun_rsel); 255 256 TUNDEBUG ("%s%d: closed\n", ifp->if_name, ifp->if_unit); 257 return (0); 258} 259 260static int 261tuninit(ifp) 262 struct ifnet *ifp; 263{ 264 struct tun_softc *tp = ifp->if_softc; 265 register struct ifaddr *ifa; 266 int error = 0; 267 268 TUNDEBUG("%s%d: tuninit\n", ifp->if_name, ifp->if_unit); 269 270 ifp->if_flags |= IFF_UP | IFF_RUNNING; 271 getmicrotime(&ifp->if_lastchange); 272 273 for (ifa = ifp->if_addrhead.tqh_first; ifa; 274 ifa = ifa->ifa_link.tqe_next) { 275 if (ifa->ifa_addr == NULL) 276 error = EFAULT; 277 /* XXX: Should maybe return straight off? */ 278 else { 279#ifdef INET 280 if (ifa->ifa_addr->sa_family == AF_INET) { 281 struct sockaddr_in *si; 282 283 si = (struct sockaddr_in *)ifa->ifa_addr; 284 if (si->sin_addr.s_addr) 285 tp->tun_flags |= TUN_IASET; 286 287 si = (struct sockaddr_in *)ifa->ifa_dstaddr; 288 if (si && si->sin_addr.s_addr) 289 tp->tun_flags |= TUN_DSTADDR; 290 } 291#endif 292 } 293 } 294 return (error); 295} 296 297/* 298 * Process an ioctl request. 299 */ 300int 301tunifioctl(ifp, cmd, data) 302 struct ifnet *ifp; 303 u_long cmd; 304 caddr_t data; 305{ 306 struct ifreq *ifr = (struct ifreq *)data; 307 struct tun_softc *tp = ifp->if_softc; 308 struct ifstat *ifs; 309 int error = 0, s; 310 311 s = splimp(); 312 switch(cmd) { 313 case SIOCGIFSTATUS: 314 ifs = (struct ifstat *)data; 315 if (tp->tun_pid) 316 sprintf(ifs->ascii + strlen(ifs->ascii), 317 "\tOpened by PID %d\n", tp->tun_pid); 318 break; 319 case SIOCSIFADDR: 320 error = tuninit(ifp); 321 TUNDEBUG("%s%d: address set, error=%d\n", 322 ifp->if_name, ifp->if_unit, error); 323 break; 324 case SIOCSIFDSTADDR: 325 error = tuninit(ifp); 326 TUNDEBUG("%s%d: destination address set, error=%d\n", 327 ifp->if_name, ifp->if_unit, error); 328 break; 329 case SIOCSIFMTU: 330 ifp->if_mtu = ifr->ifr_mtu; 331 TUNDEBUG("%s%d: mtu set\n", ifp->if_name, ifp->if_unit); 332 break; 333 case SIOCADDMULTI: 334 case SIOCDELMULTI: 335 break; 336 default: 337 error = EINVAL; 338 } 339 splx(s); 340 return (error); 341} 342 343/* 344 * tunoutput - queue packets from higher level ready to put out. 345 */ 346int 347tunoutput(ifp, m0, dst, rt) 348 struct ifnet *ifp; 349 struct mbuf *m0; 350 struct sockaddr *dst; 351 struct rtentry *rt; 352{ 353 struct tun_softc *tp = ifp->if_softc; 354 355 TUNDEBUG ("%s%d: tunoutput\n", ifp->if_name, ifp->if_unit); 356 357 if ((tp->tun_flags & TUN_READY) != TUN_READY) { 358 TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name, 359 ifp->if_unit, tp->tun_flags); 360 m_freem (m0); 361 return EHOSTDOWN; 362 } 363 364 /* BPF write needs to be handled specially */ 365 if (dst->sa_family == AF_UNSPEC) { 366 dst->sa_family = *(mtod(m0, int *)); 367 m0->m_len -= sizeof(int); 368 m0->m_pkthdr.len -= sizeof(int); 369 m0->m_data += sizeof(int); 370 } 371 372 if (ifp->if_bpf) { 373 /* 374 * We need to prepend the address family as 375 * a four byte field. Cons up a dummy header 376 * to pacify bpf. This is safe because bpf 377 * will only read from the mbuf (i.e., it won't 378 * try to free it or keep a pointer to it). 379 */ 380 struct mbuf m; 381 uint32_t af = dst->sa_family; 382 383 m.m_next = m0; 384 m.m_len = 4; 385 m.m_data = (char *)⁡ 386 387 bpf_mtap(ifp, &m); 388 } 389 390 /* prepend sockaddr? this may abort if the mbuf allocation fails */ 391 if (tp->tun_flags & TUN_LMODE) { 392 /* allocate space for sockaddr */ 393 M_PREPEND(m0, dst->sa_len, M_DONTWAIT); 394 395 /* if allocation failed drop packet */ 396 if (m0 == NULL) { 397 ifp->if_iqdrops++; 398 ifp->if_oerrors++; 399 return (ENOBUFS); 400 } else { 401 bcopy(dst, m0->m_data, dst->sa_len); 402 } 403 } 404 405 if (tp->tun_flags & TUN_IFHEAD) { 406 /* Prepend the address family */ 407 M_PREPEND(m0, 4, M_DONTWAIT); 408 409 /* if allocation failed drop packet */ 410 if (m0 == NULL) { 411 ifp->if_iqdrops++; 412 ifp->if_oerrors++; 413 return ENOBUFS; 414 } else 415 *(u_int32_t *)m0->m_data = htonl(dst->sa_family); 416 } else { 417#ifdef INET 418 if (dst->sa_family != AF_INET) 419#endif 420 { 421 m_freem(m0); 422 return EAFNOSUPPORT; 423 } 424 } 425 426 if (! IF_HANDOFF(&ifp->if_snd, m0, ifp)) { 427 ifp->if_collisions++; 428 return ENOBUFS; 429 } 430 ifp->if_opackets++; 431 return 0; 432} 433 434/* 435 * the cdevsw interface is now pretty minimal. 436 */ 437static int 438tunioctl(dev, cmd, data, flag, p) 439 dev_t dev; 440 u_long cmd; 441 caddr_t data; 442 int flag; 443 struct proc *p; 444{ 445 int s; 446 int error; 447 struct tun_softc *tp = dev->si_drv1; 448 struct tuninfo *tunp; 449 450 switch (cmd) { 451 case TUNSIFINFO: 452 tunp = (struct tuninfo *)data; 453 if (tunp->mtu < IF_MINMTU) 454 return (EINVAL); 455 if (tp->tun_if.if_mtu != tunp->mtu && (error = suser(p)) != 0) 456 return (error); 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, tlen, mlen; 622 uint32_t family; 623 624 TUNDEBUG("%s%d: tunwrite\n", ifp->if_name, ifp->if_unit); 625 626 if (uio->uio_resid == 0) 627 return 0; 628 629 if (uio->uio_resid < 0 || uio->uio_resid > TUNMRU) { 630 TUNDEBUG("%s%d: len=%d!\n", ifp->if_name, ifp->if_unit, 631 uio->uio_resid); 632 return EIO; 633 } 634 tlen = uio->uio_resid; 635 636 /* get a header mbuf */ 637 MGETHDR(m, M_DONTWAIT, MT_DATA); 638 if (m == NULL) 639 return ENOBUFS; 640 mlen = MHLEN; 641 642 top = 0; 643 mp = ⊤ 644 while (error == 0 && uio->uio_resid > 0) { 645 m->m_len = min(mlen, uio->uio_resid); 646 error = uiomove(mtod (m, caddr_t), m->m_len, uio); 647 *mp = m; 648 mp = &m->m_next; 649 if (uio->uio_resid > 0) { 650 MGET (m, M_DONTWAIT, MT_DATA); 651 if (m == 0) { 652 error = ENOBUFS; 653 break; 654 } 655 mlen = MLEN; 656 } 657 } 658 if (error) { 659 if (top) 660 m_freem (top); 661 ifp->if_ierrors++; 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 * Inconveniently, it's in the wrong byte order ! 674 */ 675 if ((top = m_pullup(top, sizeof(family))) == NULL) 676 return ENOBUFS; 677 *mtod(top, u_int32_t *) = 678 ntohl(*mtod(top, u_int32_t *)); 679 bpf_mtap(ifp, top); 680 *mtod(top, u_int32_t *) = 681 htonl(*mtod(top, u_int32_t *)); 682 } else { 683 /* 684 * We need to prepend the address family as 685 * a four byte field. Cons up a dummy header 686 * to pacify bpf. This is safe because bpf 687 * will only read from the mbuf (i.e., it won't 688 * try to free it or keep a pointer to it). 689 */ 690 struct mbuf m; 691 uint32_t af = AF_INET; 692 693 m.m_next = top; 694 m.m_len = 4; 695 m.m_data = (char *)⁡ 696 697 bpf_mtap(ifp, &m); 698 } 699 } 700 701 if (tp->tun_flags & TUN_IFHEAD) { 702 if (top->m_len < sizeof(family) && 703 (top = m_pullup(top, sizeof(family))) == NULL) 704 return ENOBUFS; 705 family = ntohl(*mtod(top, u_int32_t *)); 706 m_adj(top, sizeof(family)); 707 } else 708 family = AF_INET; 709 710 ifp->if_ibytes += top->m_pkthdr.len; 711 ifp->if_ipackets++; 712 713 return family_enqueue(family, top); 714} 715 716/* 717 * tunpoll - the poll interface, this is only useful on reads 718 * really. The write detect always returns true, write never blocks 719 * anyway, it either accepts the packet or drops it. 720 */ 721static int 722tunpoll(dev, events, p) 723 dev_t dev; 724 int events; 725 struct proc *p; 726{ 727 int s; 728 struct tun_softc *tp = dev->si_drv1; 729 struct ifnet *ifp = &tp->tun_if; 730 int revents = 0; 731 732 s = splimp(); 733 TUNDEBUG("%s%d: tunpoll\n", ifp->if_name, ifp->if_unit); 734 735 if (events & (POLLIN | POLLRDNORM)) { 736 if (ifp->if_snd.ifq_len > 0) { 737 TUNDEBUG("%s%d: tunpoll q=%d\n", ifp->if_name, 738 ifp->if_unit, ifp->if_snd.ifq_len); 739 revents |= events & (POLLIN | POLLRDNORM); 740 } else { 741 TUNDEBUG("%s%d: tunpoll waiting\n", ifp->if_name, 742 ifp->if_unit); 743 selrecord(p, &tp->tun_rsel); 744 } 745 } 746 if (events & (POLLOUT | POLLWRNORM)) 747 revents |= events & (POLLOUT | POLLWRNORM); 748 749 splx(s); 750 return (revents); 751} 752