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/

Reply via email to