Index: if_tun.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_tun.c,v
retrieving revision 1.157
retrieving revision 1.158
diff -u -r1.157 -r1.158
--- if_tun.c	29 Jun 2006 19:22:04 -0000	1.157
+++ if_tun.c	8 Aug 2006 19:22:25 -0000	1.158
@@ -123,6 +123,25 @@
 static d_write_t	tunwrite;
 static d_ioctl_t	tunioctl;
 static d_poll_t		tunpoll;
+static d_kqfilter_t	tunkqfilter;
+
+static int		tunkqread(struct knote *, long);
+static int		tunkqwrite(struct knote *, long);
+static void		tunkqdetach(struct knote *);
+
+static struct filterops tun_read_filterops = {
+	.f_isfd =	1,
+	.f_attach =	NULL,
+	.f_detach =	tunkqdetach,
+	.f_event =	tunkqread,
+};
+
+static struct filterops tun_write_filterops = {
+	.f_isfd =	1,
+	.f_attach =	NULL,
+	.f_detach =	tunkqdetach,
+	.f_event =	tunkqwrite,
+};
 
 static struct cdevsw tun_cdevsw = {
 	.d_version =	D_VERSION,
@@ -133,6 +152,7 @@
 	.d_write =	tunwrite,
 	.d_ioctl =	tunioctl,
 	.d_poll =	tunpoll,
+	.d_kqfilter =	tunkqfilter,
 	.d_name =	TUNNAME,
 };
 
@@ -179,6 +199,7 @@
 	if_detach(TUN2IFP(tp));
 	if_free(TUN2IFP(tp));
 	destroy_dev(dev);
+	knlist_destroy(&tp->tun_rsel.si_note);
 	mtx_destroy(&tp->tun_mtx);
 	free(tp, M_TUN);
 }
@@ -231,6 +252,7 @@
 	struct tun_softc *tp = ifp->if_softc;
 	struct mbuf *m;
 
+	TUNDEBUG(ifp,"%s starting\n", ifp->if_xname);
 	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
 		IFQ_LOCK(&ifp->if_snd);
 		IFQ_POLL_NOLOCK(&ifp->if_snd, m);
@@ -252,6 +274,7 @@
 	} else
 		mtx_unlock(&tp->tun_mtx);
 	selwakeuppri(&tp->tun_rsel, PZERO + 1);
+	KNOTE_UNLOCKED(&tp->tun_rsel.si_note, 0);
 }
 
 /* XXX: should return an error code so it can fail. */
@@ -285,10 +308,13 @@
 	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
 	ifp->if_snd.ifq_drv_maxlen = 0;
 	IFQ_SET_READY(&ifp->if_snd);
+	knlist_init(&sc->tun_rsel.si_note, NULL, NULL, NULL, NULL);
 
 	if_attach(ifp);
 	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
 	dev->si_drv1 = sc;
+	TUNDEBUG(ifp, "interface %s is created, minor = %#x\n",
+	    ifp->if_xname, minor(dev));
 }
 
 static int
@@ -376,6 +402,7 @@
 
 	funsetown(&tp->tun_sigio);
 	selwakeuppri(&tp->tun_rsel, PZERO + 1);
+	KNOTE_UNLOCKED(&tp->tun_rsel.si_note, 0);
 	TUNDEBUG (ifp, "closed\n");
 	return (0);
 }
@@ -712,7 +739,7 @@
 			mtx_lock(&tp->tun_mtx);
 			tp->tun_flags |= TUN_RWAIT;
 			mtx_unlock(&tp->tun_mtx);
-			if((error = tsleep(tp, PCATCH | (PZERO + 1),
+			if ((error = tsleep(tp, PCATCH | (PZERO + 1),
 					"tunread", 0)) != 0) {
 				splx(s);
 				return (error);
@@ -857,3 +884,94 @@
 	splx(s);
 	return (revents);
 }
+
+/*
+ * tunkqfilter - support for the kevent() system call.
+ */
+static int
+tunkqfilter(struct cdev *dev, struct knote *kn)
+{
+	int			s;
+	struct tun_softc	*tp = dev->si_drv1;
+	struct ifnet	*ifp = TUN2IFP(tp);
+
+	s = splimp();
+	switch(kn->kn_filter) {
+	case EVFILT_READ:
+		TUNDEBUG(ifp, "%s kqfilter: EVFILT_READ, minor = %#x\n",
+		    ifp->if_xname, minor(dev));
+		kn->kn_fop = &tun_read_filterops;
+		break;
+
+	case EVFILT_WRITE:
+		TUNDEBUG(ifp, "%s kqfilter: EVFILT_WRITE, minor = %#x\n",
+		    ifp->if_xname, minor(dev));
+		kn->kn_fop = &tun_write_filterops;
+		break;
+	
+	default:
+		TUNDEBUG(ifp, "%s kqfilter: invalid filter, minor = %#x\n",
+		    ifp->if_xname, minor(dev));
+		splx(s);
+		return(EINVAL);
+	}
+	splx(s);
+
+	kn->kn_hook = (caddr_t) dev;
+	knlist_add(&tp->tun_rsel.si_note, kn, 0);
+
+	return (0);
+}
+
+/*
+ * Return true of there is data in the interface queue.
+ */
+static int
+tunkqread(struct knote *kn, long hint)
+{
+	int			ret, s;
+	struct cdev		*dev = (struct cdev *)(kn->kn_hook);
+	struct tun_softc	*tp = dev->si_drv1;
+	struct ifnet	*ifp = TUN2IFP(tp);
+
+	s = splimp();
+	if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) {
+		TUNDEBUG(ifp,
+		    "%s have data in the queue.  Len = %d, minor = %#x\n",
+		    ifp->if_xname, ifp->if_snd.ifq_len, minor(dev));
+		ret = 1;
+	} else {
+		TUNDEBUG(ifp,
+		    "%s waiting for data, minor = %#x\n", ifp->if_xname,
+		    minor(dev));
+		ret = 0;
+	}
+	splx(s);
+
+	return (ret);
+}
+
+/*
+ * Always can write, always return MTU in kn->data.
+ */
+static int
+tunkqwrite(struct knote *kn, long hint)
+{
+	int			s;
+	struct tun_softc	*tp = ((struct cdev *)kn->kn_hook)->si_drv1;
+	struct ifnet	*ifp = TUN2IFP(tp);
+
+	s = splimp();
+	kn->kn_data = ifp->if_mtu;
+	splx(s);
+
+	return (1);
+}
+
+static void
+tunkqdetach(struct knote *kn)
+{
+	struct tun_softc	*tp = ((struct cdev *)kn->kn_hook)->si_drv1;
+
+	knlist_remove(&tp->tun_rsel.si_note, kn, 0);
+}
