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

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


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

Log:
  genet: fix issues with transmit checksum offload
  
  Fix problem with ICMP echo replies: check only deferred data checksum
  flags, and not the received checksum status bits, when checking whether
  a packet has a deferred checksum; otherwise echo replies are corrupted
  because the received checksum status bits are still present.
  
  Fix some unhandled cases in packet shuffling for checksum offload.

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 01:48:12 2020	(r361640)
+++ head/sys/arm64/broadcom/genet/if_genet.c	Sat May 30 02:02:34 2020	(r361641)
@@ -948,6 +948,9 @@ gen_start(if_t ifp)
 	GEN_UNLOCK(sc);
 }
 
+/* Test for any delayed checksum */
+#define CSUM_DELAY_ANY	(CSUM_TCP | CSUM_UDP | CSUM_IP6_TCP | CSUM_IP6_UDP)
+
 static int
 gen_encap(struct gen_softc *sc, struct mbuf **mp)
 {
@@ -978,12 +981,11 @@ gen_encap(struct gen_softc *sc, struct mbuf **mp)
 		}
 		offset = gen_parse_tx(m, csum_flags);
 		sb = mtod(m, struct statusblock *);
-		if (csum_flags != 0) {
+		if ((csum_flags & CSUM_DELAY_ANY) != 0) {
 			csuminfo = (offset << TXCSUM_OFF_SHIFT) |
 			    (offset + csumdata);
-			if (csum_flags & (CSUM_TCP | CSUM_UDP))
-				csuminfo |= TXCSUM_LEN_VALID;
-			if (csum_flags & CSUM_UDP)
+			csuminfo |= TXCSUM_LEN_VALID;
+			if (csum_flags & (CSUM_UDP | CSUM_IP6_UDP))
 				csuminfo |= TXCSUM_UDP;
 			sb->txcsuminfo = csuminfo;
 		} else
@@ -1045,7 +1047,7 @@ gen_encap(struct gen_softc *sc, struct mbuf **mp)
 		if (i == 0) {
 			length_status |= GENET_TX_DESC_STATUS_SOP |
 			    GENET_TX_DESC_STATUS_CRC;
-			if (csum_flags != 0)
+			if ((csum_flags & CSUM_DELAY_ANY) != 0)
 				length_status |= GENET_TX_DESC_STATUS_CKSUM;
 		}
 		if (i == nsegs - 1)
@@ -1087,6 +1089,7 @@ static int
 gen_parse_tx(struct mbuf *m, int csum_flags)
 {
 	int offset, off_in_m;
+	bool copy = false, shift = false;
 	u_char *p, *copy_p = NULL;
 	struct mbuf *m0 = m;
 	uint16_t ether_type;
@@ -1098,22 +1101,44 @@ gen_parse_tx(struct mbuf *m, int csum_flags)
 		m = m->m_next;
 		off_in_m = 0;
 		p = mtod(m, u_char *);
+		copy = true;
 	} else {
+		/*
+		 * If statusblock is not at beginning of mbuf (likely),
+		 * then remember to move mbuf contents down before copying
+		 * after them.
+		 */
+		if ((m->m_flags & M_EXT) == 0 && m->m_data != m->m_pktdat)
+			shift = true;
 		p = mtodo(m, sizeof(struct statusblock));
 		off_in_m = sizeof(struct statusblock);
 	}
 
-/* If headers need to be copied contiguous to statusblock, do so. */
-#define COPY(size) {						\
-	if (copy_p != NULL) {					\
-		int hsize = size;				\
-		bcopy(p, copy_p, hsize);			\
-		m0->m_len += hsize;				\
-		m0->m_pkthdr.len += hsize;	/* unneeded */	\
-		copy_p += hsize;				\
-		m->m_len -= hsize;				\
-		m->m_data += hsize;				\
-	}							\
+/*
+ * If headers need to be copied contiguous to statusblock, do so.
+ * If copying to the internal mbuf data area, and the status block
+ * is not at the beginning of that area, shift the status block (which
+ * is empty) and following data.
+ */
+#define COPY(size) {							\
+	int hsize = size;						\
+	if (copy) {							\
+		if (shift) {						\
+			u_char *p0;					\
+			shift = false;					\
+			p0 = mtodo(m0, sizeof(struct statusblock));	\
+			m0->m_data = m0->m_pktdat;			\
+			bcopy(p0, mtodo(m0, sizeof(struct statusblock)),\
+			    m0->m_len - sizeof(struct statusblock));	\
+			copy_p = mtodo(m0, sizeof(struct statusblock));	\
+		}							\
+		bcopy(p, copy_p, hsize);				\
+		m0->m_len += hsize;					\
+		m0->m_pkthdr.len += hsize;	/* unneeded */		\
+		m->m_len -= hsize;					\
+		m->m_data += hsize;					\
+	}								\
+	copy_p += hsize;						\
 }
 
 	KASSERT((sizeof(struct statusblock) + sizeof(struct ether_vlan_header) +
@@ -1127,6 +1152,7 @@ gen_parse_tx(struct mbuf *m, int csum_flags)
 			m = m->m_next;
 			off_in_m = 0;
 			p = mtod(m, u_char *);
+			copy = true;
 		} else {
 			off_in_m += sizeof(struct ether_vlan_header);
 			p += sizeof(struct ether_vlan_header);
@@ -1139,6 +1165,7 @@ gen_parse_tx(struct mbuf *m, int csum_flags)
 			m = m->m_next;
 			off_in_m = 0;
 			p = mtod(m, u_char *);
+			copy = true;
 		} else {
 			off_in_m += sizeof(struct ether_header);
 			p += sizeof(struct ether_header);


More information about the svn-src-head mailing list