Merge tag 'platform-drivers-x86-v4.6-1' of git://git.infradead.org/users/dvhart/linux...
[deliverable/linux.git] / net / ipv4 / udp_offload.c
index f5abb1ae1358f974f8024c0599e6c9bdcca5be60..8a3405a8026092f71eb5748c3568e7be24b80cbb 100644 (file)
@@ -40,13 +40,19 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
        __be16 protocol = skb->protocol;
        u16 mac_len = skb->mac_len;
        int udp_offset, outer_hlen;
-       u32 partial;
+       __wsum partial;
 
        if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
                goto out;
 
-       /* adjust partial header checksum to negate old length */
-       partial = (__force u32)uh->check + (__force u16)~uh->len;
+       /* Adjust partial header checksum to negate old length.
+        * We cannot rely on the value contained in uh->len as it is
+        * possible that the actual value exceeds the boundaries of the
+        * 16 bit length field due to the header being added outside of an
+        * IP or IPv6 frame that was already limited to 64K - 1.
+        */
+       partial = csum_sub(csum_unfold(uh->check),
+                          (__force __wsum)htonl(skb->len));
 
        /* setup inner skb. */
        skb->encapsulation = 0;
@@ -119,8 +125,7 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
                if (!need_csum)
                        continue;
 
-               uh->check = ~csum_fold((__force __wsum)
-                                      ((__force u32)len + partial));
+               uh->check = ~csum_fold(csum_add(partial, (__force __wsum)len));
 
                if (skb->encapsulation || !offload_csum) {
                        uh->check = gso_make_checksum(skb, ~uh->check);
This page took 0.038605 seconds and 5 git commands to generate.