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); _______________________________________________ svn-src-head@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"