diff options
author | thompsa <thompsa@FreeBSD.org> | 2007-10-18 21:22:15 +0000 |
---|---|---|
committer | thompsa <thompsa@FreeBSD.org> | 2007-10-18 21:22:15 +0000 |
commit | 8b39a1522c63f12ff9988be210b762ecc4329b2a (patch) | |
tree | 5b7095247627b13df1aa1b8f90b31a0c91b5b994 /sys/net/if_ethersubr.c | |
parent | efafc844b62072341308ddebfc66a3e112f7a2b9 (diff) | |
download | FreeBSD-src-8b39a1522c63f12ff9988be210b762ecc4329b2a.zip FreeBSD-src-8b39a1522c63f12ff9988be210b762ecc4329b2a.tar.gz |
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
Diffstat (limited to 'sys/net/if_ethersubr.c')
-rw-r--r-- | sys/net/if_ethersubr.c | 28 |
1 files changed, 28 insertions, 0 deletions
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); |