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

Reply via email to