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