Module Name:    src
Committed By:   msaitoh
Date:           Tue Dec 24 05:00:19 UTC 2019

Modified Files:
        src/sys/dev/ic: gem.c

Log Message:
Fix error path in gem(4)'s TX checksum offload.

 - Avoid accessing free'd m0 on error. Use m_freem() instead of m_free().
   Reported by maxv@.
 - Tested by martin@, macallan@ and jdc@.


To generate a diff of this commit:
cvs rdiff -u -r1.123 -r1.124 src/sys/dev/ic/gem.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/ic/gem.c
diff -u src/sys/dev/ic/gem.c:1.123 src/sys/dev/ic/gem.c:1.124
--- src/sys/dev/ic/gem.c:1.123	Wed Dec  4 08:21:43 2019
+++ src/sys/dev/ic/gem.c	Tue Dec 24 05:00:19 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: gem.c,v 1.123 2019/12/04 08:21:43 msaitoh Exp $ */
+/*	$NetBSD: gem.c,v 1.124 2019/12/24 05:00:19 msaitoh Exp $ */
 
 /*
  *
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gem.c,v 1.123 2019/12/04 08:21:43 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gem.c,v 1.124 2019/12/24 05:00:19 msaitoh Exp $");
 
 #include "opt_inet.h"
 
@@ -1388,6 +1388,7 @@ gem_start(struct ifnet *ifp)
 	 * until we drain the queue, or use up all available transmit
 	 * descriptors.
 	 */
+next:
 	while ((txs = SIMPLEQ_FIRST(&sc->sc_txfreeq)) != NULL &&
 	    sc->sc_txfree != 0) {
 		/*
@@ -1497,16 +1498,9 @@ gem_start(struct ifnet *ifp)
 			 * and the checksum stuff if we want the hardware
 			 * to do it.
 			 */
-			sc->sc_txdescs[nexttx].gd_addr =
-			    GEM_DMA_WRITE(sc, dmamap->dm_segs[seg].ds_addr);
 			flags = dmamap->dm_segs[seg].ds_len & GEM_TD_BUFSIZE;
 			if (nexttx == firsttx) {
 				flags |= GEM_TD_START_OF_PACKET;
-				if (++sc->sc_txwin > GEM_NTXSEGS * 2 / 3) {
-					sc->sc_txwin = 0;
-					flags |= GEM_TD_INTERRUPT_ME;
-				}
-
 #ifdef INET
 				/* h/w checksum */
 				if (ifp->if_csum_flags_tx & M_CSUM_TCPv4 &&
@@ -1525,8 +1519,10 @@ gem_start(struct ifnet *ifp)
 						break;
 					default:
 						/* unsupported, drop it */
-						m_free(m0);
-						continue;
+						bus_dmamap_unload(sc->sc_dmatag,
+							dmamap);
+						m_freem(m0);
+						goto next;
 					}
 					start += M_CSUM_DATA_IPv4_IPHL(m0->m_pkthdr.csum_data);
 					offset = M_CSUM_DATA_IPv4_OFFSET(m0->m_pkthdr.csum_data) + start;
@@ -1537,7 +1533,13 @@ gem_start(struct ifnet *ifp)
 						 GEM_TD_CXSUM_ENABLE;
 				}
 #endif
+				if (++sc->sc_txwin > GEM_NTXSEGS * 2 / 3) {
+					sc->sc_txwin = 0;
+					flags |= GEM_TD_INTERRUPT_ME;
+				}
 			}
+			sc->sc_txdescs[nexttx].gd_addr =
+			    GEM_DMA_WRITE(sc, dmamap->dm_segs[seg].ds_addr);
 			if (seg == dmamap->dm_nsegs - 1) {
 				flags |= GEM_TD_END_OF_PACKET;
 			} else {

Reply via email to