svn commit: r209959 - head/sys/dev/e1000
Jack F Vogel
jfv at FreeBSD.org
Mon Jul 12 21:47:31 UTC 2010
Author: jfv
Date: Mon Jul 12 21:47:30 2010
New Revision: 209959
URL: http://svn.freebsd.org/changeset/base/209959
Log:
Fix for a panic when TX checksum offload is done and
a packet has only a header in the first mbuf, the
checksum code will dereference a pointer into the
non-existing IP header. Do a check for the size and
pullup if needed. Thanks to Michael Tuexen for this
fix.
MFC: asap - should be in 8.1 IMHO
Modified:
head/sys/dev/e1000/if_em.c
head/sys/dev/e1000/if_lem.c
Modified: head/sys/dev/e1000/if_em.c
==============================================================================
--- head/sys/dev/e1000/if_em.c Mon Jul 12 21:09:55 2010 (r209958)
+++ head/sys/dev/e1000/if_em.c Mon Jul 12 21:47:30 2010 (r209959)
@@ -1738,6 +1738,19 @@ em_xmit(struct tx_ring *txr, struct mbuf
do_tso = ((m_head->m_pkthdr.csum_flags & CSUM_TSO) != 0);
/*
+ ** When doing checksum offload, it is critical to
+ ** make sure the first mbuf has more than header,
+ ** because that routine expects data to be present.
+ */
+ if ((m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) &&
+ (m_head->m_len < ETHER_HDR_LEN + sizeof(struct ip))) {
+ m_head = m_pullup(m_head, ETHER_HDR_LEN + sizeof(struct ip));
+ *m_headp = m_head;
+ if (m_head == NULL)
+ return (ENOBUFS);
+ }
+
+ /*
* TSO workaround:
* If an mbuf is only header we need
* to pull 4 bytes of data into it.
@@ -3262,6 +3275,7 @@ em_transmit_checksum_setup(struct tx_rin
cmd = hdr_len = ipproto = 0;
+ *txd_upper = *txd_lower = 0;
cur = txr->next_avail_desc;
/*
@@ -3305,29 +3319,21 @@ em_transmit_checksum_setup(struct tx_rin
*txd_upper |= E1000_TXD_POPTS_IXSM << 8;
}
- if (mp->m_len < ehdrlen + ip_hlen)
- return; /* failure */
-
hdr_len = ehdrlen + ip_hlen;
ipproto = ip->ip_p;
-
break;
+
case ETHERTYPE_IPV6:
ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
ip_hlen = sizeof(struct ip6_hdr); /* XXX: No header stacking. */
- if (mp->m_len < ehdrlen + ip_hlen)
- return; /* failure */
-
/* IPv6 doesn't have a header checksum. */
hdr_len = ehdrlen + ip_hlen;
ipproto = ip6->ip6_nxt;
-
break;
+
default:
- *txd_upper = 0;
- *txd_lower = 0;
return;
}
@@ -3381,6 +3387,8 @@ em_transmit_checksum_setup(struct tx_rin
break;
}
+ if (TXD == NULL)
+ return;
TXD->tcp_seg_setup.data = htole32(0);
TXD->cmd_and_length =
htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT | cmd);
Modified: head/sys/dev/e1000/if_lem.c
==============================================================================
--- head/sys/dev/e1000/if_lem.c Mon Jul 12 21:09:55 2010 (r209958)
+++ head/sys/dev/e1000/if_lem.c Mon Jul 12 21:47:30 2010 (r209959)
@@ -1566,6 +1566,19 @@ lem_xmit(struct adapter *adapter, struct
}
/*
+ ** When doing checksum offload, it is critical to
+ ** make sure the first mbuf has more than header,
+ ** because that routine expects data to be present.
+ */
+ if ((m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) &&
+ (m_head->m_len < ETHER_HDR_LEN + sizeof(struct ip))) {
+ m_head = m_pullup(m_head, ETHER_HDR_LEN + sizeof(struct ip));
+ *m_headp = m_head;
+ if (m_head == NULL)
+ return (ENOBUFS);
+ }
+
+ /*
* Map the packet for DMA
*
* Capture the first descriptor index,
@@ -2851,6 +2864,7 @@ lem_transmit_checksum_setup(struct adapt
cmd = hdr_len = ipproto = 0;
+ *txd_upper = *txd_lower = 0;
curr_txd = adapter->next_avail_tx_desc;
/*
@@ -2894,9 +2908,6 @@ lem_transmit_checksum_setup(struct adapt
*txd_upper |= E1000_TXD_POPTS_IXSM << 8;
}
- if (mp->m_len < ehdrlen + ip_hlen)
- return; /* failure */
-
hdr_len = ehdrlen + ip_hlen;
ipproto = ip->ip_p;
@@ -2905,18 +2916,13 @@ lem_transmit_checksum_setup(struct adapt
ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
ip_hlen = sizeof(struct ip6_hdr); /* XXX: No header stacking. */
- if (mp->m_len < ehdrlen + ip_hlen)
- return; /* failure */
-
/* IPv6 doesn't have a header checksum. */
hdr_len = ehdrlen + ip_hlen;
ipproto = ip6->ip6_nxt;
-
break;
+
default:
- *txd_upper = 0;
- *txd_lower = 0;
return;
}
@@ -2970,6 +2976,8 @@ lem_transmit_checksum_setup(struct adapt
break;
}
+ if (TXD == NULL)
+ return;
TXD->tcp_seg_setup.data = htole32(0);
TXD->cmd_and_length =
htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT | cmd);
More information about the svn-src-head
mailing list