bpf: add BIOCGETIFLIST ioctl that returns all available tap points

Differential Revision:	https://reviews.freebsd.org/D53873
This commit is contained in:
Gleb Smirnoff
2025-12-15 12:51:26 -08:00
parent 8774a990ee
commit c10447a925
4 changed files with 100 additions and 4 deletions
+26 -1
View File
@@ -47,7 +47,7 @@
.\" This document is derived in part from the enet man page (enet.4)
.\" distributed with 4.3BSD Unix.
.\"
.Dd October 13, 2021
.Dd December 10, 2025
.Dt BPF 4
.Os
.Sh NAME
@@ -276,6 +276,31 @@ The (third) argument to
.Xr ioctl 2
should be a pointer to the type indicated.
.Bl -tag -width BIOCGETBUFMODE
.It Dv BIOCGETIFLIST
.Pq Li "struct bpf_iflist"
Returns list of available tapping points, that can later be attached
to with
.Dv BIOCSETIF .
On entry the
.Vt bi_ubuf
shall point to user supplied buffer.
The
.Vt bi_size
shall specify length of the buffer, or 0 if the request is used
to determine the required length.
The
.Vt bi_count
can be used to limit the output to first
.Va count
entries, otherwise shall be 0.
On return, if the buffer length was enough to accomodate all desired entries,
then the supplied buffer is filled with NUL-terminated names of
available tapping points and
.Vt bi_count
is set to the number of copied names.
Otherwise
.Er ENOSPC
is returned.
.It Dv BIOCGBLEN
.Pq Li u_int
Returns the required buffer length for reads on
+63 -2
View File
@@ -221,8 +221,7 @@ struct bpf_dltlist32 {
* structures registered by different layers in the stack (i.e., 802.11
* frames, ethernet frames, etc).
*/
LIST_HEAD(bpf_iflist, bpf_if);
static struct bpf_iflist bpf_iflist = LIST_HEAD_INITIALIZER();
static LIST_HEAD(, bpf_if) bpf_iflist = LIST_HEAD_INITIALIZER();
static struct sx bpf_sx; /* bpf global lock */
static void bpfif_ref(struct bpf_if *);
@@ -240,6 +239,7 @@ static void catchpacket(struct bpf_d *, u_char *, u_int, u_int,
void (*)(struct bpf_d *, caddr_t, u_int, void *, u_int),
struct bintime *);
static void reset_d(struct bpf_d *);
static int bpf_getiflist(struct bpf_iflist *);
static int bpf_setf(struct bpf_d *, struct bpf_program *, u_long cmd);
static int bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *);
static int bpf_setdlt(struct bpf_d *, u_int);
@@ -1100,6 +1100,7 @@ reset_d(struct bpf_d *d)
/*
* FIONREAD Check for read packet available.
* BIOCGETIFLIST Get list of all tap points.
* BIOCGBLEN Get buffer len [for read()].
* BIOCSETF Set read filter.
* BIOCSETFNR Set read filter without resetting descriptor.
@@ -1153,6 +1154,7 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
if (d->bd_flags & BPFD_LOCKED) {
switch (cmd) {
case BIOCGETIFLIST:
case BIOCGBLEN:
case BIOCFLUSH:
case BIOCGDLT:
@@ -1230,6 +1232,12 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
*(int *)addr = n;
break;
}
/*
* Get list of all tap points.
*/
case BIOCGETIFLIST:
error = bpf_getiflist((struct bpf_iflist *)addr);
break;
/*
* Get buffer len [for read()].
@@ -1706,6 +1714,59 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
return (error);
}
/*
* Return list of available tapping points, or report how much space is
* required for a successful return.
*/
static int
bpf_getiflist(struct bpf_iflist *bi)
{
struct bpf_if *bp;
u_int allsize, size, cnt;
char *uaddr;
BPF_LOCK();
cnt = allsize = size = 0;
LIST_FOREACH(bp, &bpf_iflist, bif_next) {
allsize += strlen(bp->bif_name) + 1;
if (++cnt == bi->bi_count)
size = allsize;
}
if (size == 0)
size = allsize;
if (bi->bi_size == 0) {
BPF_UNLOCK();
bi->bi_size = size;
bi->bi_count = cnt;
return (0);
} else if (bi->bi_size < size) {
BPF_UNLOCK();
return (ENOSPC);
}
uaddr = bi->bi_ubuf;
cnt = 0;
LIST_FOREACH(bp, &bpf_iflist, bif_next) {
u_int len;
int error;
len = strlen(bp->bif_name) + 1;
if ((error = copyout(bp->bif_name, uaddr, len)) != 0) {
BPF_UNLOCK();
return (error);
}
if (++cnt == bi->bi_count)
break;
uaddr += len;
}
BPF_UNLOCK();
bi->bi_count = cnt;
return (0);
}
/*
* Set d's packet filter program to fp. If this file already has a filter,
* free it and replace it. Returns EINVAL for bogus requests.
+10
View File
@@ -118,6 +118,15 @@ struct bpf_zbuf {
size_t bz_buflen; /* Size of zero-copy buffers. */
};
/*
* Struct used by BIOCGETIFLIST.
*/
struct bpf_iflist {
u_int bi_size;
u_int bi_count;
void *bi_ubuf;
};
#define BIOCGBLEN _IOR('B', 102, u_int)
#define BIOCSBLEN _IOWR('B', 102, u_int)
#define BIOCSETF _IOW('B', 103, struct bpf_program)
@@ -151,6 +160,7 @@ struct bpf_zbuf {
#define BIOCGTSTAMP _IOR('B', 131, u_int)
#define BIOCSTSTAMP _IOW('B', 132, u_int)
#define BIOCSETVLANPCP _IOW('B', 133, u_int)
#define BIOCGETIFLIST _IOWR('B', 134, struct bpf_iflist)
/* Obsolete */
#define BIOCGSEESENT BIOCGDIRECTION
+1 -1
View File
@@ -74,7 +74,7 @@
* cannot include sys/param.h and should only be updated here.
*/
#undef __FreeBSD_version
#define __FreeBSD_version 1600005
#define __FreeBSD_version 1600006
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,