Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci fix a panic "m_verify_packet: inconsistent mbuf ...



details:   https://anonhg.NetBSD.org/src/rev/fdddf0cf1024
branches:  trunk
changeset: 988246:fdddf0cf1024
user:      ryo <ryo%NetBSD.org@localhost>
date:      Tue Oct 05 14:18:17 2021 +0000

description:
fix a panic "m_verify_packet: inconsistent mbuf length" on aq(4).

- If mbuf cannot be allocated or some errors occur when receiving a jumboframe,
  it is necessary to free mbuf chains of the packet being received, and ignore
  the subsequent segments that make up the packet.
- Even if aq_rx_intr() is completed in the middle of the jumboframe
  reception process, it will resume normally at the next aq_rx_intr().

diffstat:

 sys/dev/pci/if_aq.c |  47 +++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 43 insertions(+), 4 deletions(-)

diffs (126 lines):

diff -r 5ee5017255c9 -r fdddf0cf1024 sys/dev/pci/if_aq.c
--- a/sys/dev/pci/if_aq.c       Tue Oct 05 11:01:49 2021 +0000
+++ b/sys/dev/pci/if_aq.c       Tue Oct 05 14:18:17 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_aq.c,v 1.27 2021/06/16 00:21:18 riastradh Exp $     */
+/*     $NetBSD: if_aq.c,v 1.28 2021/10/05 14:18:17 ryo Exp $   */
 
 /**
  * aQuantia Corporation Network Driver
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_aq.c,v 1.27 2021/06/16 00:21:18 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_aq.c,v 1.28 2021/10/05 14:18:17 ryo Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_if_aq.h"
@@ -877,6 +877,9 @@
        int rxr_index;
        kmutex_t rxr_mutex;
        bool rxr_active;
+       bool rxr_discarding;
+       struct mbuf *rxr_receiving_m;           /* receiving jumboframe */
+       struct mbuf *rxr_receiving_m_last;      /* last mbuf of jumboframe */
 
        aq_rx_desc_t *rxr_rxdesc;       /* aq_rx_desc_t[AQ_RXD_NUM] */
        bus_dmamap_t rxr_rxdesc_dmamap;
@@ -4009,6 +4012,12 @@
 
        mutex_enter(&rxring->rxr_mutex);
        rxring->rxr_active = false;
+       rxring->rxr_discarding = false;
+       if (rxring->rxr_receiving_m != NULL) {
+               m_freem(rxring->rxr_receiving_m);
+               rxring->rxr_receiving_m = NULL;
+               rxring->rxr_receiving_m_last = NULL;
+       }
 
        /* disable DMA */
        AQ_WRITE_REG_BIT(sc, RX_DMA_DESC_REG(ringidx), RX_DMA_DESC_EN, 0);
@@ -4268,6 +4277,7 @@
        uint16_t rxd_status, rxd_pktlen;
        uint16_t rxd_nextdescptr __unused, rxd_vlan __unused;
        unsigned int idx, n = 0;
+       bool discarding;
 
        mutex_enter(&rxring->rxr_mutex);
 
@@ -4281,7 +4291,11 @@
 
        net_stat_ref_t nsr = IF_STAT_GETREF(ifp);
 
-       m0 = mprev = NULL;
+       /* restore ring context */
+       discarding = rxring->rxr_discarding;
+       m0 = rxring->rxr_receiving_m;
+       mprev = rxring->rxr_receiving_m_last;
+
        for (idx = rxring->rxr_readidx;
            idx != AQ_READ_REG_BIT(sc, RX_DMA_DESC_HEAD_PTR_REG(ringidx),
            RX_DMA_DESC_HEAD_PTR); idx = RXRING_NEXTIDX(idx), n++) {
@@ -4302,9 +4316,21 @@
                rxd_hash = le32toh(rxd->wb.rss_hash);
                rxd_vlan = le16toh(rxd->wb.vlan);
 
+               /*
+                * Some segments are being dropped while receiving jumboframe.
+                * Discard until EOP.
+                */
+               if (discarding)
+                       goto rx_next;
+
                if ((rxd_status & RXDESC_STATUS_MACERR) ||
                    (rxd_type & RXDESC_TYPE_MAC_DMA_ERR)) {
                        if_statinc_ref(nsr, if_ierrors);
+                       if (m0 != NULL) {
+                               m_freem(m0);
+                               m0 = mprev = NULL;
+                       }
+                       discarding = true;
                        goto rx_next;
                }
 
@@ -4320,6 +4346,11 @@
                         * discard this packet, and reuse mbuf for next.
                         */
                        if_statinc_ref(nsr, if_iqdrops);
+                       if (m0 != NULL) {
+                               m_freem(m0);
+                               m0 = mprev = NULL;
+                       }
+                       discarding = true;
                        goto rx_next;
                }
                rxring->rxr_mbufs[idx].m = NULL;
@@ -4335,9 +4366,10 @@
                mprev = m;
 
                if ((rxd_status & RXDESC_STATUS_EOP) == 0) {
+                       /* to be continued in the next segment */
                        m->m_len = MCLBYTES;
                } else {
-                       /* last buffer */
+                       /* the last segment */
                        int mlen = rxd_pktlen % MCLBYTES;
                        if (mlen == 0)
                                mlen = MCLBYTES;
@@ -4431,10 +4463,17 @@
                }
 
  rx_next:
+               if (discarding && (rxd_status & RXDESC_STATUS_EOP) != 0)
+                       discarding = false;
+
                aq_rxring_reset_desc(sc, rxring, idx);
                AQ_WRITE_REG(sc, RX_DMA_DESC_TAIL_PTR_REG(ringidx), idx);
        }
+       /* save ring context */
        rxring->rxr_readidx = idx;
+       rxring->rxr_discarding = discarding;
+       rxring->rxr_receiving_m = m0;
+       rxring->rxr_receiving_m_last = mprev;
 
        IF_STAT_PUTREF(ifp);
 



Home | Main Index | Thread Index | Old Index