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);