Skip to content

Commit 51cefda

Browse files
Mike KarelsMike Karels
authored andcommitted
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.
1 parent 0add2a5 commit 51cefda

File tree

1 file changed

+34
-0
lines changed

1 file changed

+34
-0
lines changed

sys/arm64/broadcom/genet/if_genet.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ __FBSDID("$FreeBSD$");
7676
#include <netinet/in.h>
7777
#include <netinet/ip.h>
7878
#include <netinet/ip6.h>
79+
#define ICMPV6_HACK /* workaround for chip issue */
80+
#ifdef ICMPV6_HACK
81+
#include <netinet/icmp6.h>
82+
#endif
7983

8084
#include "syscon_if.h"
8185
#include "miibus_if.h"
@@ -968,6 +972,36 @@ gen_encap(struct gen_softc *sc, struct mbuf **mp)
968972
q = &sc->tx_queue[DEF_TXQUEUE];
969973

970974
m = *mp;
975+
#ifdef ICMPV6_HACK
976+
/*
977+
* Reflected ICMPv6 packets, e.g. echo replies, tend to get laid
978+
* out with only the Ethernet header in the first mbuf, and this
979+
* doesn't seem to work.
980+
*/
981+
#define ICMP6_LEN (sizeof(struct ether_header) + sizeof(struct ip6_hdr) + \
982+
sizeof(struct icmp6_hdr))
983+
if (m->m_len == sizeof(struct ether_header)) {
984+
int ether_type = mtod(m, struct ether_header *)->ether_type;
985+
if (ntohs(ether_type) == ETHERTYPE_IPV6 &&
986+
m->m_next->m_len >= sizeof(struct ip6_hdr)) {
987+
struct ip6_hdr *ip6;
988+
989+
ip6 = mtod(m->m_next, struct ip6_hdr *);
990+
if (ip6->ip6_nxt == IPPROTO_ICMPV6) {
991+
m = m_pullup(m,
992+
MIN(m->m_pkthdr.len, ICMP6_LEN));
993+
if (m == NULL) {
994+
if (sc->ifp->if_flags & IFF_DEBUG)
995+
device_printf(sc->dev,
996+
"ICMPV6 pullup fail\n");
997+
*mp = NULL;
998+
return (ENOMEM);
999+
}
1000+
}
1001+
}
1002+
}
1003+
#undef ICMP6_LEN
1004+
#endif
9711005
if ((if_getcapenable(sc->ifp) & (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6)) !=
9721006
0) {
9731007
csum_flags = m->m_pkthdr.csum_flags;

0 commit comments

Comments
 (0)