Merge tag 'spi-fix-v4.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
[cascardo/linux.git] / drivers / net / hyperv / netvsc_drv.c
index 52eeb2f..f638215 100644 (file)
@@ -442,14 +442,12 @@ 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
         * GSO packet.
         */
-       if (skb_is_gso(skb)) {
+       if ((net_trans_info & (INFO_TCP | INFO_UDP)) && skb_is_gso(skb)) {
                struct ndis_tcp_lso_info *lso_info;
 
                rndis_msg_size += NDIS_LSO_PPI_SIZE;
@@ -478,56 +476,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;
@@ -636,15 +607,18 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
               packet->total_data_buflen);
 
        skb->protocol = eth_type_trans(skb, net);
-       if (csum_info) {
-               /* We only look at the IP checksum here.
-                * Should we be dropping the packet if checksum
-                * failed? How do we deal with other checksums - TCP/UDP?
-                */
-               if (csum_info->receive.ip_checksum_succeeded)
+
+       /* skb is already created with CHECKSUM_NONE */
+       skb_checksum_none_assert(skb);
+
+       /*
+        * In Linux, the IP checksum is always checked.
+        * Do L4 checksum offload if enabled and present.
+        */
+       if (csum_info && (net->features & NETIF_F_RXCSUM)) {
+               if (csum_info->receive.tcp_checksum_succeeded ||
+                   csum_info->receive.udp_checksum_succeeded)
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
-               else
-                       skb->ip_summed = CHECKSUM_NONE;
        }
 
        if (vlan_tci & VLAN_TAG_PRESENT)
@@ -725,12 +699,8 @@ int netvsc_recv_callback(struct hv_device *device_obj,
 static void netvsc_get_drvinfo(struct net_device *net,
                               struct ethtool_drvinfo *info)
 {
-       struct net_device_context *net_device_ctx = netdev_priv(net);
-       struct hv_device *dev = net_device_ctx->device_ctx;
-
        strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
        strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
-       strlcpy(info->bus_info, vmbus_dev_name(dev), sizeof(info->bus_info));
 }
 
 static void netvsc_get_channels(struct net_device *net,