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