Subject: kern/28339: M_HASFCS not honored in bpf(4)
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Thilo Manske <Thilo.Manske@HEH.Uni-Oldenburg.DE>
List: netbsd-bugs
Date: 11/17/2004 08:56:02
>Number:         28339
>Category:       kern
>Synopsis:       M_HASFCS not honored in bpf(4)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Nov 17 08:56:00 +0000 2004
>Originator:     Thilo Manske
>Release:        NetBSD 2.99.10 and below
>Organization:
>Environment:
System: NetBSD Voigt 2.99.10 NetBSD 2.99.10 (Voigt) #69: Sat Nov 13 14:17:08 MET 2004 root@Voigt:/sys/arch/i386/compile/Voigt i386
Architecture: <all>
Machine: <all>
>Description:

Some ethernet network drivers (bce,sip,rtk,vr,wm..) deliver frames including
the 4 byte CRC sum at the end of the buffer, some don't (de, epic, ex, txp,
..) Drivers set the M_LINK0 (=M_HASFCS) flag according to that, but the flag
is neither honored nor passed to the next layer by bpf(4)

>How-To-Repeat:
- tcpdump ping traffic and notice received frames being 4 bytes larger
- use ethereal with tcpdumps taken from different interfaces
- watch dhclient complain like this:
	"ip length 328 disagrees with bytes received 332"
>Fix:
This is a simple patch/workaround, it works with drivers
using bpf_mtap() (tested with rtk(4)). For drivers using bpf_mtap2() a
very similar piece of code could be used, but there's no way for me to test
it, so I left it out.

Index: bpf.c
===================================================================
RCS file: /cvsroot/src/sys/net/bpf.c,v
retrieving revision 1.104
diff -c -u -r1.104 bpf.c
--- bpf.c	19 Aug 2004 20:58:23 -0000	1.104
+++ bpf.c	17 Nov 2004 08:42:25 -0000
@@ -1271,12 +1271,32 @@
 {
 	void *(*cpfn)(void *, const void *, size_t);
 	struct bpf_if *bp = arg;
-	u_int pktlen, buflen;
+	u_int frmlen, pktlen, buflen;
 	void *marg;
 
-	pktlen = m_length(m);
+	frmlen = pktlen = m_length(m);
+	/* 
+	 * try to find out if the mbuf is comming from an ethernet interface,
+	 * since M_LINK0 (M_HASFCS) meaning depends on the type of the interface
+	 */
+	if (m->m_pkthdr.rcvif != NULL)
+	{
+		switch (m->m_pkthdr.rcvif->if_dlt)
+		{
+			case DLT_EN10MB:
+			case DLT_EN3MB:
+			case DLT_IEEE802:
+			case DLT_IEEE802_11:
+			case DLT_IEEE802_11_RADIO:
+				if (m->m_flags & M_HASFCS)
+					pktlen-=ETHER_CRC_LEN;
+				break;
+			default:
+				break;
+		}
+	}
 
-	if (pktlen == m->m_len) {
+	if (frmlen == m->m_len) {
 		cpfn = memcpy;
 		marg = mtod(m, void *);
 		buflen = pktlen;