git: c9188db6f956 - stable/14 - ifconfig: Redo fix vlan/vlanproto reconfiguration

From: Zhenlei Huang <zlei_at_FreeBSD.org>
Date: Fri, 24 May 2024 16:05:01 UTC
The branch stable/14 has been updated by zlei:

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

commit c9188db6f956b30344bc99a13baf57727d4ac97a
Author:     Zhenlei Huang <zlei@FreeBSD.org>
AuthorDate: 2024-05-21 16:35:01 +0000
Commit:     Zhenlei Huang <zlei@FreeBSD.org>
CommitDate: 2024-05-24 16:03:02 +0000

    ifconfig: Redo fix vlan/vlanproto reconfiguration
    
    When the if_vlan(4) interface has not been fully configured, i.e., a
    bare interface without a physical interface associated with it,
    retrieving the current settings of it and unconditionally overwriting
    `params` will result in losing vlandev settings in `params`. That will
    lead to failing to associate the if_vlan(4) interface with the requested
    physical interface and the false report 'both vlan and vlandev must be
    specified'.
    
    Fix that by checking if the vlan interface has been fully configured.
    
    The basic VLAN test is slightly modified to cover this case.
    
    PR:             279181
    Reviewed by:    kp
    Tested by:      Mike Tancsa <mike@sentex.net>
    Fixes:          b82b8055ad44 ifconfig: fix vlan/vlanproto reconfiguration
    MFC after:      3 days
    Differential Revision:  https://reviews.freebsd.org/D45283
    
    (cherry picked from commit 76df3c57a0abfd24652bfa33982ba136d9d0575b)
---
 sbin/ifconfig/ifvlan.c   | 31 ++++++++++++++++++++++++++-----
 tests/sys/net/if_vlan.sh | 10 +++++++---
 2 files changed, 33 insertions(+), 8 deletions(-)

diff --git a/sbin/ifconfig/ifvlan.c b/sbin/ifconfig/ifvlan.c
index a79ea35bc14b..0a2603f1736f 100644
--- a/sbin/ifconfig/ifvlan.c
+++ b/sbin/ifconfig/ifvlan.c
@@ -60,6 +60,7 @@
 #include "ifconfig.h"
 
 #define	NOTAG	((u_short) -1)
+#define	NOPROTO	((u_short) -1)
 
 static const char proto_8021Q[]  = "802.1q";
 static const char proto_8021ad[] = "802.1ad";
@@ -67,7 +68,7 @@ static const char proto_qinq[] = "qinq";
 
 static 	struct vlanreq params = {
 	.vlr_tag	= NOTAG,
-	.vlr_proto	= ETHERTYPE_VLAN,
+	.vlr_proto	= NOPROTO,
 };
 
 static void
@@ -157,6 +158,8 @@ vlan_create(if_ctx *ctx, struct ifreq *ifr)
 			errx(1, "must specify a tag for vlan create");
 		if (params.vlr_parent[0] == '\0')
 			errx(1, "must specify a parent device for vlan create");
+		if (params.vlr_proto == NOPROTO)
+			params.vlr_proto = ETHERTYPE_VLAN;
 		ifr->ifr_data = (caddr_t) &params;
 	}
 	ifcreate_ioctl(ctx, ifr);
@@ -173,6 +176,8 @@ static void
 vlan_set(int s, struct ifreq *ifr)
 {
 	if (params.vlr_tag != NOTAG && params.vlr_parent[0] != '\0') {
+		if (params.vlr_proto == NOPROTO)
+			params.vlr_proto = ETHERTYPE_VLAN;
 		ifr->ifr_data = (caddr_t) &params;
 		if (ioctl(s, SIOCSETVLAN, (caddr_t)ifr) == -1)
 			err(1, "SIOCSETVLAN");
@@ -196,8 +201,16 @@ setvlantag(if_ctx *ctx, const char *val, int dummy __unused)
 		errx(1, "value for vlan out of range");
 
 	if (ioctl_ctx_ifr(ctx, SIOCGETVLAN, &ifr) != -1) {
-		vreq.vlr_tag = params.vlr_tag;
-		memcpy(&params, &vreq, sizeof(params));
+		/*
+		 * Retrieve the current settings if the interface has already
+		 * been configured.
+		 */
+		if (vreq.vlr_parent[0] != '\0') {
+			if (params.vlr_parent[0] == '\0')
+				strlcpy(params.vlr_parent, vreq.vlr_parent, IFNAMSIZ);
+			if (params.vlr_proto == NOPROTO)
+				params.vlr_proto = vreq.vlr_proto;
+		}
 		vlan_set(ctx->io_s, &ifr);
 	}
 }
@@ -230,8 +243,16 @@ setvlanproto(if_ctx *ctx, const char *val, int dummy __unused)
 		errx(1, "invalid value for vlanproto");
 
 	if (ioctl_ctx_ifr(ctx, SIOCGETVLAN, &ifr) != -1) {
-		vreq.vlr_proto = params.vlr_proto;
-		memcpy(&params, &vreq, sizeof(params));
+		/*
+		 * Retrieve the current settings if the interface has already
+		 * been configured.
+		 */
+		if (vreq.vlr_parent[0] != '\0') {
+			if (params.vlr_parent[0] == '\0')
+				strlcpy(params.vlr_parent, vreq.vlr_parent, IFNAMSIZ);
+			if (params.vlr_tag == NOTAG)
+				params.vlr_tag = vreq.vlr_tag;
+		}
 		vlan_set(ctx->io_s, &ifr);
 	}
 }
diff --git a/tests/sys/net/if_vlan.sh b/tests/sys/net/if_vlan.sh
index 675ed0090e8c..458e3cc36bc6 100755
--- a/tests/sys/net/if_vlan.sh
+++ b/tests/sys/net/if_vlan.sh
@@ -22,8 +22,12 @@ basic_body()
 	jexec alcatraz ifconfig ${epair_vlan}a up
 	jexec alcatraz ifconfig ${vlan0} 10.0.0.1/24 up
 
-	vlan1=$(jexec singsing ifconfig vlan create vlandev ${epair_vlan}b \
-		vlan 42)
+	vlan1=$(jexec singsing ifconfig vlan create)
+
+	# Test associating the physical interface
+	atf_check -s exit:0 \
+	    jexec singsing ifconfig ${vlan1} vlandev ${epair_vlan}b vlan 42
+
 	jexec singsing ifconfig ${epair_vlan}b up
 	jexec singsing ifconfig ${vlan1} 10.0.0.2/24 up
 
@@ -37,7 +41,7 @@ basic_body()
 	# And change back
 	# Test changing the vlan ID
 	atf_check -s exit:0 \
-	    jexec singsing ifconfig ${vlan1} vlandev ${epair_vlan}b vlan 42
+	    jexec singsing ifconfig ${vlan1} vlan 42 vlandev ${epair_vlan}b
 	atf_check -s exit:0 -o ignore jexec singsing ping -c 1 10.0.0.1
 }