git: d72ea9fb3ff7 - main - ifconfig: Use SIOCGIFCAPNV if supported

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Tue, 24 May 2022 20:59:54 UTC
The branch main has been updated by kib:

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

commit d72ea9fb3ff7b80da8084b9423d8e58cbd621acf
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-12-15 03:46:33 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2022-05-24 20:59:33 +0000

    ifconfig: Use SIOCGIFCAPNV if supported
    
    Reviewed by:    hselasky, jhb, kp (previous version)
    Sponsored by:   NVIDIA Networking
    MFC after:      3 weeks
    Differential revision:  https://reviews.freebsd.org/D32551
---
 sbin/ifconfig/ifconfig.c | 65 +++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 59 insertions(+), 6 deletions(-)

diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 2ed7d43ac50c..4a0c3522c8e5 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -1425,8 +1425,12 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
 	struct ifaddrs *ifa)
 {
 	struct ifaddrs *ift;
-	int allfamilies, s;
 	struct ifstat ifs;
+	nvlist_t *nvcap;
+	const char *nvname;
+	void *buf, *cookie;
+	int allfamilies, s, type;
+	bool first, val;
 
 	if (afp == NULL) {
 		allfamilies = 1;
@@ -1471,13 +1475,62 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
 	}
 
 	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
-		if (ifr.ifr_curcap != 0) {
+		if ((ifr.ifr_curcap & IFCAP_NV) != 0) {
+			buf = malloc(IFR_CAP_NV_MAXBUFSIZE);
+			if (buf == NULL)
+				Perror("malloc");
+			ifr.ifr_cap_nv.buffer = buf;
+			ifr.ifr_cap_nv.buf_length = IFR_CAP_NV_MAXBUFSIZE;
+			if (ioctl(s, SIOCGIFCAPNV, (caddr_t)&ifr) != 0)
+				Perror("ioctl (SIOCGIFCAPNV)");
+			nvcap = nvlist_unpack(ifr.ifr_cap_nv.buffer,
+			    ifr.ifr_cap_nv.length, 0);
+			if (nvcap == NULL)
+				Perror("nvlist_unpack");
+			printf("\toptions");
+			cookie = NULL;
+			for (first = true;; first = false) {
+				nvname = nvlist_next(nvcap, &type, &cookie);
+				if (nvname == NULL) {
+					printf("\n");
+					break;
+				}
+				if (type == NV_TYPE_BOOL) {
+					val = nvlist_get_bool(nvcap, nvname);
+					if (val) {
+						printf("%c%s",
+						    first ? ' ' : ',', nvname);
+					}
+				}
+			}
+			if (supmedia) {
+				printf("\tcapabilities");
+				cookie = NULL;
+				for (first = true;; first = false) {
+					nvname = nvlist_next(nvcap, &type,
+					    &cookie);
+					if (nvname == NULL) {
+						printf("\n");
+						break;
+					}
+					if (type == NV_TYPE_BOOL)
+						printf("%c%s", first ? ' ' :
+						    ',', nvname);
+				}
+			}
+			nvlist_destroy(nvcap);
+			free(buf);
+
+			if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) != 0)
+				Perror("ioctl (SIOCGIFCAP)");
+		} else if (ifr.ifr_curcap != 0) {
 			printb("\toptions", ifr.ifr_curcap, IFCAPBITS);
 			putchar('\n');
-		}
-		if (supmedia && ifr.ifr_reqcap != 0) {
-			printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
-			putchar('\n');
+			if (supmedia && ifr.ifr_reqcap != 0) {
+				printb("\tcapabilities", ifr.ifr_reqcap,
+				    IFCAPBITS);
+				putchar('\n');
+			}
 		}
 	}