DF-4268 / fix_validated.diff
fix.diff — COMBINED validation patch for DF-4267 / DF-4268 / DF-4270 (sys/dev/netif/wb/if_wb.c). Semantically identical to the three seed fix.diffs (regenerated mechanically so the hunks apply; the seed diffs' hunk-count headers were off by one and never applied). Applied only inside the guest's /usr/src for the fix-validation build — never to the audit tree. --- if_wb.c.orig (stock sys/dev/netif/wb/if_wb.c) +++ if_wb.c.fixed (DF-4267 + DF-4268 + DF-4270 fixes) @@ -906,7 +906,7 @@ cd->wb_rx_chain[i].wb_buf = &ld->wb_rxbufs[i]; if (wb_newbuf(sc, &cd->wb_rx_chain[i], NULL) == ENOBUFS) return(ENOBUFS); - nexti = (WB_RX_LIST_CNT - 1) ? 0 : i + 1; + nexti = (i == WB_RX_LIST_CNT - 1) ? 0 : i + 1; cd->wb_rx_chain[i].wb_nextdesc = &cd->wb_rx_chain[nexti]; ld->wb_rx_list[i].wb_next = vtophys(&ld->wb_rx_list[nexti]); } @@ -980,8 +980,8 @@ m = cur_rx->wb_mbuf; if ((rxstat & WB_RXSTAT_MIIERR) || - (WB_RXBYTES(cur_rx->wb_ptr->wb_status) < WB_MIN_FRAMELEN) || - (WB_RXBYTES(cur_rx->wb_ptr->wb_status) > 1536) || + (WB_RXBYTES(rxstat) < WB_MIN_FRAMELEN) || + (WB_RXBYTES(rxstat) > 1536) || (rxstat & WB_RXSTAT_LASTFRAG) == 0|| (rxstat & WB_RXSTAT_RXCMP) == 0) { IFNET_STAT_INC(ifp, ierrors, 1); @@ -1001,7 +1001,7 @@ } /* No errors; receive the packet. */ - total_len = WB_RXBYTES(cur_rx->wb_ptr->wb_status); + total_len = WB_RXBYTES(rxstat); /* * XXX The Winbond chip includes the CRC with every @@ -1324,7 +1324,25 @@ sc->wb_cdata.wb_tx_free = cur_tx->wb_nextdesc; /* Pack the data into the descriptor. */ - wb_encap(sc, cur_tx, m_head); + if (wb_encap(sc, cur_tx, m_head) != 0) { + int fidx; + + /* + * wb_encap() failed (mbuf shortage): free the + * dequeued packet, disarm the partially programmed + * fragments so the NIC never walks the unterminated + * chain, and put the descriptor back on the free + * list. + */ + m_freem(m_head); + cur_tx->wb_mbuf = NULL; + for (fidx = 0; fidx < WB_MAXFRAGS; fidx++) + cur_tx->wb_ptr->wb_frag[fidx].wb_status = 0; + sc->wb_cdata.wb_tx_free = cur_tx; + if (cur_tx == start_tx) + return; /* nothing was queued */ + break; + } if (cur_tx != start_tx) WB_TXOWN(cur_tx) = WB_TXSTAT_OWN; |