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-all
mailing list