diff options
-rw-r--r-- | sys/net/ethernet.h | 1 | ||||
-rw-r--r-- | sys/net/if_bridge.c | 18 | ||||
-rw-r--r-- | sys/net/if_ethersubr.c | 28 | ||||
-rw-r--r-- | sys/net/if_vlan.c | 29 |
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 } /* |