diff options
author | csjp <csjp@FreeBSD.org> | 2006-11-18 23:17:22 +0000 |
---|---|---|
committer | csjp <csjp@FreeBSD.org> | 2006-11-18 23:17:22 +0000 |
commit | 5aa5d3eb87ef22b838901d976a898e7826d9032f (patch) | |
tree | 8daa14e003cb59b6b1fab70f6be511048b5bb81d /sys/net/if_ethersubr.c | |
parent | aee58e2da0c688785939850d85b12b57fbb12396 (diff) | |
download | FreeBSD-src-5aa5d3eb87ef22b838901d976a898e7826d9032f.zip FreeBSD-src-5aa5d3eb87ef22b838901d976a898e7826d9032f.tar.gz |
Currently, drivers that support hardware offload of VLAN tag
processing are forced to toggle this functionality when the card
is put in and out of promiscuous mode. The main reason for this
is because the hardware strips the VLAN tag, making it impossible
for the tag information to show up in network diagnostic tools like
tcpdump(1).
This change introduces ether_vlan_mtap(), which is called if the
mbuf has M_VLANTAG set. VLAN information is extracted from the
mbuf and inserted into a stack allocated ether vlan header which
is then inserted through the bpf machinery via bpf_mtap2(). The
original mbuf's data pointer and lengths are temporarily adjusted
to eliminate the original Ethernet header for the duration of the
tap operation. This should have no long term effects on the mbuf.
Also, define a new macro, ETHER_BPF_MTAP which should be used
by drivers which support hardware offload of VLAN tag processing.
The fixes for the relevant drivers will follow shortly.
Discussed with: rwatson, andre, jhb (and others)
Much feedback from: sam, ru
MFC after: 1 month [1]
[1] The version that is eventually MFCed will be somewhat
different then this, as there has been significant work
done to the VLAN code in HEAD.
Diffstat (limited to 'sys/net/if_ethersubr.c')
-rw-r--r-- | sys/net/if_ethersubr.c | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 61fa58b..5a507e3 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -1185,5 +1185,45 @@ static moduledata_t ether_mod = { 0 }; +void +ether_vlan_mtap(struct bpf_if *bp, struct mbuf *m, void *data, u_int dlen) +{ + struct ether_vlan_header vlan; + struct mbuf mv, mb; + + KASSERT((m->m_flags & M_VLANTAG) != 0, + ("%s: vlan information not present", __func__)); + KASSERT(m->m_len >= sizeof(struct ether_header), + ("%s: mbuf not large enough for header", __func__)); + bcopy(mtod(m, char *), &vlan, sizeof(struct ether_header)); + vlan.evl_proto = vlan.evl_encap_proto; + vlan.evl_encap_proto = htons(ETHERTYPE_VLAN); + vlan.evl_tag = htons(m->m_pkthdr.ether_vtag); + m->m_len -= sizeof(struct ether_header); + m->m_data += sizeof(struct ether_header); + /* + * If a data link has been supplied by the caller, then we will need to + * re-create a stack allocated mbuf chain with the following structure: + * + * (1) mbuf #1 will contain the supplied data link + * (2) mbuf #2 will contain the vlan header + * (3) mbuf #3 will contain the original mbuf's packet data + * + * Otherwise, submit the packet and vlan header via bpf_mtap2(). + */ + if (data != NULL) { + mv.m_next = m; + mv.m_data = (caddr_t)&vlan; + mv.m_len = sizeof(vlan); + mb.m_next = &mv; + mb.m_data = data; + mb.m_len = dlen; + bpf_mtap(bp, &mb); + } else + bpf_mtap2(bp, &vlan, sizeof(vlan), m); + m->m_len += sizeof(struct ether_header); + m->m_data -= sizeof(struct ether_header); +} + DECLARE_MODULE(ether, ether_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); MODULE_VERSION(ether, 1); |