Index: if_ix.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_ix.c,v retrieving revision 1.113 diff -u -p -r1.113 if_ix.c --- if_ix.c 22 Dec 2014 02:28:52 -0000 1.113 +++ if_ix.c 2 Jan 2015 03:54:53 -0000 @@ -2035,15 +2049,26 @@ ixgbe_tx_ctx_setup(struct tx_ring *txr, struct ix_softc *sc = txr->sc; struct ixgbe_adv_tx_context_desc *TXD; struct ixgbe_tx_buf *tx_buffer; + union { + struct ether_header eh; #if NVLAN > 0 - struct ether_vlan_header *eh; -#else + struct ether_vlan_header evh; +#endif + struct ip ip; +#ifdef notyet + struct ip6_hdr ip6; +#endif + } hdrs; struct ether_header *eh; +#if NVLAN > 0 + struct ether_vlan_header *evh; #endif struct ip *ip; #ifdef notyet struct ip6_hdr *ip6; #endif + struct mbuf *ipm; + int ipoff; uint32_t vlan_macip_lens = 0, type_tucmd_mlhl = 0; int ehdrlen, ip_hlen = 0; uint16_t etype; @@ -2089,19 +2114,32 @@ ixgbe_tx_ctx_setup(struct tx_ring *txr, * Jump over vlan headers if already present, * helpful for QinQ too. */ -#if NVLAN > 0 - eh = mtod(mp, struct ether_vlan_header *); - if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { - etype = ntohs(eh->evl_proto); - ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; - } else { - etype = ntohs(eh->evl_encap_proto); - ehdrlen = ETHER_HDR_LEN; - } -#else - eh = mtod(mp, struct ether_header *); + if (mp->m_pkthdr.len < sizeof(eh)) + return (1); + + if (mp->m_len < sizeof(*eh)) { + m_copydata(mp, 0, sizeof(hdrs.eh), (caddr_t)&hdrs.eh); + eh = &hdrs.eh; + } else + eh = mtod(mp, struct ether_header *); + etype = ntohs(eh->ether_type); ehdrlen = ETHER_HDR_LEN; + +#if NVLAN > 0 + if (etype == htons(ETHERTYPE_VLAN)) { + if (mp->m_pkthdr.len < sizeof(evh)) + return (1); + + if (mp->m_len < sizeof(*evh)) { + m_copydata(mp, 0, sizeof(hdrs.evh), (caddr_t)&hdrs.evh); + evh = &hdrs.evh; + } else + evh = mtod(mp, struct ether_vlan_header *); + + etype = ntohs(evh->evl_proto); + ehdrlen = sizeof(*evh); + } #endif /* Set the ether header length */ @@ -2109,15 +2147,45 @@ ixgbe_tx_ctx_setup(struct tx_ring *txr, switch (etype) { case ETHERTYPE_IP: - ip = (struct ip *)(mp->m_data + ehdrlen); + if (mp->m_pkthdr.len < ehdrlen + sizeof(ip)) + return (1); + + if (mp->m_len < ehdrlen + sizeof(*ip)) { + ipm = m_getptr(mp, ehdrlen, &ipoff); + KASSERT(ipm != NULL); + + if (ipm->m_len - ipoff < sizeof(*ip)) { + m_copydata(ipm, ipoff, + sizeof(hdrs.ip), (caddr_t)&hdrs.ip); + ip = &hdrs.ip; + } else + ip = (struct ip *)ipm->m_data + ipoff; + } else + ip = (struct ip *)mp->m_data + ehdrlen; + 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); + + if (mp->m_len < ehdrlen + sizeof(*ip6)) { + ipm = m_getptr(mp, ehdrlen, &ipoff); + KASSERT(ipm != NULL); + + if (ipm->m_len - ipoff < sizeof(*ip6)) { + m_copydata(ipm, ipoff, + sizeof(hdrs.ip6), (caddr_t)&hdrs.ip6); + ip6 = &hdrs.ip6; + } else + ip6 = (struct ip6 *)ipm->m_data + ipoff; + } else + ip6 = (struct ip6 *)mp->m_data + ehdrlen; + + 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;