From 348a9615c2bd23ceac38e094a0b4f746d263b572 Mon Sep 17 00:00:00 2001 From: mikeb Date: Mon, 12 Jan 2015 10:40:51 +0000 Subject: [PATCH] When setting up advanced TX descriptor use m_getptr to locate the IP or IPv6 header instead of assuming contiguousness of the target buffer across Ethernet and IP/IPv6 headers. Tested by Kapetanakis Giannis , thanks! Problem analysis and initial diff by dlg@. --- sys/dev/pci/if_ix.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/sys/dev/pci/if_ix.c b/sys/dev/pci/if_ix.c index a69d6e4a63c..8e7a6ebe236 100644 --- a/sys/dev/pci/if_ix.c +++ b/sys/dev/pci/if_ix.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ix.c,v 1.114 2015/01/11 03:06:19 deraadt Exp $ */ +/* $OpenBSD: if_ix.c,v 1.115 2015/01/12 10:40:51 mikeb Exp $ */ /****************************************************************************** @@ -2044,6 +2044,8 @@ ixgbe_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp, #ifdef notyet struct ip6_hdr *ip6; #endif + struct mbuf *m; + int ipoff; uint32_t vlan_macip_lens = 0, type_tucmd_mlhl = 0; int ehdrlen, ip_hlen = 0; uint16_t etype; @@ -2089,9 +2091,13 @@ ixgbe_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp, * Jump over vlan headers if already present, * helpful for QinQ too. */ + if (mp->m_len < sizeof(struct ether_header)) + return (1); #if NVLAN > 0 eh = mtod(mp, struct ether_vlan_header *); if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { + if (mp->m_len < sizeof(struct ether_vlan_header)) + return (1); etype = ntohs(eh->evl_proto); ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; } else { @@ -2109,15 +2115,23 @@ ixgbe_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp, switch (etype) { case ETHERTYPE_IP: - ip = (struct ip *)(mp->m_data + ehdrlen); + if (mp->m_pkthdr.len < ehdrlen + sizeof(*ip)) + return (1); + m = m_getptr(mp, ehdrlen, &ipoff); + KASSERT(m != NULL && m->m_len - ipoff >= sizeof(*ip)); + ip = (struct ip *)(m->m_data + ipoff); ip_hlen = ip->ip_hl << 2; ipproto = ip->ip_p; type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; break; #ifdef notyet case ETHERTYPE_IPV6: - ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen); - ip_hlen = sizeof(struct ip6_hdr); + if (mp->m_pkthdr.len < ehdrlen + sizeof(*ip6)) + return (1); + m = m_getptr(mp, ehdrlen, &ipoff); + KASSERT(m != NULL && m->m_len - ipoff >= sizeof(*ip6)); + ip6 = (struct ip6 *)(m->m_data + ipoff); + ip_hlen = sizeof(*ip6); /* XXX-BZ this will go badly in case of ext hdrs. */ ipproto = ip6->ip6_nxt; type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV6; -- 2.20.1