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.
This commit is contained in:
Mike Karels 2020-05-30 02:02:34 +00:00
parent 9628f49377
commit 0add2a5229
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=361641

View File

@ -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);