svn commit: r361642 - head/sys/arm64/broadcom/genet

Mike Karels karels at FreeBSD.org
Sat May 30 02:09:37 UTC 2020


Author: karels
Date: Sat May 30 02:09:36 2020
New Revision: 361642
URL: https://svnweb.freebsd.org/changeset/base/361642

Log:
  genet: workaround for problem with ICMPv6 echo replies
  
  The ICMPv6 echo reply is constructed with the IPv6 header too close to
  the beginning of a packet for an Ethernet header to be prepended, so we
  end up with an mbuf containing just the Ethernet header.  The GENET
  controller doesn't seem to handle this, with or without transmit checksum
  offload.  At least until we have chip documentation, do a pullup to
  satisfy the chip.  Hopefully this can be fixed properly in the future.

Modified:
  head/sys/arm64/broadcom/genet/if_genet.c

Modified: head/sys/arm64/broadcom/genet/if_genet.c
==============================================================================
--- head/sys/arm64/broadcom/genet/if_genet.c	Sat May 30 02:02:34 2020	(r361641)
+++ head/sys/arm64/broadcom/genet/if_genet.c	Sat May 30 02:09:36 2020	(r361642)
@@ -76,6 +76,10 @@ __FBSDID("$FreeBSD$");
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <netinet/ip6.h>
+#define ICMPV6_HACK	/* workaround for chip issue */
+#ifdef ICMPV6_HACK
+#include <netinet/icmp6.h>
+#endif
 
 #include "syscon_if.h"
 #include "miibus_if.h"
@@ -968,6 +972,36 @@ gen_encap(struct gen_softc *sc, struct mbuf **mp)
 	q = &sc->tx_queue[DEF_TXQUEUE];
 
 	m = *mp;
+#ifdef ICMPV6_HACK
+	/*
+	 * Reflected ICMPv6 packets, e.g. echo replies, tend to get laid
+	 * out with only the Ethernet header in the first mbuf, and this
+	 * doesn't seem to work.
+	 */
+#define ICMP6_LEN (sizeof(struct ether_header) + sizeof(struct ip6_hdr) + \
+		    sizeof(struct icmp6_hdr))
+	if (m->m_len == sizeof(struct ether_header)) {
+		int ether_type = mtod(m, struct ether_header *)->ether_type;
+		if (ntohs(ether_type) == ETHERTYPE_IPV6 &&
+		    m->m_next->m_len >= sizeof(struct ip6_hdr)) {
+			struct ip6_hdr *ip6;
+
+			ip6 = mtod(m->m_next, struct ip6_hdr *);
+			if (ip6->ip6_nxt == IPPROTO_ICMPV6) {
+				m = m_pullup(m,
+				    MIN(m->m_pkthdr.len, ICMP6_LEN));
+				if (m == NULL) {
+					if (sc->ifp->if_flags & IFF_DEBUG)
+						device_printf(sc->dev,
+						    "ICMPV6 pullup fail\n");
+					*mp = NULL;
+					return (ENOMEM);
+				}
+			}
+		}
+	}
+#undef ICMP6_LEN
+#endif
 	if ((if_getcapenable(sc->ifp) & (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6)) !=
 	    0) {
 		csum_flags = m->m_pkthdr.csum_flags;


More information about the svn-src-head mailing list