implement reception of "VLAN 0 priority tagged" packets.
authordlg <dlg@openbsd.org>
Thu, 19 Aug 2021 10:22:00 +0000 (10:22 +0000)
committerdlg <dlg@openbsd.org>
Thu, 19 Aug 2021 10:22:00 +0000 (10:22 +0000)
according to 802.1Q, vlan 0 on the wire is special and should be
interpreted as if it was a packet received on the parent interface,
but you get the packet priority information encoded in the vlan
header.

historically we drop vlan tagged packets that don't have a vlan
interface configured for the received tag number. historically we
have deviated from 802.1Q by allowing for the configuration of a
vlan subinterface with the vnetid "unset". this works just like any
other vlan interface, but it uses tag 0 on the wire. however, if
you're in a situation where you're receiving vlan tagged 0 packets
that really are part of the same layer 2 ethernet domain as the
parent inteface, this doesnt work well.

landry@ is in such a situation at work where the network is sending
his OpenBSD boxes packets with VLAN tag 0. sometimes. most of the
time the packets are untagged, which is expected, but sometimes
they have a VLAN header set. this causes problems, particularly
with arp.

this diff does the smallest possible change to enable reception of
these vlan 0 priority tagged packets. if an "unset" vlan interface
is not configured on the parent, then vlan 0 tagged packets get
their header stripped and continue stack processing as if they didnt
have the tag at all.

landry has been running this for months.
ok sthen@ claudio@

sys/net/if_ethersubr.c
sys/net/if_vlan.c
sys/net/if_vlan_var.h

index 87e8f01..f4ec4ff 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_ethersubr.c,v 1.275 2021/07/07 20:19:01 sashan Exp $       */
+/*     $OpenBSD: if_ethersubr.c,v 1.276 2021/08/19 10:22:00 dlg Exp $  */
 /*     $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $        */
 
 /*
@@ -404,12 +404,12 @@ ether_input(struct ifnet *ifp, struct mbuf *m)
        if (ISSET(m->m_flags, M_VLANTAG) ||
            etype == ETHERTYPE_VLAN || etype == ETHERTYPE_QINQ) {
 #if NVLAN > 0
-               m = vlan_input(ifp, m);
+               m = vlan_input(ifp, m, &sdelim);
                if (m == NULL)
                        return;
-#endif /* NVLAN > 0 */
-
+#else
                sdelim = 1;
+#endif
        }
 
        /*
@@ -497,6 +497,7 @@ ether_input(struct ifnet *ifp, struct mbuf *m)
         * At this point it is known that the packet is destined
         * for layer 3 protocol handling on the local port.
         */
+       etype = ntohs(eh->ether_type);
 
        switch (etype) {
        case ETHERTYPE_IP:
index 01fcdd3..08973cb 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_vlan.c,v 1.207 2021/06/09 03:24:54 dlg Exp $       */
+/*     $OpenBSD: if_vlan.c,v 1.208 2021/08/19 10:22:00 dlg Exp $       */
 
 /*
  * Copyright 1998 Massachusetts Institute of Technology
@@ -335,6 +335,23 @@ leave:
        if_put(ifp0);
 }
 
+struct mbuf *
+vlan_strip(struct mbuf *m)
+{
+       if (ISSET(m->m_flags, M_VLANTAG)) {
+               CLR(m->m_flags, M_VLANTAG);
+       } else {
+               struct ether_vlan_header *evl;
+
+               evl = mtod(m, struct ether_vlan_header *);
+               memmove((caddr_t)evl + EVL_ENCAPLEN, evl,
+                   offsetof(struct ether_vlan_header, evl_encap_proto));
+               m_adj(m, EVL_ENCAPLEN);
+       }
+
+       return (m);
+}
+
 struct mbuf *
 vlan_inject(struct mbuf *m, uint16_t type, uint16_t tag)
 {
@@ -358,7 +375,7 @@ vlan_inject(struct mbuf *m, uint16_t type, uint16_t tag)
 }
 
 struct mbuf *
-vlan_input(struct ifnet *ifp0, struct mbuf *m)
+vlan_input(struct ifnet *ifp0, struct mbuf *m, unsigned int *sdelim)
 {
        struct vlan_softc *sc;
        struct ifnet *ifp;
@@ -407,8 +424,25 @@ vlan_input(struct ifnet *ifp0, struct mbuf *m)
        }
        smr_read_leave();
 
-       if (sc == NULL)
-               return (m); /* decline, let bridge have a go */
+       if (sc == NULL) {
+               /* VLAN 0 Priority Tagging */
+               if (tag == 0 && etype == ETHERTYPE_VLAN) {
+                       struct ether_header *eh;
+
+                       /* XXX we should actually use the prio value? */
+                       m = vlan_strip(m);
+
+                       eh = mtod(m, struct ether_header *);
+                       if (eh->ether_type == htons(ETHERTYPE_VLAN) ||
+                           eh->ether_type == htons(ETHERTYPE_QINQ)) {
+                               m_freem(m);
+                               return (NULL);
+                       }
+               } else
+                       *sdelim = 1;
+
+               return (m); /* decline */
+       }
 
        ifp = &sc->sc_if;
        if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
@@ -421,13 +455,7 @@ vlan_input(struct ifnet *ifp0, struct mbuf *m)
         * the given source interface and vlan tag, remove the
         * encapsulation.
         */
-       if (ISSET(m->m_flags, M_VLANTAG)) {
-               CLR(m->m_flags, M_VLANTAG);
-       } else {
-               memmove((caddr_t)evl + EVL_ENCAPLEN, evl,
-                   offsetof(struct ether_vlan_header, evl_encap_proto));
-               m_adj(m, EVL_ENCAPLEN);
-       }
+       m = vlan_strip(m);
 
        rxprio = sc->sc_rxprio;
        switch (rxprio) {
index 006ff2a..401701e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_vlan_var.h,v 1.42 2020/07/22 01:30:54 dlg Exp $    */
+/*     $OpenBSD: if_vlan_var.h,v 1.43 2021/08/19 10:22:00 dlg Exp $    */
 
 /*
  * Copyright 1998 Massachusetts Institute of Technology
@@ -47,7 +47,7 @@ struct        vlanreq {
 };
 
 #ifdef _KERNEL
-struct mbuf    *vlan_input(struct ifnet *, struct mbuf *);
+struct mbuf    *vlan_input(struct ifnet *, struct mbuf *, unsigned int *);
 struct mbuf    *vlan_inject(struct mbuf *, uint16_t, uint16_t);
 #endif /* _KERNEL */