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; } }