summaryrefslogtreecommitdiffstats
path: root/sys/net/if_tun.c
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2006-08-08 19:22:25 +0000
committerrwatson <rwatson@FreeBSD.org>2006-08-08 19:22:25 +0000
commitb9cf2acb162dcbb5f906cf7a22b4bfcbdf222de1 (patch)
tree2c671d1ca93333e2c8c4c67476c8a1aea45b6756 /sys/net/if_tun.c
parent5f3cfb10281a4a5f945178813e656149f8feeef0 (diff)
downloadFreeBSD-src-b9cf2acb162dcbb5f906cf7a22b4bfcbdf222de1.zip
FreeBSD-src-b9cf2acb162dcbb5f906cf7a22b4bfcbdf222de1.tar.gz
Add kqueue support to if_tun. Loosely based on if_tap changes.
Two almost identical patches based on the if_tap work were submitted via GNATS; I started out with the patch in 100796 from David Gilbert, but could have easily started with the patch from Vilmos Nebehaj which I found only later. MFC after: 1 week PR: 93976, 100796
Diffstat (limited to 'sys/net/if_tun.c')
-rw-r--r--sys/net/if_tun.c120
1 files changed, 119 insertions, 1 deletions
diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c
index b0d0e42..ddf6412 100644
--- a/sys/net/if_tun.c
+++ b/sys/net/if_tun.c
@@ -123,6 +123,25 @@ static d_read_t tunread;
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 @@ static struct cdevsw tun_cdevsw = {
.d_write = tunwrite,
.d_ioctl = tunioctl,
.d_poll = tunpoll,
+ .d_kqfilter = tunkqfilter,
.d_name = TUNNAME,
};
@@ -179,6 +199,7 @@ tun_destroy(struct tun_softc *tp)
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 @@ tunstart(struct ifnet *ifp)
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 @@ tunstart(struct ifnet *ifp)
} 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 @@ tuncreate(struct cdev *dev)
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 @@ tunclose(struct cdev *dev, int foo, int bar, struct thread *td)
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 @@ tunread(struct cdev *dev, struct uio *uio, int flag)
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 @@ tunpoll(struct cdev *dev, int events, struct thread *td)
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);
+}
OpenPOWER on IntegriCloud