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:
parent
9628f49377
commit
0add2a5229
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user