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