From 916ce663d77987cd78862e28e097abdfc7273adc Mon Sep 17 00:00:00 2001 From: emax Date: Thu, 16 Mar 2006 18:22:01 +0000 Subject: Add kqueue(2) support on if_tap(4) interfaces. While I'm here, replace K&R style function declarations with ANSI style. Also fix endian bugs accessing ioctl arguments that are passed by value. PR: kern/93897 Submitted by: Vilmos Nebehaj < vili at huwico dot hu > MFC after: 1 week --- sys/net/if_tap.c | 213 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 153 insertions(+), 60 deletions(-) (limited to 'sys/net') diff --git a/sys/net/if_tap.c b/sys/net/if_tap.c index 66c4a92..62b7241 100644 --- a/sys/net/if_tap.c +++ b/sys/net/if_tap.c @@ -98,6 +98,26 @@ static d_read_t tapread; static d_write_t tapwrite; static d_ioctl_t tapioctl; static d_poll_t tappoll; +static d_kqfilter_t tapkqfilter; + +/* kqueue(2) */ +static int tapkqread(struct knote *, long); +static int tapkqwrite(struct knote *, long); +static void tapkqdetach(struct knote *); + +static struct filterops tap_read_filterops = { + .f_isfd = 1, + .f_attach = NULL, + .f_detach = tapkqdetach, + .f_event = tapkqread, +}; + +static struct filterops tap_write_filterops = { + .f_isfd = 1, + .f_attach = NULL, + .f_detach = tapkqdetach, + .f_event = tapkqwrite, +}; static struct cdevsw tap_cdevsw = { .d_version = D_VERSION, @@ -109,6 +129,7 @@ static struct cdevsw tap_cdevsw = { .d_ioctl = tapioctl, .d_poll = tappoll, .d_name = CDEV_NAME, + .d_kqfilter = tapkqfilter, }; /* @@ -141,10 +162,7 @@ DEV_MODULE(if_tap, tapmodevent, NULL); * module event handler */ static int -tapmodevent(mod, type, data) - module_t mod; - int type; - void *data; +tapmodevent(module_t mod, int type, void *data) { static eventhandler_tag eh_tag = NULL; struct tap_softc *tp = NULL; @@ -232,12 +250,7 @@ tapmodevent(mod, type, data) * We need to support two kind of devices - tap and vmnet */ static void -tapclone(arg, cred, name, namelen, dev) - void *arg; - struct ucred *cred; - char *name; - int namelen; - struct cdev **dev; +tapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev) { u_int extra; int i, unit; @@ -280,8 +293,7 @@ tapclone(arg, cred, name, namelen, dev) * to create interface */ static void -tapcreate(dev) - struct cdev *dev; +tapcreate(struct cdev *dev) { struct ifnet *ifp = NULL; struct tap_softc *tp = NULL; @@ -353,11 +365,7 @@ tapcreate(dev) * to open tunnel. must be superuser */ static int -tapopen(dev, flag, mode, td) - struct cdev *dev; - int flag; - int mode; - struct thread *td; +tapopen(struct cdev *dev, int flag, int mode, struct thread *td) { struct tap_softc *tp = NULL; struct ifnet *ifp = NULL; @@ -397,6 +405,8 @@ tapopen(dev, flag, mode, td) ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; splx(s); + knlist_init(&tp->tap_rsel.si_note, NULL, NULL, NULL, NULL); + TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev)); return (0); @@ -409,13 +419,9 @@ tapopen(dev, flag, mode, td) * close the device - mark i/f down & delete routing info */ static int -tapclose(dev, foo, bar, td) - struct cdev *dev; - int foo; - int bar; - struct thread *td; +tapclose(struct cdev *dev, int foo, int bar, struct thread *td) { - struct ifaddr *ifa; + struct ifaddr *ifa; struct tap_softc *tp = dev->si_drv1; struct ifnet *ifp = tp->tap_ifp; int s; @@ -446,12 +452,15 @@ tapclose(dev, foo, bar, td) funsetown(&tp->tap_sigio); selwakeuppri(&tp->tap_rsel, PZERO+1); + KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0); mtx_lock(&tp->tap_mtx); tp->tap_flags &= ~TAP_OPEN; tp->tap_pid = 0; mtx_unlock(&tp->tap_mtx); + knlist_destroy(&tp->tap_rsel.si_note); + TAPDEBUG("%s is closed. minor = %#x\n", ifp->if_xname, minor(dev)); @@ -465,8 +474,7 @@ tapclose(dev, foo, bar, td) * network interface initialization function */ static void -tapifinit(xtp) - void *xtp; +tapifinit(void *xtp) { struct tap_softc *tp = (struct tap_softc *)xtp; struct ifnet *ifp = tp->tap_ifp; @@ -487,10 +495,7 @@ tapifinit(xtp) * Process an ioctl request on network interface */ static int -tapifioctl(ifp, cmd, data) - struct ifnet *ifp; - u_long cmd; - caddr_t data; +tapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); struct ifstat *ifs = NULL; @@ -520,6 +525,7 @@ tapifioctl(ifp, cmd, data) dummy = ether_ioctl(ifp, cmd, data); splx(s); return (dummy); + /* NOT REACHED */ } return (0); @@ -532,8 +538,7 @@ tapifioctl(ifp, cmd, data) * queue packets from higher level ready to put out */ static void -tapifstart(ifp) - struct ifnet *ifp; +tapifstart(struct ifnet *ifp) { struct tap_softc *tp = ifp->if_softc; int s; @@ -586,6 +591,7 @@ tapifstart(ifp) mtx_unlock(&tp->tap_mtx); selwakeuppri(&tp->tap_rsel, PZERO+1); + KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0); ifp->if_opackets ++; /* obytes are counted in ether_output */ } @@ -600,12 +606,7 @@ tapifstart(ifp) * the cdevsw interface is now pretty minimal */ static int -tapioctl(dev, cmd, data, flag, td) - struct cdev *dev; - u_long cmd; - caddr_t data; - int flag; - struct thread *td; +tapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) { struct tap_softc *tp = dev->si_drv1; struct ifnet *ifp = tp->tap_ifp; @@ -631,11 +632,11 @@ tapioctl(dev, cmd, data, flag, td) break; case TAPSDEBUG: - tapdebug = *(int *)data; + tapdebug = *(intptr_t *)data; break; case TAPGDEBUG: - *(int *)data = tapdebug; + *(intptr_t *)data = tapdebug; break; case FIONBIO: @@ -644,7 +645,7 @@ tapioctl(dev, cmd, data, flag, td) case FIOASYNC: s = splimp(); mtx_lock(&tp->tap_mtx); - if (*(int *)data) + if (*(intptr_t *)data) tp->tap_flags |= TAP_ASYNC; else tp->tap_flags &= ~TAP_ASYNC; @@ -657,27 +658,27 @@ tapioctl(dev, cmd, data, flag, td) if (ifp->if_snd.ifq_head) { struct mbuf *mb = ifp->if_snd.ifq_head; - for(*(int *)data = 0;mb != NULL;mb = mb->m_next) - *(int *)data += mb->m_len; + for(*(intptr_t *)data = 0;mb != NULL;mb = mb->m_next) + *(intptr_t *)data += mb->m_len; } else - *(int *)data = 0; + *(intptr_t *)data = 0; splx(s); break; case FIOSETOWN: - return (fsetown(*(int *)data, &tp->tap_sigio)); + return (fsetown(*(intptr_t *)data, &tp->tap_sigio)); case FIOGETOWN: - *(int *)data = fgetown(&tp->tap_sigio); + *(intptr_t *)data = fgetown(&tp->tap_sigio); return (0); /* this is deprecated, FIOSETOWN should be used instead */ case TIOCSPGRP: - return (fsetown(-(*(int *)data), &tp->tap_sigio)); + return (fsetown(-(*(intptr_t *)data), &tp->tap_sigio)); /* this is deprecated, FIOGETOWN should be used instead */ case TIOCGPGRP: - *(int *)data = -fgetown(&tp->tap_sigio); + *(intptr_t *)data = -fgetown(&tp->tap_sigio); return (0); /* VMware/VMnet port ioctl's */ @@ -687,7 +688,7 @@ tapioctl(dev, cmd, data, flag, td) break; case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ - f = *(int *)data; + f = *(intptr_t *)data; f &= 0x0fff; f &= ~IFF_CANTCHANGE; f |= IFF_UP; @@ -724,10 +725,7 @@ tapioctl(dev, cmd, data, flag, td) * least as much of a packet as can be read */ static int -tapread(dev, uio, flag) - struct cdev *dev; - struct uio *uio; - int flag; +tapread(struct cdev *dev, struct uio *uio, int flag) { struct tap_softc *tp = dev->si_drv1; struct ifnet *ifp = tp->tap_ifp; @@ -798,10 +796,7 @@ tapread(dev, uio, flag) * the cdevsw write interface - an atomic write is a packet - or else! */ static int -tapwrite(dev, uio, flag) - struct cdev *dev; - struct uio *uio; - int flag; +tapwrite(struct cdev *dev, struct uio *uio, int flag) { struct tap_softc *tp = dev->si_drv1; struct ifnet *ifp = tp->tap_ifp; @@ -844,10 +839,7 @@ tapwrite(dev, uio, flag) * anyway, it either accepts the packet or drops it */ static int -tappoll(dev, events, td) - struct cdev *dev; - int events; - struct thread *td; +tappoll(struct cdev *dev, int events, struct thread *td) { struct tap_softc *tp = dev->si_drv1; struct ifnet *ifp = tp->tap_ifp; @@ -878,3 +870,104 @@ tappoll(dev, events, td) splx(s); return (revents); } /* tappoll */ + + +/* + * tap_kqfilter + * + * support for kevent() system call + */ +static int +tapkqfilter(struct cdev *dev, struct knote *kn) +{ + int s; + struct tap_softc *tp = dev->si_drv1; + struct ifnet *ifp = tp->tap_ifp; + + s = splimp(); + switch (kn->kn_filter) { + case EVFILT_READ: + TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n", + ifp->if_xname, minor(dev)); + kn->kn_fop = &tap_read_filterops; + break; + + case EVFILT_WRITE: + TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n", + ifp->if_xname, minor(dev)); + kn->kn_fop = &tap_write_filterops; + break; + + default: + TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n", + ifp->if_xname, minor(dev)); + splx(s); + return (EINVAL); + /* NOT REACHED */ + } + splx(s); + + kn->kn_hook = (caddr_t) dev; + knlist_add(&tp->tap_rsel.si_note, kn, 0); + + return (0); +} /* tapkqfilter */ + + +/* + * tap_kqread + * + * Return true if there is data in the interface queue + */ +static int +tapkqread(struct knote *kn, long hint) +{ + int ret, s; + struct cdev *dev = (struct cdev *)(kn->kn_hook); + struct tap_softc *tp = dev->si_drv1; + struct ifnet *ifp = tp->tap_ifp; + + s = splimp(); + if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) { + TAPDEBUG("%s have data in queue. len = %d, minor = %#x\n", + ifp->if_xname, ifp->if_snd.ifq_len, minor(dev)); + ret = 1; + } else { + TAPDEBUG("%s waiting for data, minor = %#x\n", + ifp->if_xname, minor(dev)); + ret = 0; + } + splx(s); + + return (ret); +} /* tapkqread */ + + +/* + * tap_kqwrite + * + * Always can write. Return the MTU in kn->data + */ +static int +tapkqwrite(struct knote *kn, long hint) +{ + int s; + struct tap_softc *tp = ((struct cdev *) kn->kn_hook)->si_drv1; + struct ifnet *ifp = tp->tap_ifp; + + s = splimp(); + kn->kn_data = ifp->if_mtu; + splx(s); + + return (1); +} /* tapkqwrite */ + + +static void +tapkqdetach(struct knote *kn) +{ + struct tap_softc *tp = ((struct cdev *) kn->kn_hook)->si_drv1; + + knlist_remove(&tp->tap_rsel.si_note, kn, 0); +} /* tapkqdetach */ + -- cgit v1.1