summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/net/ethernet.h1
-rw-r--r--sys/net/if_bridge.c18
-rw-r--r--sys/net/if_ethersubr.c28
-rw-r--r--sys/net/if_vlan.c29
4 files changed, 47 insertions, 29 deletions
diff --git a/sys/net/ethernet.h b/sys/net/ethernet.h
index 29a5316..c5b6118 100644
--- a/sys/net/ethernet.h
+++ b/sys/net/ethernet.h
@@ -386,6 +386,7 @@ extern int ether_output_frame(struct ifnet *, struct mbuf *);
extern char *ether_sprintf(const u_int8_t *);
void ether_vlan_mtap(struct bpf_if *, struct mbuf *,
void *, u_int);
+struct mbuf *ether_vlanencap(struct mbuf *, int);
#else /* _KERNEL */
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index e464d96..f29063d 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -1653,7 +1653,23 @@ bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m)
for (; m; m = m0) {
m0 = m->m_nextpkt;
m->m_nextpkt = NULL;
-
+
+ /*
+ * If underlying interface can not do VLAN tag insertion itself
+ * then attach a packet tag that holds it.
+ */
+ if ((m->m_flags & M_VLANTAG) &&
+ (dst_ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) {
+ m = ether_vlanencap(m, m->m_pkthdr.ether_vtag);
+ if (m == NULL) {
+ if_printf(dst_ifp,
+ "unable to prepend VLAN header\n");
+ dst_ifp->if_oerrors++;
+ continue;
+ }
+ m->m_flags &= ~M_VLANTAG;
+ }
+
if (err == 0)
IFQ_ENQUEUE(&dst_ifp->if_snd, m, err);
}
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 53e9b64..9509eb5 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -1249,5 +1249,33 @@ ether_vlan_mtap(struct bpf_if *bp, struct mbuf *m, void *data, u_int dlen)
m->m_data -= sizeof(struct ether_header);
}
+struct mbuf *
+ether_vlanencap(struct mbuf *m, int tag)
+{
+ struct ether_vlan_header *evl;
+
+ M_PREPEND(m, ETHER_VLAN_ENCAP_LEN, M_DONTWAIT);
+ if (m == NULL)
+ return (NULL);
+ /* M_PREPEND takes care of m_len, m_pkthdr.len for us */
+
+ if (m->m_len < sizeof(*evl)) {
+ m = m_pullup(m, sizeof(*evl));
+ if (m == NULL)
+ return (NULL);
+ }
+
+ /*
+ * Transform the Ethernet header into an Ethernet header
+ * with 802.1Q encapsulation.
+ */
+ evl = mtod(m, struct ether_vlan_header *);
+ bcopy((char *)evl + ETHER_VLAN_ENCAP_LEN,
+ (char *)evl, ETHER_HDR_LEN - ETHER_TYPE_LEN);
+ evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
+ evl->evl_tag = htons(tag);
+ return (m);
+}
+
DECLARE_MODULE(ether, ether_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
MODULE_VERSION(ether, 1);
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index 8fb7a1f..6cce6e9 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -850,40 +850,13 @@ vlan_start(struct ifnet *ifp)
m->m_pkthdr.ether_vtag = ifv->ifv_tag;
m->m_flags |= M_VLANTAG;
} else {
- struct ether_vlan_header *evl;
-
- M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
+ m = ether_vlanencap(m, ifv->ifv_tag);
if (m == NULL) {
if_printf(ifp,
"unable to prepend VLAN header\n");
ifp->if_oerrors++;
continue;
}
- /* M_PREPEND takes care of m_len, m_pkthdr.len for us */
-
- if (m->m_len < sizeof(*evl)) {
- m = m_pullup(m, sizeof(*evl));
- if (m == NULL) {
- if_printf(ifp,
- "cannot pullup VLAN header\n");
- ifp->if_oerrors++;
- continue;
- }
- }
-
- /*
- * Transform the Ethernet header into an Ethernet header
- * with 802.1Q encapsulation.
- */
- evl = mtod(m, struct ether_vlan_header *);
- bcopy((char *)evl + ifv->ifv_encaplen,
- (char *)evl, ETHER_HDR_LEN - ETHER_TYPE_LEN);
- evl->evl_encap_proto = htons(ifv->ifv_proto);
- evl->evl_tag = htons(ifv->ifv_tag);
-#ifdef DEBUG
- printf("%s: %*D\n", __func__, (int)sizeof(*evl),
- (unsigned char *)evl, ":");
-#endif
}
/*
OpenPOWER on IntegriCloud