so dlg noticed that tcpdump on vlan is now somewhat busted,
specifically dhc* don't work on the any more. the reason is that bpf
now sees the ether_vlan_header instead of the ether_header. only
visible if your NIC does NOT have hw vlan tagging.
reason: while we previously would prepend an ethernet header in
ether_output and way later in vlan_start throw the ethernet header
away again, replacing it by an ether_vlan_header, we now add the
ether_vlan_header in ether_output already. the mtap is in vlan_start,
aka after.
now removing the ether_vlan_header and either prepending a new
ether_header or calling bpf_mtap_ether which adds a fake one didn't
seem too smart. so I made a bpf_mcopy_stripvlan which, well, cuts
those extra 4 bytes out.
the if_ethersubr.c chunk eases testing, it'll make us hit the right
codepath wether the hw has tagging or not. that chunk not to be
committed of course.
Index: net/bpf.c
===================================================================
RCS file: /cvs/src/sys/net/bpf.c,v
retrieving revision 1.97
diff -u -p -r1.97 bpf.c
--- net/bpf.c 9 Jul 2014 13:52:35 -0000 1.97
+++ net/bpf.c 9 Jul 2014 21:30:19 -0000
@@ -90,6 +90,7 @@ void bpf_ifname(struct ifnet *, struct i
void _bpf_mtap(caddr_t, struct mbuf *, u_int,
void (*)(const void *, void *, size_t));
void bpf_mcopy(const void *, void *, size_t);
+void bpf_mcopy_stripvlan(const void *, void *, size_t);
int bpf_movein(struct uio *, u_int, struct mbuf **,
struct sockaddr *, struct bpf_insn *);
void bpf_attachd(struct bpf_d *, struct bpf_if *);
@@ -1169,6 +1170,46 @@ bpf_mcopy(const void *src_arg, void *dst
}
/*
+ * Copy an ethernet frame from an mbuf chain into a buffer, strip the
+ * vlan header bits
+ */
+void
+bpf_mcopy_stripvlan(const void *src_arg, void *dst_arg, size_t len)
+{
+#if NVLAN > 0
+ const struct mbuf *m;
+ u_int count, copied = 0, hdrdone = 0;
+ u_char *dst;
+ struct ether_vlan_header *evh;
+
+ m = src_arg;
+ dst = dst_arg;
+ evh = dst_arg;
+ while (len > 0) {
+ if (m == 0)
+ panic("bpf_mcopy_stripvlan");
+ count = min(m->m_len, len);
+ bcopy(mtod(m, caddr_t), (caddr_t)dst, count);
+ m = m->m_next;
+ dst += count;
+ len -= count;
+ copied += count;
+ if (!hdrdone && copied >= sizeof(struct ether_vlan_header) &&
+ (ntohs(evh->evl_encap_proto) == ETHERTYPE_VLAN ||
+ ntohs(evh->evl_encap_proto) == ETHERTYPE_QINQ)) {
+ /* move up by 4 bytes, overwrite encap_proto + tag */
+ memmove(&evh->evl_encap_proto, &evh->evl_proto, copied -
+ offsetof(struct ether_vlan_header, evl_proto));
+ dst -= (offsetof(struct ether_vlan_header, evl_proto) -
+ offsetof(struct ether_vlan_header,
+ evl_encap_proto)); /* long expression for "4" */
+ hdrdone = 1;
+ }
+ }
+#endif
+}
+
+/*
* like bpf_mtap, but copy fn can be given. used by various bpf_mtap*
*/
void
@@ -1218,6 +1259,13 @@ void
bpf_mtap(caddr_t arg, struct mbuf *m, u_int direction)
{
_bpf_mtap(arg, m, direction, NULL);
+}
+
+/* like bpf_mtap, but strip the vlan header, leave regular ethernet hdr */
+void
+bpf_mtap_stripvlan(caddr_t arg, struct mbuf *m, u_int direction)
+{
+ _bpf_mtap(arg, m, direction, bpf_mcopy_stripvlan);
}
/*
Index: net/bpf.h
===================================================================
RCS file: /cvs/src/sys/net/bpf.h,v
retrieving revision 1.45
diff -u -p -r1.45 bpf.h
--- net/bpf.h 9 Jul 2014 11:03:04 -0000 1.45
+++ net/bpf.h 9 Jul 2014 13:16:31 -0000
@@ -272,6 +272,7 @@ struct bpf_dltlist {
int bpf_validate(struct bpf_insn *, int);
int bpf_tap(caddr_t, u_char *, u_int, u_int);
void bpf_mtap(caddr_t, struct mbuf *, u_int);
+void bpf_mtap_stripvlan(caddr_t, struct mbuf *, u_int);
void bpf_mtap_hdr(caddr_t, caddr_t, u_int, struct mbuf *, u_int,
void (*)(const void *, void *, size_t));
void bpf_mtap_af(caddr_t, u_int32_t, struct mbuf *, u_int);
Index: net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.173
diff -u -p -r1.173 if_ethersubr.c
--- net/if_ethersubr.c 8 Jul 2014 07:10:12 -0000 1.173
+++ net/if_ethersubr.c 9 Jul 2014 14:03:10 -0000
@@ -204,7 +204,7 @@ ether_addheader(struct mbuf **m, struct
struct ifnet *p = ifv->ifv_p;
/* should we use the tx tagging hw offload at all? */
- if ((p->if_capabilities & IFCAP_VLAN_HWTAGGING) &&
+ if (0 && (p->if_capabilities & IFCAP_VLAN_HWTAGGING) &&
(ifv->ifv_type == ETHERTYPE_VLAN)) {
(*m)->m_pkthdr.ether_vtag = ifv->ifv_tag +
((*m)->m_pkthdr.pf.prio << EVL_PRIO_BITS);
Index: net/if_vlan.c
===================================================================
RCS file: /cvs/src/sys/net/if_vlan.c,v
retrieving revision 1.106
diff -u -p -r1.106 if_vlan.c
--- net/if_vlan.c 9 Jul 2014 09:30:49 -0000 1.106
+++ net/if_vlan.c 9 Jul 2014 14:09:43 -0000
@@ -213,7 +213,7 @@ vlan_start(struct ifnet *ifp)
#if NBPFILTER > 0
if (ifp->if_bpf)
- bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+ bpf_mtap_stripvlan(ifp->if_bpf, m, BPF_DIRECTION_OUT);
#endif
/*
--
Henning Brauer, [email protected], [email protected]
BS Web Services GmbH, http://bsws.de, Full-Service ISP
Secure Hosting, Mail and DNS. Virtual & Dedicated Servers, Root to Fully Managed
Henning Brauer Consulting, http://henningbrauer.com/