git: 6ca418e4816a - main - ifconfig: add setifcapnv()

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

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

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

    ifconfig: add setifcapnv()
    
    which uses SIOCSIFCAPNV to set arbitrary string-named interface
    capability.
    
    Reviewed by:    hselasky, jhb, kp
    Sponsored by:   NVIDIA Networking
    MFC after:      3 weeks
    Differential revision:  https://reviews.freebsd.org/D32551
---
 sbin/ifconfig/ifconfig.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 sbin/ifconfig/ifconfig.h |  2 ++
 2 files changed, 45 insertions(+)

diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 37ce0fb18943..9ee86b2a5169 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -44,6 +44,7 @@ static const char rcsid[] =
 #include <sys/ioctl.h>
 #include <sys/module.h>
 #include <sys/linker.h>
+#include <sys/nv.h>
 #include <sys/queue.h>
 #include <sys/socket.h>
 #include <sys/time.h>
@@ -1253,6 +1254,48 @@ setifcap(const char *vname, int value, int s, const struct afswtch *afp)
 		Perror(vname);
 }
 
+void
+setifcapnv(const char *vname, const char *arg, int s, const struct afswtch *afp)
+{
+	nvlist_t *nvcap;
+	void *buf;
+	char *marg, *mopt;
+	size_t nvbuflen;
+	bool neg;
+
+	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0)
+		Perror("ioctl (SIOCGIFCAP)");
+	if ((ifr.ifr_curcap & IFCAP_NV) == 0) {
+		warnx("IFCAP_NV not supported");
+		return; /* Not exit() */
+	}
+
+	marg = strdup(arg);
+	if (marg == NULL)
+		Perror("strdup");
+	nvcap = nvlist_create(0);
+	if (nvcap == NULL)
+		Perror("nvlist_create");
+	while ((mopt = strsep(&marg, ",")) != NULL) {
+		neg = *mopt == '-';
+		if (neg)
+			mopt++;
+		nvlist_add_bool(nvcap, mopt, !neg);
+	}
+	buf = nvlist_pack(nvcap, &nvbuflen);
+	if (buf == NULL) {
+		errx(1, "nvlist_pack error");
+		exit(1);
+	}
+	ifr.ifr_cap_nv.buf_length = ifr.ifr_cap_nv.length = nvbuflen;
+	ifr.ifr_cap_nv.buffer = buf;
+	if (ioctl(s, SIOCSIFCAPNV, (caddr_t)&ifr) < 0)
+		Perror(vname);
+	free(buf);
+	nvlist_destroy(nvcap);
+	free(marg);
+}
+
 static void
 setifmetric(const char *val, int dummy __unused, int s, 
     const struct afswtch *afp)
diff --git a/sbin/ifconfig/ifconfig.h b/sbin/ifconfig/ifconfig.h
index 4a9fb380fbab..26f68d67cec2 100644
--- a/sbin/ifconfig/ifconfig.h
+++ b/sbin/ifconfig/ifconfig.h
@@ -202,6 +202,8 @@ extern	int printifname;
 extern	int exit_code;
 
 void	setifcap(const char *, int value, int s, const struct afswtch *);
+void	setifcapnv(const char *vname, const char *arg, int s,
+	    const struct afswtch *afp);
 
 void	Perror(const char *cmd);
 void	printb(const char *s, unsigned value, const char *bits);