The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=c10447a9256b561bf2edf26b5abf5f28071a15c7
commit c10447a9256b561bf2edf26b5abf5f28071a15c7 Author: Gleb Smirnoff <[email protected]> AuthorDate: 2025-12-15 20:51:26 +0000 Commit: Gleb Smirnoff <[email protected]> CommitDate: 2025-12-15 20:51:26 +0000 bpf: add BIOCGETIFLIST ioctl that returns all available tap points Differential Revision: https://reviews.freebsd.org/D53873 --- share/man/man4/bpf.4 | 27 +++++++++++++++++++++- sys/net/bpf.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++-- sys/net/bpf.h | 10 ++++++++ sys/sys/param.h | 2 +- 4 files changed, 100 insertions(+), 4 deletions(-) diff --git a/share/man/man4/bpf.4 b/share/man/man4/bpf.4 index 8082f6eac39a..dcf321c40782 100644 --- a/share/man/man4/bpf.4 +++ b/share/man/man4/bpf.4 @@ -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 diff --git a/sys/net/bpf.c b/sys/net/bpf.c index 0155b27b4919..4026c44112ab 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -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. diff --git a/sys/net/bpf.h b/sys/net/bpf.h index cda03c06d51d..f6bcb0e34ed4 100644 --- a/sys/net/bpf.h +++ b/sys/net/bpf.h @@ -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 diff --git a/sys/sys/param.h b/sys/sys/param.h index 003c28c082cb..fa09878507c6 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -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,
