]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - net/ipv4/udp_offload.c
udp: Do not pass checksum as a parameter to GSO segmentation
[linux.git] / net / ipv4 / udp_offload.c
index c1afcd2f1a7656b47c40457a0d3c9976b1c803e3..92c182e99ddc3323bc565c7d15cb7ca13e844fd7 100644 (file)
@@ -188,8 +188,7 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
 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,