Module Name:    src
Committed By:   yamaguchi
Date:           Thu Nov  2 09:48:29 UTC 2023

Modified Files:
        src/sys/net: if_vlan.c

Log Message:
Support vlan(4) over l2tp(4)


To generate a diff of this commit:
cvs rdiff -u -r1.170 -r1.171 src/sys/net/if_vlan.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/if_vlan.c
diff -u src/sys/net/if_vlan.c:1.170 src/sys/net/if_vlan.c:1.171
--- src/sys/net/if_vlan.c:1.170	Mon Jun 20 08:14:48 2022
+++ src/sys/net/if_vlan.c	Thu Nov  2 09:48:29 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_vlan.c,v 1.170 2022/06/20 08:14:48 yamaguchi Exp $	*/
+/*	$NetBSD: if_vlan.c,v 1.171 2023/11/02 09:48:29 yamaguchi Exp $	*/
 
 /*
  * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@@ -78,7 +78,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.170 2022/06/20 08:14:48 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.171 2023/11/02 09:48:29 yamaguchi Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -97,6 +97,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 
 #include <sys/kauth.h>
 #include <sys/mutex.h>
 #include <sys/kmem.h>
+#include <sys/cprng.h>
 #include <sys/cpu.h>
 #include <sys/pserialize.h>
 #include <sys/psref.h>
@@ -149,6 +150,7 @@ struct ifvlan_linkmib {
 
 struct ifvlan {
 	struct ethercom ifv_ec;
+	uint8_t ifv_lladdr[ETHER_ADDR_LEN];
 	struct ifvlan_linkmib *ifv_mib;	/*
 					 * reader must use vlan_getref_linkmib()
 					 * instead of direct dereference
@@ -189,6 +191,15 @@ const struct vlan_multisw vlan_ether_mul
 	.vmsw_purgemulti = vlan_ether_purgemulti,
 };
 
+static void	vlan_multi_nothing(struct ifvlan *);
+static int	vlan_multi_nothing_ifreq(struct ifvlan *, struct ifreq *);
+
+const struct vlan_multisw vlan_nothing_multisw = {
+	.vmsw_addmulti = vlan_multi_nothing_ifreq,
+	.vmsw_delmulti = vlan_multi_nothing_ifreq,
+	.vmsw_purgemulti = vlan_multi_nothing,
+};
+
 static int	vlan_clone_create(struct if_clone *, int);
 static int	vlan_clone_destroy(struct ifnet *);
 static int	vlan_config(struct ifvlan *, struct ifnet *, uint16_t);
@@ -327,6 +338,9 @@ vlan_clone_create(struct if_clone *ifc, 
 	mib = kmem_zalloc(sizeof(struct ifvlan_linkmib), KM_SLEEP);
 	ifp = &ifv->ifv_if;
 	LIST_INIT(&ifv->ifv_mc_listhead);
+	cprng_fast(ifv->ifv_lladdr, sizeof(ifv->ifv_lladdr));
+	ifv->ifv_lladdr[0] &= 0xFE; /* clear I/G bit */
+	ifv->ifv_lladdr[0] |= 0x02; /* set G/L bit */
 
 	mib->ifvm_ifvlan = ifv;
 	mib->ifvm_p = NULL;
@@ -394,7 +408,10 @@ vlan_config(struct ifvlan *ifv, struct i
 	struct ifvlan_linkmib *omib = NULL;
 	struct ifvlan_linkmib *checkmib;
 	struct psref_target *nmib_psref = NULL;
+	struct ethercom *ec;
 	const uint16_t vid = EVL_VLANOFTAG(tag);
+	const uint8_t *lla;
+	u_char ifv_iftype;
 	int error = 0;
 	int idx;
 	bool omib_cleanup = false;
@@ -428,69 +445,79 @@ vlan_config(struct ifvlan *ifv, struct i
 
 	switch (p->if_type) {
 	case IFT_ETHER:
-	    {
-		struct ethercom *ec = (void *)p;
-
 		nmib->ifvm_msw = &vlan_ether_multisw;
 		nmib->ifvm_mintu = ETHERMIN;
 
-		error = ether_add_vlantag(p, tag, NULL);
-		if (error != 0)
-			goto done;
-
-		if (ec->ec_capenable & ETHERCAP_VLAN_MTU) {
-			nmib->ifvm_mtufudge = 0;
-		} else {
-			/*
-			 * Fudge the MTU by the encapsulation size. This
-			 * makes us incompatible with strictly compliant
-			 * 802.1Q implementations, but allows us to use
-			 * the feature with other NetBSD
-			 * implementations, which might still be useful.
-			 */
-			nmib->ifvm_mtufudge = ETHER_VLAN_ENCAP_LEN;
-		}
-
 		/*
-		 * If the parent interface can do hardware-assisted
-		 * VLAN encapsulation, then propagate its hardware-
-		 * assisted checksumming flags and tcp segmentation
-		 * offload.
+		 * We inherit the parent's Ethernet address.
 		 */
-		if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING) {
-			ifp->if_capabilities = p->if_capabilities &
-			    (IFCAP_TSOv4 | IFCAP_TSOv6 |
-				IFCAP_CSUM_IPv4_Tx  | IFCAP_CSUM_IPv4_Rx |
-				IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx |
-				IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx |
-				IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx |
-				IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx);
-		}
+		lla = CLLADDR(p->if_sadl);
 
 		/*
-		 * We inherit the parent's Ethernet address.
+		 * Inherit the if_type from the parent.  This allows us
+		 * to participate in bridges of that type.
 		 */
-		ether_ifattach(ifp, CLLADDR(p->if_sadl));
-		ifp->if_hdrlen = sizeof(struct ether_vlan_header); /* XXX? */
+		ifv_iftype = p->if_type;
+		break;
+
+	case IFT_L2TP:
+		nmib->ifvm_msw = &vlan_nothing_multisw;
+		nmib->ifvm_mintu = ETHERMIN;
+		/* use random Ethernet address. */
+		lla = ifv->ifv_lladdr;
+		ifv_iftype = IFT_ETHER;
 		break;
-	    }
 
 	default:
 		error = EPROTONOSUPPORT;
 		goto done;
 	}
 
+	error = ether_add_vlantag(p, tag, NULL);
+	if (error != 0)
+		goto done;
+
+	ec = (struct ethercom *)p;
+	if (ec->ec_capenable & ETHERCAP_VLAN_MTU) {
+		nmib->ifvm_mtufudge = 0;
+	} else {
+		/*
+		 * Fudge the MTU by the encapsulation size. This
+		 * makes us incompatible with strictly compliant
+		 * 802.1Q implementations, but allows us to use
+		 * the feature with other NetBSD
+		 * implementations, which might still be useful.
+		 */
+		nmib->ifvm_mtufudge = ETHER_VLAN_ENCAP_LEN;
+	}
+
+	/*
+	 * If the parent interface can do hardware-assisted
+	 * VLAN encapsulation, then propagate its hardware-
+	 * assisted checksumming flags and tcp segmentation
+	 * offload.
+	 */
+	if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING) {
+		ifp->if_capabilities = p->if_capabilities &
+		    (IFCAP_TSOv4 | IFCAP_TSOv6 |
+			IFCAP_CSUM_IPv4_Tx  | IFCAP_CSUM_IPv4_Rx |
+			IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx |
+			IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx |
+			IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx |
+			IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx);
+	}
+
+	ether_ifattach(ifp, lla);
+	ifp->if_hdrlen = sizeof(struct ether_vlan_header); /* XXX? */
+
 	nmib->ifvm_p = p;
 	nmib->ifvm_tag = vid;
 	ifv->ifv_if.if_mtu = p->if_mtu - nmib->ifvm_mtufudge;
 	ifv->ifv_if.if_flags = p->if_flags &
 	    (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
 
-	/*
-	 * Inherit the if_type from the parent.  This allows us
-	 * to participate in bridges of that type.
-	 */
-	ifv->ifv_if.if_type = p->if_type;
+	/*XXX need to update the if_type in if_sadl if it is changed */
+	ifv->ifv_if.if_type = ifv_iftype;
 
 	PSLIST_ENTRY_INIT(ifv, ifv_hash);
 	idx = vlan_tag_hash(vid, ifv_hash.mask);
@@ -587,32 +614,26 @@ vlan_unconfig_locked(struct ifvlan *ifv,
 	(*nmib->ifvm_msw->vmsw_purgemulti)(ifv);
 
 	/* Disconnect from parent. */
-	switch (p->if_type) {
-	case IFT_ETHER:
-	    {
-		(void)ether_del_vlantag(p, nmib->ifvm_tag);
-
-		/* XXX ether_ifdetach must not be called with IFNET_LOCK */
-		ifv->ifv_stopping = true;
-		mutex_exit(&ifv->ifv_lock);
-		IFNET_UNLOCK(ifp);
-		ether_ifdetach(ifp);
-		IFNET_LOCK(ifp);
-		mutex_enter(&ifv->ifv_lock);
-		ifv->ifv_stopping = false;
+	KASSERT(
+	    p->if_type == IFT_ETHER ||
+	    p->if_type == IFT_L2TP);
+	(void)ether_del_vlantag(p, nmib->ifvm_tag);
 
-		/* if_free_sadl must be called with IFNET_LOCK */
-		if_free_sadl(ifp, 1);
+	/* XXX ether_ifdetach must not be called with IFNET_LOCK */
+	ifv->ifv_stopping = true;
+	mutex_exit(&ifv->ifv_lock);
+	IFNET_UNLOCK(ifp);
+	ether_ifdetach(ifp);
+	IFNET_LOCK(ifp);
+	mutex_enter(&ifv->ifv_lock);
+	ifv->ifv_stopping = false;
 
-		/* Restore vlan_ioctl overwritten by ether_ifdetach */
-		ifp->if_ioctl = vlan_ioctl;
-		vlan_reset_linkname(ifp);
-		break;
-	    }
+	/* if_free_sadl must be called with IFNET_LOCK */
+	if_free_sadl(ifp, 1);
 
-	default:
-		panic("%s: impossible", __func__);
-	}
+	/* Restore vlan_ioctl overwritten by ether_ifdetach */
+	ifp->if_ioctl = vlan_ioctl;
+	vlan_reset_linkname(ifp);
 
 	nmib->ifvm_p = NULL;
 	ifv->ifv_if.if_mtu = 0;
@@ -1190,6 +1211,18 @@ vlan_ether_purgemulti(struct ifvlan *ifv
 	}
 }
 
+static int
+vlan_multi_nothing_ifreq(struct ifvlan *v __unused, struct ifreq *r __unused)
+{
+	/* do nothing */
+	return 0;
+}
+static void
+vlan_multi_nothing(struct ifvlan *v __unused)
+{
+	/* do nothing */
+}
+
 static void
 vlan_start(struct ifnet *ifp)
 {
@@ -1253,13 +1286,10 @@ vlan_start(struct ifnet *ifp)
 		 * the address family/header pointer in the pktattr.
 		 */
 		if (ALTQ_IS_ENABLED(&p->if_snd)) {
-			switch (p->if_type) {
-			case IFT_ETHER:
-				altq_etherclassify(&p->if_snd, m);
-				break;
-			default:
-				panic("%s: impossible (altq)", __func__);
-			}
+			KASSERT(
+			    p->if_type == IFT_ETHER ||
+			    p->if_type == IFT_L2TP);
+			altq_etherclassify(&p->if_snd, m);
 		}
 		KERNEL_UNLOCK_ONE(NULL);
 #endif /* ALTQ */
@@ -1275,20 +1305,15 @@ vlan_start(struct ifnet *ifp)
 			/*
 			 * insert the tag ourselves
 			 */
-
-			switch (p->if_type) {
-			case IFT_ETHER:
-				(void)ether_inject_vlantag(&m,
-				    ETHERTYPE_VLAN, mib->ifvm_tag);
-				if (m == NULL) {
-					printf("%s: unable to inject VLAN tag",
-					    p->if_xname);
-					continue;
-				}
-				break;
-
-			default:
-				panic("%s: impossible", __func__);
+			KASSERT(
+			    p->if_type == IFT_ETHER ||
+			    p->if_type == IFT_L2TP);
+			(void)ether_inject_vlantag(&m,
+			    ETHERTYPE_VLAN, mib->ifvm_tag);
+			if (m == NULL) {
+				printf("%s: unable to inject VLAN tag",
+				    p->if_xname);
+				continue;
 			}
 		}
 
@@ -1376,20 +1401,16 @@ vlan_transmit(struct ifnet *ifp, struct 
 		/*
 		 * insert the tag ourselves
 		 */
-		switch (p->if_type) {
-		case IFT_ETHER:
-			error = ether_inject_vlantag(&m,
-			    ETHERTYPE_VLAN, mib->ifvm_tag);
-			if (error != 0) {
-				KASSERT(m == NULL);
-				printf("%s: unable to inject VLAN tag",
-				    p->if_xname);
-				goto out;
-			}
-			break;
-
-		default:
-			panic("%s: impossible", __func__);
+		KASSERT(
+		    p->if_type == IFT_ETHER ||
+		    p->if_type == IFT_L2TP);
+		error = ether_inject_vlantag(&m,
+		    ETHERTYPE_VLAN, mib->ifvm_tag);
+		if (error != 0) {
+			KASSERT(m == NULL);
+			printf("%s: unable to inject VLAN tag",
+			    p->if_xname);
+			goto out;
 		}
 	}
 

Reply via email to