Module Name: src Committed By: ryo Date: Tue Oct 5 14:18:18 UTC 2021
Modified Files: src/sys/dev/pci: if_aq.c Log Message: 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(). To generate a diff of this commit: cvs rdiff -u -r1.27 -r1.28 src/sys/dev/pci/if_aq.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/if_aq.c diff -u src/sys/dev/pci/if_aq.c:1.27 src/sys/dev/pci/if_aq.c:1.28 --- src/sys/dev/pci/if_aq.c:1.27 Wed Jun 16 00:21:18 2021 +++ src/sys/dev/pci/if_aq.c Tue Oct 5 14:18:17 2021 @@ -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 @@ struct aq_rxring { 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 @@ aq_rxring_reset(struct aq_softc *sc, str 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 @@ aq_rx_intr(void *arg) 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 @@ aq_rx_intr(void *arg) 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 @@ aq_rx_intr(void *arg) 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 @@ aq_rx_intr(void *arg) * 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 @@ aq_rx_intr(void *arg) 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 @@ aq_rx_intr(void *arg) } 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);