Пример #1
0
/*
 * Ioctl to force rotation of the two buffers, if there's any data available.
 * This can be used by user space to implement timeouts when waiting for a
 * buffer to fill.
 */
int
bpf_zerocopy_ioctl_rotzbuf(struct thread *td, struct bpf_d *d,
    struct bpf_zbuf *bz)
{
	struct zbuf *bzh;

	bzero(bz, sizeof(*bz));
	BPFD_WLOCK(d);
	if (d->bd_hbuf == NULL && d->bd_slen != 0) {
		ROTATE_BUFFERS(d);
		bzh = (struct zbuf *)d->bd_hbuf;
		bz->bz_bufa = (void *)bzh->zb_uaddr;
		bz->bz_buflen = d->bd_hlen;
	}
	BPFD_WUNLOCK(d);
	return (0);
}
Пример #2
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);
}
Пример #3
0
/*
 * Move the packet data from interface memory (pkt) into the
 * store buffer.  Return 1 if it's time to wakeup a listener (buffer full),
 * otherwise 0.  "copy" is the routine called to do the actual data
 * transfer.  bcopy is passed in to copy contiguous chunks, while
 * bpf_mcopy is passed in to copy mbuf chains.  In the latter case,
 * pkt is really an mbuf.
 */
void
bpf_catchpacket(struct bpf_d *d, u_char *pkt, size_t pktlen, size_t snaplen,
                void (*cpfn)(const void *, void *, size_t))
{
    struct bpf_hdr *hp;
    int totlen, curlen;
    int hdrlen = d->bd_bif->bif_hdrlen;
    struct timeval tv;

    /*
     * Figure out how many bytes to move.  If the packet is
     * greater or equal to the snapshot length, transfer that
     * much.  Otherwise, transfer the whole packet (unless
     * we hit the buffer size limit).
     */
    totlen = hdrlen + min(snaplen, pktlen);
    if (totlen > d->bd_bufsize)
        totlen = d->bd_bufsize;

    /*
     * Round up the end of the previous packet to the next longword.
     */
    curlen = BPF_WORDALIGN(d->bd_slen);
    if (curlen + totlen > d->bd_bufsize) {
        /*
         * This packet will overflow the storage buffer.
         * Rotate the buffers if we can, then wakeup any
         * pending reads.
         */
        if (d->bd_fbuf == 0) {
            /*
             * We haven't completed the previous read yet,
             * so drop the packet.
             */
            ++d->bd_dcount;
            return;
        }
        ROTATE_BUFFERS(d);
        bpf_wakeup(d);
        curlen = 0;
    }

    /*
     * Append the bpf header.
     */
    hp = (struct bpf_hdr *)(d->bd_sbuf + curlen);
    microtime(&tv);
    hp->bh_tstamp.tv_sec = tv.tv_sec;
    hp->bh_tstamp.tv_usec = tv.tv_usec;
    hp->bh_datalen = pktlen;
    hp->bh_hdrlen = hdrlen;
    /*
     * Copy the packet data into the store buffer and update its length.
     */
    (*cpfn)(pkt, (u_char *)hp + hdrlen, (hp->bh_caplen = totlen - hdrlen));
    d->bd_slen = curlen + totlen;

    if (d->bd_immediate) {
        /*
         * Immediate mode is set.  A packet arrived so any
         * reads should be woken up.
         */
        bpf_wakeup(d);
    }

    if (d->bd_rdStart && (d->bd_rtout + d->bd_rdStart < ticks)) {
        /*
         * we could be selecting on the bpf, and we
         * may have timeouts set.  We got here by getting
         * a packet, so wake up the reader.
         */
        if (d->bd_fbuf) {
            d->bd_rdStart = 0;
            ROTATE_BUFFERS(d);
            bpf_wakeup(d);
            curlen = 0;
        }
    }
}
Пример #4
0
Файл: bpf.c Проект: SbIm/xnu-env
/*
 *  bpfread - read next chunk of packets from buffers
 */
int
bpfread(dev_t dev, struct uio *uio, int ioflag)
{
	struct bpf_d *d;
	int error;

	lck_mtx_lock(bpf_mlock);

	d = bpf_dtab[minor(dev)];
	if (d == 0 || d == (void *)1) {
		lck_mtx_unlock(bpf_mlock);
		return (ENXIO);
	}


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

	/*
	 * 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_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;
		}

		/*
		 * No data is available, check to see if the bpf device
		 * is still pointed at a real interface.  If not, return
		 * ENXIO so that the userland process knows to rebind
		 * it before using it again.
		 */
		if (d->bd_bif == NULL) {
			lck_mtx_unlock(bpf_mlock);
			return (ENXIO);
		}
		if (ioflag & IO_NDELAY) {
			lck_mtx_unlock(bpf_mlock);
			return (EWOULDBLOCK);
		}
		error = BPF_SLEEP(d, PRINET|PCATCH, "bpf",
				  d->bd_rtout);
		/*
		 * Make sure device is still opened
		 */
		d = bpf_dtab[minor(dev)];
		if (d == 0 || d == (void *)1) {
			lck_mtx_unlock(bpf_mlock);
			return (ENXIO);
		}
		if (error == EINTR || error == ERESTART) {
			lck_mtx_unlock(bpf_mlock);
			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) {
				lck_mtx_unlock(bpf_mlock);
				return (0);
			}
			ROTATE_BUFFERS(d);
			break;
		}
	}
	/*
	 * At this point, we know we have something in the hold slot.
	 */

	/*
	 * 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_READ, uio);

	d->bd_fbuf = d->bd_hbuf;
	d->bd_hbuf = NULL;
	d->bd_hlen = 0;
	lck_mtx_unlock(bpf_mlock);
	return (error);
}