diff options
-rw-r--r-- | drivers/net/hyperv/hyperv_net.h | 1 | ||||
-rw-r--r-- | drivers/net/hyperv/netvsc.c | 2 | ||||
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 30 | ||||
-rw-r--r-- | drivers/net/hyperv/rndis_filter.c | 12 |
4 files changed, 41 insertions, 4 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 13010b4dae5b..d18f711d0b0c 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h | |||
@@ -747,6 +747,7 @@ struct ndis_oject_header { | |||
747 | #define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4 0 | 747 | #define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4 0 |
748 | #define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6 1 | 748 | #define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6 1 |
749 | 749 | ||
750 | #define VERSION_4_OFFLOAD_SIZE 22 | ||
750 | /* | 751 | /* |
751 | * New offload OIDs for NDIS 6 | 752 | * New offload OIDs for NDIS 6 |
752 | */ | 753 | */ |
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index daddea2654ce..f7629ecefa84 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c | |||
@@ -344,7 +344,7 @@ static int netvsc_connect_vsp(struct hv_device *device) | |||
344 | memset(init_packet, 0, sizeof(struct nvsp_message)); | 344 | memset(init_packet, 0, sizeof(struct nvsp_message)); |
345 | 345 | ||
346 | if (net_device->nvsp_version <= NVSP_PROTOCOL_VERSION_4) | 346 | if (net_device->nvsp_version <= NVSP_PROTOCOL_VERSION_4) |
347 | ndis_version = 0x00050001; | 347 | ndis_version = 0x00060001; |
348 | else | 348 | else |
349 | ndis_version = 0x0006001e; | 349 | ndis_version = 0x0006001e; |
350 | 350 | ||
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++; |
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 4a37e3db9e32..143a98caf618 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c | |||
@@ -641,6 +641,16 @@ int rndis_filter_set_offload_params(struct hv_device *hdev, | |||
641 | struct rndis_set_complete *set_complete; | 641 | struct rndis_set_complete *set_complete; |
642 | u32 extlen = sizeof(struct ndis_offload_params); | 642 | u32 extlen = sizeof(struct ndis_offload_params); |
643 | int ret, t; | 643 | int ret, t; |
644 | u32 vsp_version = nvdev->nvsp_version; | ||
645 | |||
646 | if (vsp_version <= NVSP_PROTOCOL_VERSION_4) { | ||
647 | extlen = VERSION_4_OFFLOAD_SIZE; | ||
648 | /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support | ||
649 | * UDP checksum offload. | ||
650 | */ | ||
651 | req_offloads->udp_ip_v4_csum = 0; | ||
652 | req_offloads->udp_ip_v6_csum = 0; | ||
653 | } | ||
644 | 654 | ||
645 | request = get_rndis_request(rdev, RNDIS_MSG_SET, | 655 | request = get_rndis_request(rdev, RNDIS_MSG_SET, |
646 | RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen); | 656 | RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen); |
@@ -674,7 +684,7 @@ int rndis_filter_set_offload_params(struct hv_device *hdev, | |||
674 | } else { | 684 | } else { |
675 | set_complete = &request->response_msg.msg.set_complete; | 685 | set_complete = &request->response_msg.msg.set_complete; |
676 | if (set_complete->status != RNDIS_STATUS_SUCCESS) { | 686 | if (set_complete->status != RNDIS_STATUS_SUCCESS) { |
677 | netdev_err(ndev, "Fail to set MAC on host side:0x%x\n", | 687 | netdev_err(ndev, "Fail to set offload on host side:0x%x\n", |
678 | set_complete->status); | 688 | set_complete->status); |
679 | ret = -EINVAL; | 689 | ret = -EINVAL; |
680 | } | 690 | } |