diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/udp.c | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 0b24508bcdc4..74d2c95db57f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -2337,7 +2337,7 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, | |||
2337 | uh->len = htons(skb->len - udp_offset); | 2337 | uh->len = htons(skb->len - udp_offset); |
2338 | 2338 | ||
2339 | /* csum segment if tunnel sets skb with csum. */ | 2339 | /* csum segment if tunnel sets skb with csum. */ |
2340 | if (unlikely(uh->check)) { | 2340 | if (protocol == htons(ETH_P_IP) && unlikely(uh->check)) { |
2341 | struct iphdr *iph = ip_hdr(skb); | 2341 | struct iphdr *iph = ip_hdr(skb); |
2342 | 2342 | ||
2343 | uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, | 2343 | uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, |
@@ -2348,7 +2348,18 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, | |||
2348 | if (uh->check == 0) | 2348 | if (uh->check == 0) |
2349 | uh->check = CSUM_MANGLED_0; | 2349 | uh->check = CSUM_MANGLED_0; |
2350 | 2350 | ||
2351 | } else if (protocol == htons(ETH_P_IPV6)) { | ||
2352 | struct ipv6hdr *ipv6h = ipv6_hdr(skb); | ||
2353 | u32 len = skb->len - udp_offset; | ||
2354 | |||
2355 | uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, | ||
2356 | len, IPPROTO_UDP, 0); | ||
2357 | uh->check = csum_fold(skb_checksum(skb, udp_offset, len, 0)); | ||
2358 | if (uh->check == 0) | ||
2359 | uh->check = CSUM_MANGLED_0; | ||
2360 | skb->ip_summed = CHECKSUM_NONE; | ||
2351 | } | 2361 | } |
2362 | |||
2352 | skb->protocol = protocol; | 2363 | skb->protocol = protocol; |
2353 | } while ((skb = skb->next)); | 2364 | } while ((skb = skb->next)); |
2354 | out: | 2365 | out: |