Commit 5b82ac35 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller

[IPV4/IPV6]: Fixup checksums properly when fragmenting.

If we end up with a fraggap, when we copy the data
over to the next frag being built we must compute
a checksum for the bit we copy over for the new
fragment and subtract that checksum from the place
we are copying it from.
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 58b31cc9
......@@ -78,6 +78,7 @@
#include <net/raw.h>
#include <net/checksum.h>
#include <net/inetpeer.h>
#include <net/checksum.h>
#include <linux/igmp.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_bridge.h>
......@@ -892,14 +893,17 @@ int ip_append_data(struct sock *sk,
skb->h.raw = data + exthdrlen;
if (fraggap) {
skb_copy_bits(skb_prev, maxfraglen,
data + transhdrlen, fraggap);
skb->csum = skb_copy_and_csum_bits(
skb_prev, maxfraglen,
data + transhdrlen, fraggap, 0);
skb_prev->csum = csum_block_sub(
skb_prev->csum, skb->csum, 0);
data += fraggap;
skb_trim(skb_prev, maxfraglen);
}
copy = datalen - transhdrlen - fraggap;
if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, 0, skb) < 0) {
if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) {
err = -EFAULT;
kfree_skb(skb);
goto error;
......@@ -1087,8 +1091,11 @@ ssize_t ip_append_page(struct sock *sk, struct page *page,
skb->h.raw = data;
if (fraggap) {
skb_copy_bits(skb_prev, maxfraglen,
data, fraggap);
skb->csum = skb_copy_and_csum_bits(
skb_prev, maxfraglen,
data, fraggap, 0);
skb_prev->csum = csum_block_sub(
skb_prev->csum, skb->csum, 0);
skb_trim(skb_prev, maxfraglen);
}
......
......@@ -54,6 +54,7 @@
#include <net/rawv6.h>
#include <net/icmp.h>
#include <net/xfrm.h>
#include <net/checksum.h>
static int ip6_fragment(struct sk_buff **pskb, int (*output)(struct sk_buff**));
......@@ -981,8 +982,11 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offse
skb->h.raw = data + exthdrlen;
if (fraggap) {
skb_copy_bits(skb_prev, maxfraglen,
data + transhdrlen, fraggap);
skb->csum = skb_copy_and_csum_bits(
skb_prev, maxfraglen,
data + transhdrlen, fraggap, 0);
skb_prev->csum = csum_block_sub(
skb_prev->csum, skb->csum, 0);
data += fraggap;
skb_trim(skb_prev, maxfraglen);
}
......@@ -991,7 +995,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offse
err = -EINVAL;
kfree_skb(skb);
goto error;
} else if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, 0, skb) < 0) {
} else if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) {
err = -EFAULT;
kfree_skb(skb);
goto error;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment