diff options
Diffstat (limited to 'drivers/net/hyperv/netvsc_drv.c')
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 4e4cf9e0c8d7..31e55fba7cad 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
@@ -319,7 +319,9 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
319 | packet = kzalloc(sizeof(struct hv_netvsc_packet) + | 319 | packet = kzalloc(sizeof(struct hv_netvsc_packet) + |
320 | (num_data_pgs * sizeof(struct hv_page_buffer)) + | 320 | (num_data_pgs * sizeof(struct hv_page_buffer)) + |
321 | sizeof(struct rndis_message) + | 321 | sizeof(struct rndis_message) + |
322 | NDIS_VLAN_PPI_SIZE, GFP_ATOMIC); | 322 | NDIS_VLAN_PPI_SIZE + |
323 | NDIS_CSUM_PPI_SIZE + | ||
324 | NDIS_LSO_PPI_SIZE, GFP_ATOMIC); | ||
323 | if (!packet) { | 325 | if (!packet) { |
324 | /* out of memory, drop packet */ | 326 | /* out of memory, drop packet */ |
325 | netdev_err(net, "unable to allocate hv_netvsc_packet\n"); | 327 | netdev_err(net, "unable to allocate hv_netvsc_packet\n"); |
@@ -396,7 +398,30 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
396 | csum_info->transmit.tcp_checksum = 1; | 398 | csum_info->transmit.tcp_checksum = 1; |
397 | csum_info->transmit.tcp_header_offset = hdr_offset; | 399 | csum_info->transmit.tcp_header_offset = hdr_offset; |
398 | } else if (net_trans_info & INFO_UDP) { | 400 | } else if (net_trans_info & INFO_UDP) { |
399 | csum_info->transmit.udp_checksum = 1; | 401 | /* UDP checksum offload is not supported on ws2008r2. |
402 | * Furthermore, on ws2012 and ws2012r2, there are some | ||
403 | * issues with udp checksum offload from Linux guests. | ||
404 | * (these are host issues). | ||
405 | * For now compute the checksum here. | ||
406 | */ | ||
407 | struct udphdr *uh; | ||
408 | u16 udp_len; | ||
409 | |||
410 | ret = skb_cow_head(skb, 0); | ||
411 | if (ret) | ||
412 | goto drop; | ||
413 | |||
414 | uh = udp_hdr(skb); | ||
415 | udp_len = ntohs(uh->len); | ||
416 | uh->check = 0; | ||
417 | uh->check = csum_tcpudp_magic(ip_hdr(skb)->saddr, | ||
418 | ip_hdr(skb)->daddr, | ||
419 | udp_len, IPPROTO_UDP, | ||
420 | csum_partial(uh, udp_len, 0)); | ||
421 | if (uh->check == 0) | ||
422 | uh->check = CSUM_MANGLED_0; | ||
423 | |||
424 | csum_info->transmit.udp_checksum = 0; | ||
400 | } | 425 | } |
401 | goto do_send; | 426 | goto do_send; |
402 | 427 | ||
@@ -436,6 +461,7 @@ do_send: | |||
436 | 461 | ||
437 | ret = netvsc_send(net_device_ctx->device_ctx, packet); | 462 | ret = netvsc_send(net_device_ctx->device_ctx, packet); |
438 | 463 | ||
464 | drop: | ||
439 | if (ret == 0) { | 465 | if (ret == 0) { |
440 | net->stats.tx_bytes += skb->len; | 466 | net->stats.tx_bytes += skb->len; |
441 | net->stats.tx_packets++; | 467 | net->stats.tx_packets++; |