diff options
| -rw-r--r-- | drivers/net/hyperv/hyperv_net.h | 1 | ||||
| -rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 26 | ||||
| -rw-r--r-- | drivers/net/hyperv/rndis_filter.c | 12 |
3 files changed, 37 insertions, 2 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_drv.c b/drivers/net/hyperv/netvsc_drv.c index 6f39baa67a5f..31e55fba7cad 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
| @@ -398,7 +398,30 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
| 398 | csum_info->transmit.tcp_checksum = 1; | 398 | csum_info->transmit.tcp_checksum = 1; |
| 399 | csum_info->transmit.tcp_header_offset = hdr_offset; | 399 | csum_info->transmit.tcp_header_offset = hdr_offset; |
| 400 | } else if (net_trans_info & INFO_UDP) { | 400 | } else if (net_trans_info & INFO_UDP) { |
| 401 | 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; | ||
| 402 | } | 425 | } |
| 403 | goto do_send; | 426 | goto do_send; |
| 404 | 427 | ||
| @@ -438,6 +461,7 @@ do_send: | |||
| 438 | 461 | ||
| 439 | ret = netvsc_send(net_device_ctx->device_ctx, packet); | 462 | ret = netvsc_send(net_device_ctx->device_ctx, packet); |
| 440 | 463 | ||
| 464 | drop: | ||
| 441 | if (ret == 0) { | 465 | if (ret == 0) { |
| 442 | net->stats.tx_bytes += skb->len; | 466 | net->stats.tx_bytes += skb->len; |
| 443 | 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 | } |
