summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2020-07-22 01:30:55 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2020-07-22 01:30:55 +0000
commite38c7eb467620d279f738451e80d8ce868b9a3ca (patch)
tree1719bf088286c23236d4f6af0b96ae4cbb1b2e8a /sys/net
parent22ad5c772ea0eaf700df338e6b8d9f1e244ee4c7 (diff)
move vlan_input into ether_input, instead of via an input handler.
this means there's a consistent order of processing of service delimited (vlan and svlan) packets and bridging of packets. vlan and svlan get to look at a packet first. it's only if they decline a packet that a bridge can handle it. this allows operators to slice vlans out for processing separate to the "native" vlan handling if they want. while here, this fixes up a bug in vlan_input if m_pullup needed to prepend an mbuf. this has been in snaps as part of a larger diff for over a week.
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if_ethersubr.c46
-rw-r--r--sys/net/if_vlan.c74
-rw-r--r--sys/net/if_vlan_var.h3
3 files changed, 75 insertions, 48 deletions
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 942261e88ea..041cc259c05 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ethersubr.c,v 1.263 2020/07/22 00:37:24 dlg Exp $ */
+/* $OpenBSD: if_ethersubr.c,v 1.264 2020/07/22 01:30:54 dlg Exp $ */
/* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */
/*
@@ -104,6 +104,11 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
#include <net/bpf.h>
#endif
+#include "vlan.h"
+#if NVLAN > 0
+#include <net/if_vlan_var.h>
+#endif
+
#include "pppoe.h"
#if NPPPOE > 0
#include <net/if_pppoe.h>
@@ -357,12 +362,34 @@ ether_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
u_int16_t etype;
struct arpcom *ac;
const struct ether_brport *eb;
+ unsigned int sdelim = 0;
/* Drop short frames */
if (m->m_len < ETHER_HDR_LEN)
goto dropanyway;
/*
+ * Let vlan(4) and svlan(4) look at "service delimited"
+ * packets. If a virtual interface does not exist to take
+ * those packets, they're returned to ether_input() so a
+ * bridge can have a go at forwarding them.
+ */
+
+ eh = mtod(m, struct ether_header *);
+ etype = ntohs(eh->ether_type);
+
+ if (ISSET(m->m_flags, M_VLANTAG) ||
+ etype == ETHERTYPE_VLAN || etype == ETHERTYPE_QINQ) {
+#if NVLAN > 0
+ m = vlan_input(ifp, m);
+ if (m == NULL)
+ return (1);
+#endif /* NVLAN > 0 */
+
+ sdelim = 1;
+ }
+
+ /*
* Give the packet to a bridge interface, ie, bridge(4),
* switch(4), or tpmr(4), if it is configured. A bridge
* may take the packet and forward it to another port, or it
@@ -383,6 +410,14 @@ ether_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
}
smr_read_leave();
+ /*
+ * If the packet has a tag, and a bridge didn't want it,
+ * it's not for this port.
+ */
+
+ if (sdelim)
+ goto dropanyway;
+
eh = mtod(m, struct ether_header *);
/* Is the packet for us? */
@@ -409,15 +444,6 @@ ether_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
ifp->if_imcasts++;
}
- /*
- * HW vlan tagged packets that were not collected by vlan(4) must
- * be dropped now.
- */
- if (m->m_flags & M_VLANTAG)
- goto dropanyway;
-
- etype = ntohs(eh->ether_type);
-
switch (etype) {
case ETHERTYPE_IP:
input = ipv4_input;
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index 577b9d1f0b1..c5a08e63950 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_vlan.c,v 1.203 2020/02/01 10:27:40 jmatthew Exp $ */
+/* $OpenBSD: if_vlan.c,v 1.204 2020/07/22 01:30:54 dlg Exp $ */
/*
* Copyright 1998 Massachusetts Institute of Technology
@@ -119,7 +119,6 @@ void vlanattach(int count);
int vlan_clone_create(struct if_clone *, int);
int vlan_clone_destroy(struct ifnet *);
-int vlan_input(struct ifnet *, struct mbuf *, void *);
int vlan_enqueue(struct ifnet *, struct mbuf *);
void vlan_start(struct ifqueue *ifq);
int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
@@ -358,44 +357,45 @@ vlan_inject(struct mbuf *m, uint16_t type, uint16_t tag)
return (m);
}
-/*
- * vlan_input() returns 1 if it has consumed the packet, 0 otherwise.
- */
-int
-vlan_input(struct ifnet *ifp0, struct mbuf *m, void *cookie)
+struct mbuf *
+vlan_input(struct ifnet *ifp0, struct mbuf *m)
{
struct vlan_softc *sc;
+ struct ifnet *ifp;
struct ether_vlan_header *evl;
- struct ether_header *eh;
struct vlan_list *tagh, *list;
- uint16_t tag;
+ uint16_t vtag, tag;
uint16_t etype;
int rxprio;
- eh = mtod(m, struct ether_header *);
- etype = ntohs(eh->ether_type);
-
if (m->m_flags & M_VLANTAG) {
+ vtag = m->m_pkthdr.ether_vtag;
etype = ETHERTYPE_VLAN;
tagh = vlan_tagh;
- } else if ((etype == ETHERTYPE_VLAN) || (etype == ETHERTYPE_QINQ)) {
- if (m->m_len < sizeof(*evl) &&
- (m = m_pullup(m, sizeof(*evl))) == NULL) {
- ifp0->if_ierrors++;
- return (1);
+ } else {
+ if (m->m_len < sizeof(*evl)) {
+ m = m_pullup(m, sizeof(*evl));
+ if (m == NULL)
+ return (NULL);
}
evl = mtod(m, struct ether_vlan_header *);
- m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag);
- tagh = etype == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
- } else {
- /* Skip non-VLAN packets. */
- return (0);
+ vtag = bemtoh16(&evl->evl_tag);
+ etype = bemtoh16(&evl->evl_encap_proto);
+ switch (etype) {
+ case ETHERTYPE_VLAN:
+ tagh = vlan_tagh;
+ break;
+ case ETHERTYPE_QINQ:
+ tagh = svlan_tagh;
+ break;
+ default:
+ panic("%s: unexpected etype 0x%04x", __func__, etype);
+ /* NOTREACHED */
+ }
}
- /* From now on ether_vtag is fine */
- tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
-
+ tag = EVL_VLANOFTAG(vtag);
list = &tagh[TAG_HASH(tag)];
smr_read_enter();
SMR_SLIST_FOREACH(sc, list, sc_list) {
@@ -407,7 +407,11 @@ vlan_input(struct ifnet *ifp0, struct mbuf *m, void *cookie)
}
smr_read_leave();
- if (sc == NULL || !ISSET(sc->sc_if.if_flags, IFF_RUNNING)) {
+ if (sc == NULL)
+ return (m); /* decline, let bridge have a go */
+
+ ifp = &sc->sc_if;
+ if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
m_freem(m);
goto leave;
}
@@ -417,11 +421,11 @@ vlan_input(struct ifnet *ifp0, struct mbuf *m, void *cookie)
* the given source interface and vlan tag, remove the
* encapsulation.
*/
- if (m->m_flags & M_VLANTAG) {
- m->m_flags &= ~M_VLANTAG;
+ if (ISSET(m->m_flags, M_VLANTAG)) {
+ CLR(m->m_flags, M_VLANTAG);
} else {
- eh->ether_type = evl->evl_proto;
- memmove((char *)eh + EVL_ENCAPLEN, eh, sizeof(*eh));
+ memmove((caddr_t)evl + EVL_ENCAPLEN, evl,
+ offsetof(struct ether_vlan_header, evl_encap_proto));
m_adj(m, EVL_ENCAPLEN);
}
@@ -440,11 +444,10 @@ vlan_input(struct ifnet *ifp0, struct mbuf *m, void *cookie)
break;
}
- if_vinput(&sc->sc_if, m);
+ if_vinput(ifp, m);
leave:
- if (sc != NULL)
- refcnt_rele_wake(&sc->sc_refcnt);
- return (1);
+ refcnt_rele_wake(&sc->sc_refcnt);
+ return (NULL);
}
int
@@ -530,8 +533,6 @@ vlan_up(struct vlan_softc *sc)
/* configure the parent to handle packets for this vlan */
vlan_multi_apply(sc, ifp0, SIOCADDMULTI);
- if_ih_insert(ifp0, vlan_input, NULL);
-
/* we're running now */
SET(ifp->if_flags, IFF_RUNNING);
vlan_link_state(sc, ifp0->if_link_state, ifp0->if_baudrate);
@@ -574,7 +575,6 @@ vlan_down(struct vlan_softc *sc)
ifp0 = if_get(sc->sc_ifidx0);
if (ifp0 != NULL) {
- if_ih_remove(ifp0, vlan_input, NULL);
if (ISSET(sc->sc_flags, IFVF_PROMISC))
ifpromisc(ifp0, 0);
vlan_multi_apply(sc, ifp0, SIOCDELMULTI);
diff --git a/sys/net/if_vlan_var.h b/sys/net/if_vlan_var.h
index 57c7e519f86..006ff2a822c 100644
--- a/sys/net/if_vlan_var.h
+++ b/sys/net/if_vlan_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_vlan_var.h,v 1.41 2019/04/27 04:46:03 dlg Exp $ */
+/* $OpenBSD: if_vlan_var.h,v 1.42 2020/07/22 01:30:54 dlg Exp $ */
/*
* Copyright 1998 Massachusetts Institute of Technology
@@ -47,6 +47,7 @@ struct vlanreq {
};
#ifdef _KERNEL
+struct mbuf *vlan_input(struct ifnet *, struct mbuf *);
struct mbuf *vlan_inject(struct mbuf *, uint16_t, uint16_t);
#endif /* _KERNEL */