|
@@ -36,6 +36,7 @@
|
|
|
#include <net/arp.h>
|
|
|
#include <net/route.h>
|
|
|
#include <net/sock.h>
|
|
|
+#include <net/udp.h>
|
|
|
#include <net/pkt_sched.h>
|
|
|
|
|
|
#include "hyperv_net.h"
|
|
@@ -442,8 +443,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
|
|
|
}
|
|
|
|
|
|
net_trans_info = get_net_transport_info(skb, &hdr_offset);
|
|
|
- if (net_trans_info == TRANSPORT_INFO_NOT_IP)
|
|
|
- goto do_send;
|
|
|
|
|
|
/*
|
|
|
* Setup the sendside checksum offload only if this is not a
|
|
@@ -478,56 +477,29 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
|
|
|
}
|
|
|
lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset;
|
|
|
lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size;
|
|
|
- goto do_send;
|
|
|
- }
|
|
|
-
|
|
|
- if ((skb->ip_summed == CHECKSUM_NONE) ||
|
|
|
- (skb->ip_summed == CHECKSUM_UNNECESSARY))
|
|
|
- goto do_send;
|
|
|
-
|
|
|
- rndis_msg_size += NDIS_CSUM_PPI_SIZE;
|
|
|
- ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE,
|
|
|
- TCPIP_CHKSUM_PKTINFO);
|
|
|
-
|
|
|
- csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi +
|
|
|
- ppi->ppi_offset);
|
|
|
-
|
|
|
- if (net_trans_info & (INFO_IPV4 << 16))
|
|
|
- csum_info->transmit.is_ipv4 = 1;
|
|
|
- else
|
|
|
- csum_info->transmit.is_ipv6 = 1;
|
|
|
-
|
|
|
- if (net_trans_info & INFO_TCP) {
|
|
|
- csum_info->transmit.tcp_checksum = 1;
|
|
|
- csum_info->transmit.tcp_header_offset = hdr_offset;
|
|
|
- } else if (net_trans_info & INFO_UDP) {
|
|
|
- /* UDP checksum offload is not supported on ws2008r2.
|
|
|
- * Furthermore, on ws2012 and ws2012r2, there are some
|
|
|
- * issues with udp checksum offload from Linux guests.
|
|
|
- * (these are host issues).
|
|
|
- * For now compute the checksum here.
|
|
|
- */
|
|
|
- struct udphdr *uh;
|
|
|
- u16 udp_len;
|
|
|
-
|
|
|
- ret = skb_cow_head(skb, 0);
|
|
|
- if (ret)
|
|
|
- goto no_memory;
|
|
|
-
|
|
|
- uh = udp_hdr(skb);
|
|
|
- udp_len = ntohs(uh->len);
|
|
|
- uh->check = 0;
|
|
|
- uh->check = csum_tcpudp_magic(ip_hdr(skb)->saddr,
|
|
|
- ip_hdr(skb)->daddr,
|
|
|
- udp_len, IPPROTO_UDP,
|
|
|
- csum_partial(uh, udp_len, 0));
|
|
|
- if (uh->check == 0)
|
|
|
- uh->check = CSUM_MANGLED_0;
|
|
|
-
|
|
|
- csum_info->transmit.udp_checksum = 0;
|
|
|
+ } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
|
|
+ if (net_trans_info & INFO_TCP) {
|
|
|
+ rndis_msg_size += NDIS_CSUM_PPI_SIZE;
|
|
|
+ ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE,
|
|
|
+ TCPIP_CHKSUM_PKTINFO);
|
|
|
+
|
|
|
+ csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi +
|
|
|
+ ppi->ppi_offset);
|
|
|
+
|
|
|
+ if (net_trans_info & (INFO_IPV4 << 16))
|
|
|
+ csum_info->transmit.is_ipv4 = 1;
|
|
|
+ else
|
|
|
+ csum_info->transmit.is_ipv6 = 1;
|
|
|
+
|
|
|
+ csum_info->transmit.tcp_checksum = 1;
|
|
|
+ csum_info->transmit.tcp_header_offset = hdr_offset;
|
|
|
+ } else {
|
|
|
+ /* UDP checksum (and other) offload is not supported. */
|
|
|
+ if (skb_checksum_help(skb))
|
|
|
+ goto drop;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-do_send:
|
|
|
/* Start filling in the page buffers with the rndis hdr */
|
|
|
rndis_msg->msg_len += rndis_msg_size;
|
|
|
packet->total_data_buflen = rndis_msg->msg_len;
|