Пример #1
0
/*
 * Allocate or resize buffers.
 */
int
bpf_buffer_ioctl_sblen(struct bpf_d *d, u_int *i)
{
	u_int size;
	caddr_t fbuf, sbuf;

	size = *i;
	if (size > bpf_maxbufsize)
		*i = size = bpf_maxbufsize;
	else if (size < BPF_MINBUFSIZE)
		*i = size = BPF_MINBUFSIZE;

	/* Allocate buffers immediately */
	fbuf = (caddr_t)malloc(size, M_BPF, M_WAITOK);
	sbuf = (caddr_t)malloc(size, M_BPF, M_WAITOK);

	BPFD_LOCK(d);
	if (d->bd_bif != NULL) {
		/* Interface already attached, unable to change buffers */
		BPFD_UNLOCK(d);
		free(fbuf, M_BPF);
		free(sbuf, M_BPF);
		return (EINVAL);
	}

	while (d->bd_hbuf_in_use)
		mtx_sleep(&d->bd_hbuf_in_use, &d->bd_lock,
		    PRINET, "bd_hbuf", 0);
	/* Free old buffers if set */
	if (d->bd_fbuf != NULL)
		free(d->bd_fbuf, M_BPF);
	if (d->bd_sbuf != NULL)
		free(d->bd_sbuf, M_BPF);

	/* Fill in new data */
	d->bd_bufsize = size;
	d->bd_fbuf = fbuf;
	d->bd_sbuf = sbuf;

	d->bd_hbuf = NULL;
	d->bd_slen = 0;
	d->bd_hlen = 0;

	BPFD_UNLOCK(d);
	return (0);
}
Пример #2
0
/*
 * Allocate or resize buffers.
 */
int
bpf_buffer_ioctl_sblen(struct bpf_d *d, u_int *i)
{
	u_int size;

	BPFD_LOCK(d);
	if (d->bd_bif != NULL) {
		BPFD_UNLOCK(d);
		return (EINVAL);
	}
	size = *i;
	if (size > bpf_maxbufsize)
		*i = size = bpf_maxbufsize;
	else if (size < BPF_MINBUFSIZE)
		*i = size = BPF_MINBUFSIZE;
	d->bd_bufsize = size;
	BPFD_UNLOCK(d);
	return (0);
}
Пример #3
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_LOCK(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_UNLOCK(d);
	return (0);
}
Пример #4
0
/*
 * Ioctl to configure zero-copy buffers -- may be done only once.
 */
int
bpf_zerocopy_ioctl_setzbuf(struct thread *td, struct bpf_d *d,
    struct bpf_zbuf *bz)
{
	struct zbuf *zba, *zbb;
	int error;

	KASSERT(d->bd_bufmode == BPF_BUFMODE_ZBUF,
	    ("bpf_zerocopy_ioctl_setzbuf: not in zbuf mode"));

	/*
	 * Must set both buffers.  Cannot clear them.
	 */
	if (bz->bz_bufa == NULL || bz->bz_bufb == NULL)
		return (EINVAL);

	/*
	 * Buffers must have a size greater than 0.  Alignment and other size
	 * validity checking is done in zbuf_setup().
	 */
	if (bz->bz_buflen == 0)
		return (EINVAL);

	/*
	 * Allocate new buffers.
	 */
	error = zbuf_setup(td, (vm_offset_t)bz->bz_bufa, bz->bz_buflen,
	    &zba);
	if (error)
		return (error);
	error = zbuf_setup(td, (vm_offset_t)bz->bz_bufb, bz->bz_buflen,
	    &zbb);
	if (error) {
		zbuf_free(zba);
		return (error);
	}

	/*
	 * We only allow buffers to be installed once, so atomically check
	 * that no buffers are currently installed and install new buffers.
	 */
	BPFD_LOCK(d);
	if (d->bd_hbuf != NULL || d->bd_sbuf != NULL || d->bd_fbuf != NULL ||
	    d->bd_bif != NULL) {
		BPFD_UNLOCK(d);
		zbuf_free(zba);
		zbuf_free(zbb);
		return (EINVAL);
	}

	/*
	 * Point BPF descriptor at buffers; initialize sbuf as zba so that
	 * it is always filled first in the sequence, per bpf(4).
	 */
	d->bd_fbuf = (caddr_t)zbb;
	d->bd_sbuf = (caddr_t)zba;
	d->bd_slen = 0;
	d->bd_hlen = 0;

	/*
	 * We expose only the space left in the buffer after the size of the
	 * shared management region.
	 */
	d->bd_bufsize = bz->bz_buflen - sizeof(struct bpf_zbuf_header);
	BPFD_UNLOCK(d);
	return (0);
}