bpf: add BIOCGETIFLIST ioctl that returns all available tap points
Differential Revision: https://reviews.freebsd.org/D53873
This commit is contained in:
+26
-1
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user