Index: head/sys/dev/hyperv/netvsc/if_hn.c =================================================================== --- head/sys/dev/hyperv/netvsc/if_hn.c +++ head/sys/dev/hyperv/netvsc/if_hn.c @@ -727,6 +727,7 @@ ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; else ehlen = ETHER_HDR_LEN; + m_head->m_pkthdr.l2hlen = ehlen; #ifdef INET if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { @@ -736,6 +737,7 @@ PULLUP_HDR(m_head, ehlen + sizeof(*ip)); ip = mtodo(m_head, ehlen); iphlen = ip->ip_hl << 2; + m_head->m_pkthdr.l3hlen = iphlen; PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); th = mtodo(m_head, ehlen + iphlen); @@ -759,6 +761,7 @@ m_freem(m_head); return (NULL); } + m_head->m_pkthdr.l3hlen = sizeof(*ip6); PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th)); th = mtodo(m_head, ehlen + sizeof(*ip6)); @@ -768,41 +771,34 @@ } #endif return (m_head); - } /* * NOTE: If this function failed, the m_head would be freed. */ static __inline struct mbuf * -hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn) +hn_set_hlen(struct mbuf *m_head) { const struct ether_vlan_header *evl; - const struct tcphdr *th; int ehlen; - *tcpsyn = 0; - PULLUP_HDR(m_head, sizeof(*evl)); evl = mtod(m_head, const struct ether_vlan_header *); if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; else ehlen = ETHER_HDR_LEN; + m_head->m_pkthdr.l2hlen = ehlen; #ifdef INET - if (m_head->m_pkthdr.csum_flags & CSUM_IP_TCP) { + if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP_UDP)) { const struct ip *ip; int iphlen; PULLUP_HDR(m_head, ehlen + sizeof(*ip)); ip = mtodo(m_head, ehlen); iphlen = ip->ip_hl << 2; - - PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); - th = mtodo(m_head, ehlen + iphlen); - if (th->th_flags & TH_SYN) - *tcpsyn = 1; + m_head->m_pkthdr.l3hlen = iphlen; } #endif #if defined(INET6) && defined(INET) @@ -814,18 +810,36 @@ PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); ip6 = mtodo(m_head, ehlen); - if (ip6->ip6_nxt != IPPROTO_TCP) - return (m_head); - - PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th)); - th = mtodo(m_head, ehlen + sizeof(*ip6)); - if (th->th_flags & TH_SYN) - *tcpsyn = 1; + if (ip6->ip6_nxt != IPPROTO_TCP) { + m_freem(m_head); + return (NULL); + } + m_head->m_pkthdr.l3hlen = sizeof(*ip6); } #endif return (m_head); } +/* + * NOTE: If this function failed, the m_head would be freed. + */ +static __inline struct mbuf * +hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn) +{ + const struct tcphdr *th; + int ehlen, iphlen; + + *tcpsyn = 0; + ehlen = m_head->m_pkthdr.l2hlen; + iphlen = m_head->m_pkthdr.l3hlen; + + PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); + th = mtodo(m_head, ehlen + iphlen); + if (th->th_flags & TH_SYN) + *tcpsyn = 1; + return (m_head); +} + #undef PULLUP_HDR #endif /* INET6 || INET */ @@ -3010,7 +3024,8 @@ NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO); #ifdef INET if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { - *pi_data = NDIS_LSO2_INFO_MAKEIPV4(0, + *pi_data = NDIS_LSO2_INFO_MAKEIPV4( + m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen, m_head->m_pkthdr.tso_segsz); } #endif @@ -3019,7 +3034,8 @@ #endif #ifdef INET6 { - *pi_data = NDIS_LSO2_INFO_MAKEIPV6(0, + *pi_data = NDIS_LSO2_INFO_MAKEIPV6( + m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen, m_head->m_pkthdr.tso_segsz); } #endif @@ -3036,11 +3052,15 @@ *pi_data |= NDIS_TXCSUM_INFO_IPCS; } - if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP)) - *pi_data |= NDIS_TXCSUM_INFO_TCPCS; - else if (m_head->m_pkthdr.csum_flags & - (CSUM_IP_UDP | CSUM_IP6_UDP)) - *pi_data |= NDIS_TXCSUM_INFO_UDPCS; + if (m_head->m_pkthdr.csum_flags & + (CSUM_IP_TCP | CSUM_IP6_TCP)) { + *pi_data |= NDIS_TXCSUM_INFO_MKTCPCS( + m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen); + } else if (m_head->m_pkthdr.csum_flags & + (CSUM_IP_UDP | CSUM_IP6_UDP)) { + *pi_data |= NDIS_TXCSUM_INFO_MKUDPCS( + m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen); + } } pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen; @@ -5566,6 +5586,13 @@ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); continue; } + } else if (m_head->m_pkthdr.csum_flags & + (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) { + m_head = hn_set_hlen(m_head); + if (__predict_false(m_head == NULL)) { + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + continue; + } } #endif @@ -5846,11 +5873,18 @@ #if defined(INET6) || defined(INET) /* - * Perform TSO packet header fixup now, since the TSO - * packet header should be cache-hot. + * Perform TSO packet header fixup or get l2/l3 header length now, + * since packet headers should be cache-hot. */ if (m->m_pkthdr.csum_flags & CSUM_TSO) { m = hn_tso_fixup(m); + if (__predict_false(m == NULL)) { + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + return EIO; + } + } else if (m->m_pkthdr.csum_flags & + (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) { + m = hn_set_hlen(m); if (__predict_false(m == NULL)) { if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return EIO; Index: head/sys/dev/hyperv/netvsc/ndis.h =================================================================== --- head/sys/dev/hyperv/netvsc/ndis.h +++ head/sys/dev/hyperv/netvsc/ndis.h @@ -402,4 +402,13 @@ #define NDIS_TXCSUM_INFO_IPCS 0x00000010 #define NDIS_TXCSUM_INFO_THOFF 0x03ff0000 +#define NDIS_TXCSUM_INFO_MKL4CS(thoff, flag) \ + ((((uint32_t)(thoff)) << 16) | (flag)) + +#define NDIS_TXCSUM_INFO_MKTCPCS(thoff) \ + NDIS_TXCSUM_INFO_MKL4CS((thoff), NDIS_TXCSUM_INFO_TCPCS) + +#define NDIS_TXCSUM_INFO_MKUDPCS(thoff) \ + NDIS_TXCSUM_INFO_MKL4CS((thoff), NDIS_TXCSUM_INFO_UDPCS) + #endif /* !_NET_NDIS_H_ */