mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-24 07:40:52 +00:00
The bridging output function puts the mbuf directly on the interfaces send
queue so the output network card must support the same tagging mechanism as how the frame was input (prepended Ethernet header tag or stripped HW mflag). Now the vlan Ethernet header is _always_ stripped in ether_input and the mbuf flagged, only only network cards with VLAN_HWTAGGING enabled would properly re-tag any outgoing vlan frames. If the outgoing interface does not support hardware tagging then readd the vlan header to the front of the frame. Move the common vlan encapsulation in to ether_vlanencap(). Reported by: Erik Osterholm, Jon Otterholm MFC after: 1 week
This commit is contained in:
parent
a87abab4b0
commit
60e87ca8df
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=172770
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user