git: c10447a9256b - main - bpf: add BIOCGETIFLIST ioctl that returns all available tap points

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Mon, 15 Dec 2025 21:45:31 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=c10447a9256b561bf2edf26b5abf5f28071a15c7

commit c10447a9256b561bf2edf26b5abf5f28071a15c7
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2025-12-15 20:51:26 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
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,