Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 8 Oct 2004 18:15:15 +0300
From:      Giorgos Keramidas <keramida@freebsd.org>
To:        freebsd-net@freebsd.org
Subject:   Calling m_pullup in ether_input
Message-ID:  <20041008151515.GA3136@orion.daedalusnetworks.priv>

next in thread | raw e-mail | index | archive | help

--CE+1k2dSO48ffgeK
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

In ether_input() we unconditionaly discard the mbufs whose m_len is less than
ETHER_HDR_LEN.  A bit higher M_PKTHDR has been checked but the check made
before discarding the frame doesn't pay attention to the m->m_pkthdr.len (the
total packet length).

I am trying to find out how often this happens, by using the attached patch to
count the number of small frames received in ether_input() and the number of
failed m_pullup() attempts that result from that.

Does this change seem reasonable as an instrumentation  of the particular
problem or am I unknowingly breaking something in the way ether_input() is
supposed to work?

- Giorgos


--CE+1k2dSO48ffgeK
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="ether_input.pullup.patch"

Index: if_ethersubr.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.177
diff -u -u -r1.177 if_ethersubr.c
--- if_ethersubr.c	27 Jul 2004 23:20:45 -0000	1.177
+++ if_ethersubr.c	8 Oct 2004 15:10:40 -0000
@@ -124,6 +124,20 @@
 static int ether_ipfw;
 #endif
 
+static int ether_smallframes;	/* Number of too small input packets. */
+static int ether_pfailed;	/* Failed m_pullup attempts. */
+
+SYSCTL_DECL(_net_link);
+SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet");
+SYSCTL_INT(_net_link_ether, OID_AUTO, smallframes, CTLFLAG_RD,
+	    &ether_smallframes,0,"Number of too small input frames");
+SYSCTL_INT(_net_link_ether, OID_AUTO, pfailed, CTLFLAG_RD,
+	    &ether_pfailed,0,"Number of pkt pullup attempts that failed");
+#if defined(INET) || defined(INET6)
+SYSCTL_INT(_net_link_ether, OID_AUTO, ipfw, CTLFLAG_RW,
+	    &ether_ipfw,0,"Pass ether pkts through firewall");
+#endif
+
 /*
  * Ethernet output routine.
  * Encapsulate a packet of type family for the local net.
@@ -482,6 +496,7 @@
 ether_input(struct ifnet *ifp, struct mbuf *m)
 {
 	struct ether_header *eh;
+	int mlen, plen;
 	u_short etype;
 
 	/*
@@ -494,14 +509,26 @@
 		m_freem(m);
 		return;
 	}
+	/*
+	 * If the first mbuf of the chain doesn't have at least ETHER_HDR_LEN
+	 * bytes check the m->m_pkthdr.len to see if the entire packet holds
+	 * more than ETHER_HDR_LEN data and attempt a pullup if it does.
+	 */
+	mlen = m->m_len;
+	plen = m->m_pkthdr.len;
 	if (m->m_len < ETHER_HDR_LEN) {
-		/* XXX maybe should pullup? */
-		if_printf(ifp, "discard frame w/o leading ethernet "
-				"header (len %u pkt len %u)\n",
-				m->m_len, m->m_pkthdr.len);
-		ifp->if_ierrors++;
-		m_freem(m);
-		return;
+		ether_smallframes++;
+		if (m->m_pkthdr.len < ETHER_HDR_LEN ||
+		    ((m = m_pullup(m, ETHER_HDR_LEN)) == NULL)) {
+			if_printf(ifp, "discard frame w/o leading ethernet "
+			    "header (len %u pkt len %u)\n", mlen, plen);
+			ifp->if_ierrors++;
+			if (m)
+				m_freem(m);
+			else
+				ether_pfailed++;
+			return;
+		}
 	}
 	eh = mtod(m, struct ether_header *);
 	etype = ntohs(eh->ether_type);
@@ -906,13 +933,6 @@
 		bdgtakeifaces_ptr();
 }
 
-SYSCTL_DECL(_net_link);
-SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet");
-#if defined(INET) || defined(INET6)
-SYSCTL_INT(_net_link_ether, OID_AUTO, ipfw, CTLFLAG_RW,
-	    &ether_ipfw,0,"Pass ether pkts through firewall");
-#endif
-
 #if 0
 /*
  * This is for reference.  We have a table-driven version

--CE+1k2dSO48ffgeK--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20041008151515.GA3136>