summaryrefslogtreecommitdiff
path: root/net/ipv4/udp_offload.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/udp_offload.c')
-rw-r--r--net/ipv4/udp_offload.c32
1 files changed, 18 insertions, 14 deletions
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index c1afcd2f1a76..92c182e99ddc 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -188,8 +188,7 @@ out_unlock:
EXPORT_SYMBOL(skb_udp_tunnel_segment);
struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
- netdev_features_t features,
- __sum16 check)
+ netdev_features_t features)
{
struct sock *sk = gso_skb->sk;
unsigned int sum_truesize = 0;
@@ -197,6 +196,8 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
unsigned int hdrlen;
struct udphdr *uh;
unsigned int mss;
+ __sum16 check;
+ __be16 newlen;
mss = skb_shinfo(gso_skb)->gso_size;
if (gso_skb->len <= sizeof(*uh) + mss)
@@ -215,17 +216,25 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
return segs;
}
+ uh = udp_hdr(segs);
+
+ /* compute checksum adjustment based on old length versus new */
+ newlen = htons(sizeof(*uh) + mss);
+ check = csum16_add(csum16_sub(uh->check, uh->len), newlen);
+
for (seg = segs; seg; seg = seg->next) {
uh = udp_hdr(seg);
- uh->len = htons(seg->len - hdrlen);
- uh->check = check;
/* last packet can be partial gso_size */
- if (!seg->next)
- csum_replace2(&uh->check, htons(mss),
- htons(seg->len - hdrlen - sizeof(*uh)));
+ if (!seg->next) {
+ newlen = htons(seg->len - hdrlen);
+ check = csum16_add(csum16_sub(uh->check, uh->len),
+ newlen);
+ }
+
+ uh->len = newlen;
+ uh->check = check;
- uh->check = ~uh->check;
seg->destructor = sock_wfree;
seg->sk = sk;
sum_truesize += seg->truesize;
@@ -240,15 +249,10 @@ EXPORT_SYMBOL_GPL(__udp_gso_segment);
static struct sk_buff *__udp4_gso_segment(struct sk_buff *gso_skb,
netdev_features_t features)
{
- const struct iphdr *iph = ip_hdr(gso_skb);
- unsigned int mss = skb_shinfo(gso_skb)->gso_size;
-
if (!can_checksum_protocol(features, htons(ETH_P_IP)))
return ERR_PTR(-EIO);
- return __udp_gso_segment(gso_skb, features,
- udp_v4_check(sizeof(struct udphdr) + mss,
- iph->saddr, iph->daddr, 0));
+ return __udp_gso_segment(gso_skb, features);
}
static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,