Пример #1
0
int
bpfkqfilter(dev_t dev, struct knote *kn)
{
    struct bpf_d *d;
    struct klist *klist;
    int s;

    d = bpfilter_lookup(minor(dev));
    switch (kn->kn_filter) {
    case EVFILT_READ:
        klist = &d->bd_sel.si_note;
        kn->kn_fop = &bpfread_filtops;
        break;
    default:
        return (1);
    }

    kn->kn_hook = (caddr_t)((u_long)dev);

    s = splnet();
    SLIST_INSERT_HEAD(klist, kn, kn_selnext);
    splx(s);

    return (0);
}
Пример #2
0
/*
 * Support for poll() system call
 */
int
bpfpoll(dev_t dev, int events, struct proc *p)
{
	struct bpf_d *d;
	int s, revents;

	revents = events & (POLLIN | POLLRDNORM);
	if (revents == 0)
		return (0);		/* only support reading */

	/*
	 * An imitation of the FIONREAD ioctl code.
	 */
	d = bpfilter_lookup(minor(dev));
	s = splnet();
	if (d->bd_hlen == 0 && (!d->bd_immediate || d->bd_slen == 0)) {
		revents = 0;		/* no data waiting */
		/*
		 * if there's a timeout, mark the time we started waiting.
		 */
		if (d->bd_rtout != -1 && d->bd_rdStart == 0)
			d->bd_rdStart = ticks;
		selrecord(p, &d->bd_sel);
	}
	splx(s);
	return (revents);
}
Пример #3
0
int
filt_bpfread(struct knote *kn, long hint)
{
    dev_t dev = (dev_t)((u_long)kn->kn_hook);
    struct bpf_d *d;

    d = bpfilter_lookup(minor(dev));
    kn->kn_data = d->bd_hlen;
    if (d->bd_immediate)
        kn->kn_data += d->bd_slen;
    return (kn->kn_data > 0);
}
Пример #4
0
void
filt_bpfrdetach(struct knote *kn)
{
    dev_t dev = (dev_t)((u_long)kn->kn_hook);
    struct bpf_d *d;
    int s;

    d = bpfilter_lookup(minor(dev));
    s = splnet();
    SLIST_REMOVE(&d->bd_sel.si_note, kn, knote, kn_selnext);
    splx(s);
}
Пример #5
0
/* ARGSUSED */
int
bpfclose(dev_t dev, int flag, int mode, struct proc *p)
{
    struct bpf_d *d;
    int s;

    d = bpfilter_lookup(minor(dev));
    s = splnet();
    if (d->bd_bif)
        bpf_detachd(d);
    bpf_wakeup(d);
    D_PUT(d);
    splx(s);

    return (0);
}
Пример #6
0
int
bpfwrite(dev_t dev, struct uio *uio, int ioflag)
{
	struct bpf_d *d;
	struct ifnet *ifp;
	struct mbuf *m;
	int error, s;
	struct sockaddr_storage dst;

	d = bpfilter_lookup(minor(dev));
	if (d->bd_bif == 0)
		return (ENXIO);

	ifp = d->bd_bif->bif_ifp;

	if ((ifp->if_flags & IFF_UP) == 0)
		return (ENETDOWN);

	if (uio->uio_resid == 0)
		return (0);

	error = bpf_movein(uio, d->bd_bif->bif_dlt, &m,
	    (struct sockaddr *)&dst, d->bd_wfilter);
	if (error)
		return (error);

	if (m->m_pkthdr.len > ifp->if_mtu) {
		m_freem(m);
		return (EMSGSIZE);
	}

	m->m_pkthdr.rdomain = ifp->if_rdomain;

	if (d->bd_hdrcmplt)
		dst.ss_family = pseudo_AF_HDRCMPLT;

	s = splsoftnet();
	error = (*ifp->if_output)(ifp, m, (struct sockaddr *)&dst,
	    (struct rtentry *)0);
	splx(s);
	/*
	 * The driver frees the mbuf.
	 */
	return (error);
}
Пример #7
0
/*
 * Support for poll() system call
 */
int
bpfpoll(dev_t dev, int events, struct proc *p)
{
	struct bpf_d *d;
	int s, revents;

	/*
	 * An imitation of the FIONREAD ioctl code.
	 */
	d = bpfilter_lookup(minor(dev));

	/*
	 * XXX The USB stack manages it to trigger some race condition
	 * which causes bpfilter_lookup to return NULL when a USB device
	 * gets detached while it is up and has an open bpf handler (e.g.
	 * dhclient).  We still should recheck if we can fix the root
	 * cause of this issue.
	 */
	if (d == NULL)
		return (POLLERR);

	/* Always ready to write data */
	revents = events & (POLLOUT | POLLWRNORM);

	if (events & (POLLIN | POLLRDNORM)) {
		s = splnet();
		if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0))
			revents |= events & (POLLIN | POLLRDNORM);
		else {
			/*
			 * if there's a timeout, mark the time we
			 * started waiting.
			 */
			if (d->bd_rtout != -1 && d->bd_rdStart == 0)
				d->bd_rdStart = ticks;
			selrecord(p, &d->bd_sel);
		}
		splx(s);
	}
	return (revents);
}
Пример #8
0
/* ARGSUSED */
int
bpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
{
    struct bpf_d *d;
    int s, error = 0;

    d = bpfilter_lookup(minor(dev));
    if (d->bd_locked && suser(p, 0) != 0) {
        /* list of allowed ioctls when locked and not root */
        switch (cmd) {
        case BIOCGBLEN:
        case BIOCFLUSH:
        case BIOCGDLT:
        case BIOCGDLTLIST:
        case BIOCGETIF:
        case BIOCGRTIMEOUT:
        case BIOCGSTATS:
        case BIOCVERSION:
        case BIOCGRSIG:
        case BIOCGHDRCMPLT:
        case FIONREAD:
        case BIOCLOCK:
        case BIOCSRTIMEOUT:
        case BIOCIMMEDIATE:
        case TIOCGPGRP:
        case BIOCGDIRFILT:
            break;
        default:
            return (EPERM);
        }
    }

    switch (cmd) {

    default:
        error = EINVAL;
        break;

    /*
     * Check for read packet available.
     */
    case FIONREAD:
    {
        int n;

        s = splnet();
        n = d->bd_slen;
        if (d->bd_hbuf)
            n += d->bd_hlen;
        splx(s);

        *(int *)addr = n;
        break;
    }

    /*
     * Get buffer len [for read()].
     */
    case BIOCGBLEN:
        *(u_int *)addr = d->bd_bufsize;
        break;

    /*
     * Set buffer length.
     */
    case BIOCSBLEN:
        if (d->bd_bif != 0)
            error = EINVAL;
        else {
            u_int size = *(u_int *)addr;

            if (size > bpf_maxbufsize)
                *(u_int *)addr = size = bpf_maxbufsize;
            else if (size < BPF_MINBUFSIZE)
                *(u_int *)addr = size = BPF_MINBUFSIZE;
            d->bd_bufsize = size;
        }
        break;

    /*
     * Set link layer read filter.
     */
    case BIOCSETF:
        error = bpf_setf(d, (struct bpf_program *)addr, 0);
        break;

    /*
     * Set link layer write filter.
     */
    case BIOCSETWF:
        error = bpf_setf(d, (struct bpf_program *)addr, 1);
        break;

    /*
     * Flush read packet buffer.
     */
    case BIOCFLUSH:
        s = splnet();
        bpf_reset_d(d);
        splx(s);
        break;

    /*
     * Put interface into promiscuous mode.
     */
    case BIOCPROMISC:
        if (d->bd_bif == 0) {
            /*
             * No interface attached yet.
             */
            error = EINVAL;
            break;
        }
        s = splnet();
        if (d->bd_promisc == 0) {
            error = ifpromisc(d->bd_bif->bif_ifp, 1);
            if (error == 0)
                d->bd_promisc = 1;
        }
        splx(s);
        break;

    /*
     * Get a list of supported device parameters.
     */
    case BIOCGDLTLIST:
        if (d->bd_bif == NULL)
            error = EINVAL;
        else
            error = bpf_getdltlist(d, (struct bpf_dltlist *)addr);
        break;

    /*
     * Get device parameters.
     */
    case BIOCGDLT:
        if (d->bd_bif == 0)
            error = EINVAL;
        else
            *(u_int *)addr = d->bd_bif->bif_dlt;
        break;

    /*
     * Set device parameters.
     */
    case BIOCSDLT:
        if (d->bd_bif == NULL)
            error = EINVAL;
        else
            error = bpf_setdlt(d, *(u_int *)addr);
        break;

    /*
     * Set interface name.
     */
    case BIOCGETIF:
        if (d->bd_bif == 0)
            error = EINVAL;
        else
            bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr);
        break;

    /*
     * Set interface.
     */
    case BIOCSETIF:
        error = bpf_setif(d, (struct ifreq *)addr);
        break;

    /*
     * Set read timeout.
     */
    case BIOCSRTIMEOUT:
    {
        struct timeval *tv = (struct timeval *)addr;

        /* Compute number of ticks. */
        d->bd_rtout = tv->tv_sec * hz + tv->tv_usec / tick;
        if (d->bd_rtout == 0 && tv->tv_usec != 0)
            d->bd_rtout = 1;
        break;
    }

    /*
     * Get read timeout.
     */
    case BIOCGRTIMEOUT:
    {
        struct timeval *tv = (struct timeval *)addr;

        tv->tv_sec = d->bd_rtout / hz;
        tv->tv_usec = (d->bd_rtout % hz) * tick;
        break;
    }

    /*
     * Get packet stats.
     */
    case BIOCGSTATS:
    {
        struct bpf_stat *bs = (struct bpf_stat *)addr;

        bs->bs_recv = d->bd_rcount;
        bs->bs_drop = d->bd_dcount;
        break;
    }

    /*
     * Set immediate mode.
     */
    case BIOCIMMEDIATE:
        d->bd_immediate = *(u_int *)addr;
        break;

    case BIOCVERSION:
    {
        struct bpf_version *bv = (struct bpf_version *)addr;

        bv->bv_major = BPF_MAJOR_VERSION;
        bv->bv_minor = BPF_MINOR_VERSION;
        break;
    }

    case BIOCGHDRCMPLT:	/* get "header already complete" flag */
        *(u_int *)addr = d->bd_hdrcmplt;
        break;

    case BIOCSHDRCMPLT:	/* set "header already complete" flag */
        d->bd_hdrcmplt = *(u_int *)addr ? 1 : 0;
        break;

    case BIOCLOCK:		/* set "locked" flag (no reset) */
        d->bd_locked = 1;
        break;

    case BIOCGFILDROP:	/* get "filter-drop" flag */
        *(u_int *)addr = d->bd_fildrop;
        break;

    case BIOCSFILDROP:	/* set "filter-drop" flag */
        d->bd_fildrop = *(u_int *)addr ? 1 : 0;
        break;

    case BIOCGDIRFILT:	/* get direction filter */
        *(u_int *)addr = d->bd_dirfilt;
        break;

    case BIOCSDIRFILT:	/* set direction filter */
        d->bd_dirfilt = (*(u_int *)addr) &
                        (BPF_DIRECTION_IN|BPF_DIRECTION_OUT);
        break;

    case FIONBIO:		/* Non-blocking I/O */
        if (*(int *)addr)
            d->bd_rtout = -1;
        else
            d->bd_rtout = 0;
        break;

    case FIOASYNC:		/* Send signal on receive packets */
        d->bd_async = *(int *)addr;
        break;

    /*
     * N.B.  ioctl (FIOSETOWN) and fcntl (F_SETOWN) both end up doing
     * the equivalent of a TIOCSPGRP and hence end up here.  *However*
     * TIOCSPGRP's arg is a process group if it's positive and a process
     * id if it's negative.  This is exactly the opposite of what the
     * other two functions want!  Therefore there is code in ioctl and
     * fcntl to negate the arg before calling here.
     */
    case TIOCSPGRP:		/* Process or group to send signals to */
        d->bd_pgid = *(int *)addr;
        d->bd_siguid = p->p_cred->p_ruid;
        d->bd_sigeuid = p->p_ucred->cr_uid;
        break;

    case TIOCGPGRP:
        *(int *)addr = d->bd_pgid;
        break;

    case BIOCSRSIG:		/* Set receive signal */
    {
        u_int sig;

        sig = *(u_int *)addr;

        if (sig >= NSIG)
            error = EINVAL;
        else
            d->bd_sig = sig;
        break;
    }
    case BIOCGRSIG:
        *(u_int *)addr = d->bd_sig;
        break;
    }
    return (error);
}
Пример #9
0
/*
 *  bpfread - read next chunk of packets from buffers
 */
int
bpfread(dev_t dev, struct uio *uio, int ioflag)
{
    struct bpf_d *d;
    int error;
    int s;

    d = bpfilter_lookup(minor(dev));
    if (d->bd_bif == 0)
        return (ENXIO);

    /*
     * Restrict application to use a buffer the same size as
     * as kernel buffers.
     */
    if (uio->uio_resid != d->bd_bufsize)
        return (EINVAL);

    s = splnet();

    D_GET(d);

    /*
     * bd_rdStart is tagged when we start the read, iff there's a timeout.
     * we can then figure out when we're done reading.
     */
    if (d->bd_rtout != -1 && d->bd_rdStart == 0)
        d->bd_rdStart = ticks;
    else
        d->bd_rdStart = 0;

    /*
     * If the hold buffer is empty, then do a timed sleep, which
     * ends when the timeout expires or when enough packets
     * have arrived to fill the store buffer.
     */
    while (d->bd_hbuf == 0) {
        if (d->bd_bif == NULL) {
            /* interface is gone */
            if (d->bd_slen == 0) {
                D_PUT(d);
                splx(s);
                return (EIO);
            }
            ROTATE_BUFFERS(d);
            break;
        }
        if (d->bd_immediate && d->bd_slen != 0) {
            /*
             * A packet(s) either arrived since the previous
             * read or arrived while we were asleep.
             * Rotate the buffers and return what's here.
             */
            ROTATE_BUFFERS(d);
            break;
        }
        if ((d->bd_rtout != -1) ||
                (d->bd_rdStart + d->bd_rtout) < ticks) {
            error = tsleep((caddr_t)d, PRINET|PCATCH, "bpf",
                           d->bd_rtout);
        } else {
            if (d->bd_rtout == -1) {
                /* User requested non-blocking I/O */
                error = EWOULDBLOCK;
            } else
                error = 0;
        }
        if (error == EINTR || error == ERESTART) {
            D_PUT(d);
            splx(s);
            return (error);
        }
        if (error == EWOULDBLOCK) {
            /*
             * On a timeout, return what's in the buffer,
             * which may be nothing.  If there is something
             * in the store buffer, we can rotate the buffers.
             */
            if (d->bd_hbuf)
                /*
                 * We filled up the buffer in between
                 * getting the timeout and arriving
                 * here, so we don't need to rotate.
                 */
                break;

            if (d->bd_slen == 0) {
                D_PUT(d);
                splx(s);
                return (0);
            }
            ROTATE_BUFFERS(d);
            break;
        }
    }
    /*
     * At this point, we know we have something in the hold slot.
     */
    splx(s);

    /*
     * Move data from hold buffer into user space.
     * We know the entire buffer is transferred since
     * we checked above that the read buffer is bpf_bufsize bytes.
     */
    error = uiomove(d->bd_hbuf, d->bd_hlen, uio);

    s = splnet();
    d->bd_fbuf = d->bd_hbuf;
    d->bd_hbuf = 0;
    d->bd_hlen = 0;

    D_PUT(d);
    splx(s);

    return (error);
}