]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/if_tun.c
xnu-344.23.tar.gz
[apple/xnu.git] / bsd / net / if_tun.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
de355530
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
1c79356b 11 *
de355530
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
de355530
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/* $NetBSD: if_tun.c,v 1.14 1994/06/29 06:36:25 cgd Exp $ */
23
24/*
25 * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
26 * Nottingham University 1987.
27 *
28 * This source may be freely distributed, however I would be interested
29 * in any changes that are made.
30 *
31 * This driver takes packets off the IP i/f and hands them up to a
32 * user process to have its wicked way with. This driver has it's
33 * roots in a similar driver written by Phil Cockcroft (formerly) at
34 * UCL. This driver is based much more on read/write/poll mode of
35 * operation though.
36 */
37
38#include "tun.h"
39#if NTUN > 0
40
41#include "opt_devfs.h"
42#include "opt_inet.h"
43
44#include <sys/param.h>
45#include <sys/proc.h>
46#include <sys/systm.h>
47#include <sys/mbuf.h>
48#include <sys/socket.h>
49#include <sys/filio.h>
50#include <sys/sockio.h>
51#include <sys/ttycom.h>
52#include <sys/poll.h>
53#include <sys/signalvar.h>
54#include <sys/filedesc.h>
55#include <sys/kernel.h>
56#include <sys/sysctl.h>
57#if DEVFS
58#include <sys/devfsext.h>
59#endif /*DEVFS*/
60#include <sys/conf.h>
61#include <sys/uio.h>
62#include <sys/vnode.h>
63
64#include <net/if.h>
65#include <net/if_types.h>
66#include <net/netisr.h>
67#include <net/route.h>
68
69#if INET
70#include <netinet/in.h>
71#include <netinet/in_var.h>
72#endif
73
74#if INET6
75#include <netinet/ip6.h>
76#include <netinet6/ip6_var.h>
77#include <netinet6/in6_ifattach.h>
78#endif /* INET6 */
79
1c79356b
A
80#include "bpfilter.h"
81#if NBPFILTER > 0
82#include <net/bpf.h>
83#endif
84
85#include <net/if_tunvar.h>
86#include <net/if_tun.h>
87
88static void tunattach __P((void *));
89PSEUDO_SET(tunattach, if_tun);
90
91#define TUNDEBUG if (tundebug) printf
92static int tundebug = 0;
93SYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, "");
94
95static struct tun_softc tunctl[NTUN];
96
97static int tunoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *,
98 struct rtentry *rt));
99static int tunifioctl __P((struct ifnet *, u_long, caddr_t));
100static int tuninit __P((int, int, u_char));
101
102static d_open_t tunopen;
103static d_close_t tunclose;
104static d_read_t tunread;
105static d_write_t tunwrite;
106static d_ioctl_t tunioctl;
107static d_poll_t tunpoll;
108
109#define CDEV_MAJOR 52
110static struct cdevsw tun_cdevsw = {
111 tunopen, tunclose, tunread, tunwrite,
112 tunioctl, nullstop, noreset, nodevtotty,
113 tunpoll, nommap, nostrategy, "tun", NULL, -1
114};
115
116
117static int tun_devsw_installed;
118#if DEVFS
119static void *tun_devfs_token[NTUN];
120#endif
121
122#define minor_val(n) ((((n) & ~0xff) << 8) | ((n) & 0xff))
123#define dev_val(n) (((n) >> 8) | ((n) & 0xff))
124
125static void
126tunattach(dummy)
127 void *dummy;
128{
129 register int i;
130 struct ifnet *ifp;
131 dev_t dev;
132
133 if ( tun_devsw_installed )
134 return;
135 dev = makedev(CDEV_MAJOR, 0);
136 cdevsw_add(&dev, &tun_cdevsw, NULL);
137 tun_devsw_installed = 1;
138 for ( i = 0; i < NTUN; i++ ) {
139#if DEVFS
140 tun_devfs_token[i] = devfs_add_devswf(&tun_cdevsw, minor_val(i),
141 DV_CHR, UID_UUCP,
142 GID_DIALER, 0600,
143 "tun%d", i);
144#endif
145 tunctl[i].tun_flags = TUN_INITED;
146
147 ifp = &tunctl[i].tun_if;
148 ifp->if_unit = i;
149 ifp->if_name = "tun";
150 ifp->if_family = APPLE_IF_FAM_TUN;
151 ifp->if_mtu = TUNMTU;
152 ifp->if_ioctl = tunifioctl;
153 ifp->if_output = tunoutput;
154 ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
155 ifp->if_type = IFT_PPP; /* necessary init value for IPv6 lladdr auto conf */
156 ifp->if_snd.ifq_maxlen = ifqmaxlen;
157 if_attach(ifp);
158#if NBPFILTER > 0
159 bpfattach(ifp, DLT_NULL, sizeof(u_int));
160#endif
161 }
162}
163
164/*
165 * tunnel open - must be superuser & the device must be
166 * configured in
167 */
168static int
169tunopen(dev, flag, mode, p)
170 dev_t dev;
171 int flag, mode;
172 struct proc *p;
173{
174 struct ifnet *ifp;
175 struct tun_softc *tp;
176 register int unit, error;
177
178 error = suser(p->p_ucred, &p->p_acflag);
179 if (error)
180 return (error);
181
182 if ((unit = dev_val(minor(dev))) >= NTUN)
183 return (ENXIO);
184 tp = &tunctl[unit];
185 if (tp->tun_flags & TUN_OPEN)
186 return EBUSY;
187 ifp = &tp->tun_if;
188 tp->tun_flags |= TUN_OPEN;
189 TUNDEBUG("%s%d: open\n", ifp->if_name, ifp->if_unit);
190 return (0);
191}
192
193/*
194 * tunclose - close the device - mark i/f down & delete
195 * routing info
196 */
197static int
198tunclose(dev, foo, bar, p)
199 dev_t dev;
200 int foo;
201 int bar;
202 struct proc *p;
203{
204 register int unit = dev_val(minor(dev)), s;
205 struct tun_softc *tp = &tunctl[unit];
206 struct ifnet *ifp = &tp->tun_if;
207 struct mbuf *m;
208
209 tp->tun_flags &= ~TUN_OPEN;
210
211 /*
212 * junk all pending output
213 */
214 do {
215 s = splimp();
216 IF_DEQUEUE(&ifp->if_snd, m);
217 splx(s);
218 if (m)
219 m_freem(m);
220 } while (m);
221
222 if (ifp->if_flags & IFF_UP) {
223 s = splimp();
224 if_down(ifp);
225 if (ifp->if_flags & IFF_RUNNING) {
226 /* find internet addresses and delete routes */
227 register struct ifaddr *ifa;
228 for (ifa = ifp->if_addrhead.tqh_first; ifa;
229 ifa = ifa->ifa_link.tqe_next) {
230 switch (ifa->ifa_addr->sa_family) {
231#if INET
232 case AF_INET:
233#endif
234#if INET6
235 case AF_INET6:
236#endif
237 rtinit(ifa, (int)RTM_DELETE,
238 tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0);
239 break;
240 }
241 }
242 }
243 splx(s);
244 }
245 ifp->if_flags &= ~IFF_RUNNING;
246 funsetown(tp->tun_sigio);
1c79356b 247 selwakeup(&tp->tun_rsel);
0b4e3aa0 248 selthreadclear(&tp->tun_rsel);
1c79356b
A
249
250 TUNDEBUG ("%s%d: closed\n", ifp->if_name, ifp->if_unit);
251 return (0);
252}
253
254static int
255tuninit(unit, cmd, af)
256 int unit;
257 int cmd;
258 u_char af;
259{
260 struct tun_softc *tp = &tunctl[unit];
261 struct ifnet *ifp = &tp->tun_if;
262 register struct ifaddr *ifa;
263
264 TUNDEBUG("%s%d: tuninit\n", ifp->if_name, ifp->if_unit);
265
266 ifp->if_flags |= IFF_UP | IFF_RUNNING;
267 getmicrotime(&ifp->if_lastchange);
268
269 for (ifa = ifp->if_addrhead.tqh_first; ifa;
270 ifa = ifa->ifa_link.tqe_next) {
271#if INET
272 if (ifa->ifa_addr->sa_family == AF_INET) {
273 struct sockaddr_in *si;
274
275 si = (struct sockaddr_in *)ifa->ifa_addr;
276 if (si && si->sin_addr.s_addr)
277 tp->tun_flags |= TUN_IASET;
278
279 si = (struct sockaddr_in *)ifa->ifa_dstaddr;
280 if (si && si->sin_addr.s_addr)
281 tp->tun_flags |= TUN_DSTADDR;
282 }
283#endif
284 }
285 return 0;
286}
287
288/*
289 * Process an ioctl request.
290 */
291int
292tunifioctl(ifp, cmd, data)
293 struct ifnet *ifp;
294 u_long cmd;
295 caddr_t data;
296{
297 register struct ifreq *ifr = (struct ifreq *)data;
298 int error = 0, s;
299
300 s = splimp();
301 switch(cmd) {
9bccf70c
A
302 case SIOCGIFSTATUS:
303 ifs = (struct ifstat *)data;
304 if (tp->tun_pid)
305 sprintf(ifs->ascii + strlen(ifs->ascii),
306 "\tOpened by PID %d\n", tp->tun_pid);
307 break;
1c79356b
A
308 case SIOCSIFADDR:
309 tuninit(ifp->if_unit);
310 TUNDEBUG("%s%d: address set\n",
311 ifp->if_name, ifp->if_unit);
312 break;
313 case SIOCSIFDSTADDR:
314#if 0
315#if defined(INET6) && defined(__FreeBSD__) && __FreeBSD__ >= 3
316 if (found_first_ifid == 0)
317 in6_ifattach_noifid(ifp);
318#endif /* defined(INET6) && defined(__FreeBSD__) && __FreeBSD__ >= 3 */
319#endif
320 tuninit(ifp->if_unit, cmd, ifr->ifr_addr.sa_family);
321 break;
322 case SIOCSIFMTU:
323 ifp->if_mtu = ifr->ifr_mtu;
324 TUNDEBUG("%s%d: mtu set\n",
325 ifp->if_name, ifp->if_unit);
326 break;
327 case SIOCADDMULTI:
328 case SIOCDELMULTI:
329 break;
330
331 case SIOCSIFFLAGS:
332 if ((ifp->if_flags & IFF_UP) != 0)
333 ifp->if_flags |= IFF_RUNNING;
334 else if ((ifp->if_flags & IFF_UP) == 0)
335 ifp->if_flags &= ~IFF_RUNNING;
336 break;
337
338 default:
339 error = EINVAL;
340 }
341 splx(s);
342 return (error);
343}
344
345/*
346 * tunoutput - queue packets from higher level ready to put out.
347 */
348/* Packet data format between tun and ppp is changed to enable checking of
349 * Address Family of sending packet. When INET6 is defined, 4byte AF field
350 * is appended to packet data as following.
351 *
352 * 0 1 2 3 4 5 6 7 8 .....
353 * ------------------------------
354 * | af | packet data .....
355 * ------------------------------
356 * ^^^^^^^^^^^^^
357 * Newly added part. The size is sizeof(u_long).
358 *
359 * However, this is not adopted for tun -> ppp AF_INET packet for
360 * backword compatibility, because the ppp process may be an existing
361 * ip only supporting one.
362 * Also in ppp->tun case, when af value is unknown, (af > 255) is checked and
363 * if it is true, AF_INET is assumed. (the 4byte may be the head of
364 * AF_INET packet. Despite the byte order, the value must always be
365 * greater than 255, because of ip_len field or (ip_v and ip_hl)
366 * field. (Idea from Mr. Noritoshi Demize)
367 */
368int
369tunoutput(ifp, m0, dst, rt)
370 struct ifnet *ifp;
371 struct mbuf *m0;
372 struct sockaddr *dst;
373 struct rtentry *rt;
374{
375 struct tun_softc *tp = &tunctl[ifp->if_unit];
376 int s;
377
378 TUNDEBUG ("%s%d: tunoutput\n", ifp->if_name, ifp->if_unit);
379
380 if ((tp->tun_flags & TUN_READY) != TUN_READY) {
381 TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name,
382 ifp->if_unit, tp->tun_flags);
383 m_freem (m0);
384 return EHOSTDOWN;
385 }
386
387#if NBPFILTER > 0
388 /* BPF write needs to be handled specially */
389 if (dst->sa_family == AF_UNSPEC) {
390 dst->sa_family = *(mtod(m0, int *));
391 m0->m_len -= sizeof(int);
392 m0->m_pkthdr.len -= sizeof(int);
393 m0->m_data += sizeof(int);
394 }
395
396 if (ifp->if_bpf) {
397 /*
398 * We need to prepend the address family as
399 * a four byte field. Cons up a dummy header
400 * to pacify bpf. This is safe because bpf
401 * will only read from the mbuf (i.e., it won't
402 * try to free it or keep a pointer to it).
403 */
404 struct mbuf m;
405 u_int af = dst->sa_family;
406
407 m.m_next = m0;
408 m.m_len = 4;
409 m.m_data = (char *)&af;
410
411 bpf_mtap(ifp, &m);
412 }
413#endif
414
415 switch(dst->sa_family) {
416#if defined(INET) || defined(INET6)
417#if INET6
418 case AF_INET6:
419 M_PREPEND(m0, sizeof(u_long) /* af field passed to upper */,
420 M_DONTWAIT);
421 if (m0 == 0)
422 return (ENOBUFS);
423 *mtod(m0, u_long *) = (u_long)dst->sa_family;
424 /* FALLTHROUGH */
425#endif /* INET6 */
426#if INET
427 case AF_INET:
428#endif /* INET */
429#endif /* INET || INET6 */
430 s = splimp();
431 if (IF_QFULL(&ifp->if_snd)) {
432 IF_DROP(&ifp->if_snd);
433 m_freem(m0);
434 splx(s);
435 ifp->if_collisions++;
436 return (ENOBUFS);
437 }
438 ifp->if_obytes += m0->m_pkthdr.len;
439 IF_ENQUEUE(&ifp->if_snd, m0);
440 splx(s);
441 ifp->if_opackets++;
442 break;
443 default:
444 m_freem(m0);
445 return EAFNOSUPPORT;
446 }
447
448 if (tp->tun_flags & TUN_RWAIT) {
449 tp->tun_flags &= ~TUN_RWAIT;
450 wakeup((caddr_t)tp);
451 }
452 if (tp->tun_flags & TUN_ASYNC && tp->tun_sigio)
453 pgsigio(tp->tun_sigio, SIGIO, 0);
1c79356b 454 selwakeup(&tp->tun_rsel);
1c79356b
A
455 return 0;
456}
457
458/*
459 * the cdevsw interface is now pretty minimal.
460 */
461static int
462tunioctl(dev, cmd, data, flag, p)
463 dev_t dev;
464 u_long cmd;
465 caddr_t data;
466 int flag;
467 struct proc *p;
468{
469 int unit = dev_val(minor(dev)), s;
470 struct tun_softc *tp = &tunctl[unit];
471 struct tuninfo *tunp;
472
473 switch (cmd) {
474 case TUNSIFINFO:
475 tunp = (struct tuninfo *)data;
476 tp->tun_if.if_mtu = tunp->mtu;
477 tp->tun_if.if_type = tunp->type;
478 tp->tun_if.if_baudrate = tunp->baudrate;
479 break;
480 case TUNGIFINFO:
481 tunp = (struct tuninfo *)data;
482 tunp->mtu = tp->tun_if.if_mtu;
483 tunp->type = tp->tun_if.if_type;
484 tunp->baudrate = tp->tun_if.if_baudrate;
485 break;
486 case TUNSDEBUG:
487 tundebug = *(int *)data;
488 break;
489 case TUNGDEBUG:
490 *(int *)data = tundebug;
491 break;
492 case FIONBIO:
493 break;
494 case FIOASYNC:
495 if (*(int *)data)
496 tp->tun_flags |= TUN_ASYNC;
497 else
498 tp->tun_flags &= ~TUN_ASYNC;
499 break;
500 case FIONREAD:
501 s = splimp();
502 if (tp->tun_if.if_snd.ifq_head) {
503 struct mbuf *mb = tp->tun_if.if_snd.ifq_head;
504 for( *(int *)data = 0; mb != 0; mb = mb->m_next)
505 *(int *)data += mb->m_len;
506 } else
507 *(int *)data = 0;
508 splx(s);
509 break;
510 case FIOSETOWN:
511 return (fsetown(*(int *)data, &tp->tun_sigio));
512
513 case FIOGETOWN:
514 *(int *)data = fgetown(tp->tun_sigio);
515 return (0);
516
517 /* This is deprecated, FIOSETOWN should be used instead. */
518 case TIOCSPGRP:
519 return (fsetown(-(*(int *)data), &tp->tun_sigio));
520
521 /* This is deprecated, FIOGETOWN should be used instead. */
522 case TIOCGPGRP:
523 *(int *)data = -fgetown(tp->tun_sigio);
524 return (0);
525
526 default:
527 return (ENOTTY);
528 }
529 return (0);
530}
531
532/*
533 * The cdevsw read interface - reads a packet at a time, or at
534 * least as much of a packet as can be read.
535 */
536static int
537tunread(dev, uio, flag)
538 dev_t dev;
539 struct uio *uio;
540 int flag;
541{
542 int unit = dev_val(minor(dev));
543 struct tun_softc *tp = &tunctl[unit];
544 struct ifnet *ifp = &tp->tun_if;
545 struct mbuf *m, *m0;
546 int error=0, len, s;
547
548 TUNDEBUG ("%s%d: read\n", ifp->if_name, ifp->if_unit);
549 if ((tp->tun_flags & TUN_READY) != TUN_READY) {
550 TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name,
551 ifp->if_unit, tp->tun_flags);
552 return EHOSTDOWN;
553 }
554
555 tp->tun_flags &= ~TUN_RWAIT;
556
557 s = splimp();
558 do {
559 IF_DEQUEUE(&ifp->if_snd, m0);
560 if (m0 == 0) {
561 if (flag & IO_NDELAY) {
562 splx(s);
563 return EWOULDBLOCK;
564 }
565 tp->tun_flags |= TUN_RWAIT;
566 if( error = tsleep((caddr_t)tp, PCATCH | (PZERO + 1),
567 "tunread", 0)) {
568 splx(s);
569 return error;
570 }
571 }
572 } while (m0 == 0);
573 splx(s);
574
575 while (m0 && uio->uio_resid > 0 && error == 0) {
576 len = min(uio->uio_resid, m0->m_len);
577 if (len == 0)
578 break;
579 error = uiomove(mtod(m0, caddr_t), len, uio);
580 MFREE(m0, m);
581 m0 = m;
582 }
583
584 if (m0) {
585 TUNDEBUG("Dropping mbuf\n");
586 m_freem(m0);
587 }
588 return error;
589}
590
591/*
592 * the cdevsw write interface - an atomic write is a packet - or else!
593 */
594/* See top of tunoutput() about interface change between ppp process and
595 * tun. */
596static int
597tunwrite(dev, uio, flag)
598 dev_t dev;
599 struct uio *uio;
600 int flag;
601{
602 int unit = dev_val(minor(dev));
603 struct ifnet *ifp = &tunctl[unit].tun_if;
604 struct mbuf *top, **mp, *m;
605 int error=0, s, tlen, mlen;
606 u_long af;
607 u_int netisr_af;
608 struct ifqueue *afintrq = NULL;
609
610 TUNDEBUG("%s%d: tunwrite\n", ifp->if_name, ifp->if_unit);
611
612 if (uio->uio_resid < 0 || uio->uio_resid > TUNMRU) {
613 TUNDEBUG("%s%d: len=%d!\n", ifp->if_name, ifp->if_unit,
614 uio->uio_resid);
615 return EIO;
616 }
617 tlen = uio->uio_resid;
618
619 /* get a header mbuf */
620 MGETHDR(m, M_DONTWAIT, MT_DATA);
621 if (m == NULL)
622 return ENOBUFS;
623 if (tlen > MHLEN) {
624 MCLGET(m, M_DONTWAIT);
625 if ((m->m_flags & M_EXT) == 0) {
626 m_free(m);
627 return ENOBUFS;
628 }
629 mlen = m->m_ext.ext_size;
630 } else
631 mlen = MHLEN;
632
633 top = 0;
634 mp = &top;
635 while (error == 0 && uio->uio_resid > 0) {
636 m->m_len = min(mlen, uio->uio_resid);
637 error = uiomove(mtod (m, caddr_t), m->m_len, uio);
638 *mp = m;
639 mp = &m->m_next;
640 if (uio->uio_resid > 0) {
641 MGET (m, M_DONTWAIT, MT_DATA);
642 if (m == 0) {
643 error = ENOBUFS;
644 break;
645 }
646 mlen = MLEN;
647 }
648 }
649 /* Change for checking Address Family of sending packet. */
650 af = *mtod(top, u_long *);
651 switch (af) {
652#if INET
653 case AF_INET:
654 netisr_af = NETISR_IP;
655 afintrq = &ipintrq;
656 break;
657#endif /* INET */
658#if INET6
659 case AF_INET6:
660 netisr_af = NETISR_IPV6;
661 afintrq = &ip6intrq;
662 break;
663#endif /* INET6 */
664 default:
665 if (af > 255) { /* see description at the top of tunoutput */
666 af = AF_INET;
667 netisr_af = NETISR_IP;
668 afintrq = &ipintrq;
669 goto af_decided;
670 }
671 error = EAFNOSUPPORT;
672 break;
673 }
674 m_adj(top, sizeof(u_long)); /* remove af field passed from upper */
675 tlen -= sizeof(u_long);
676 af_decided:
677 if (error) {
678 if (top)
679 m_freem (top);
680 return error;
681 }
682
683 top->m_pkthdr.len = tlen;
684 top->m_pkthdr.rcvif = ifp;
685
686#if NBPFILTER > 0
687 if (ifp->if_bpf) {
688 /*
689 * We need to prepend the address family as
690 * a four byte field. Cons up a dummy header
691 * to pacify bpf. This is safe because bpf
692 * will only read from the mbuf (i.e., it won't
693 * try to free it or keep a pointer to it).
694 */
695 struct mbuf m;
696
697 m.m_next = top;
698 m.m_len = 4;
699 m.m_data = (char *)&af;
700
701 bpf_mtap(ifp, &m);
702 }
703#endif
704
705 /* just for safety */
706 if (!afintrq)
707 return EAFNOSUPPORT;
708
709 s = splimp();
710 if (IF_QFULL (afintrq)) {
711 IF_DROP(afintrq);
712 splx(s);
713 ifp->if_collisions++;
714 m_freem(top);
715 return ENOBUFS;
716 }
717 IF_ENQUEUE(afintrq, top);
718 splx(s);
719 ifp->if_ibytes += tlen;
720 ifp->if_ipackets++;
721 schednetisr(netisr_af);
722 return error;
723}
724
725/*
726 * tunpoll - the poll interface, this is only useful on reads
727 * really. The write detect always returns true, write never blocks
728 * anyway, it either accepts the packet or drops it.
729 */
730static int
0b4e3aa0 731tunpoll(dev, events, wql, p)
1c79356b
A
732 dev_t dev;
733 int events;
0b4e3aa0 734 void * wql;
1c79356b
A
735 struct proc *p;
736{
737 int unit = dev_val(minor(dev)), s;
738 struct tun_softc *tp = &tunctl[unit];
739 struct ifnet *ifp = &tp->tun_if;
740 int revents = 0;
741
742 s = splimp();
743 TUNDEBUG("%s%d: tunpoll\n", ifp->if_name, ifp->if_unit);
744
745 if (events & (POLLIN | POLLRDNORM))
746 if (ifp->if_snd.ifq_len > 0) {
747 TUNDEBUG("%s%d: tunpoll q=%d\n", ifp->if_name,
748 ifp->if_unit, ifp->if_snd.ifq_len);
749 revents |= events & (POLLIN | POLLRDNORM);
750 } else {
751 TUNDEBUG("%s%d: tunpoll waiting\n", ifp->if_name,
752 ifp->if_unit);
0b4e3aa0 753 selrecord(p, &tp->tun_rsel, wql);
1c79356b
A
754 }
755
756 if (events & (POLLOUT | POLLWRNORM))
757 revents |= events & (POLLOUT | POLLWRNORM);
758
759 splx(s);
760 return (revents);
761}
762
763
764#endif /* NTUN */