datapath: Don't compute checksums on partial packets.
[sliver-openvswitch.git] / datapath / datapath.c
index 491f98a..c715f0e 100644 (file)
@@ -744,16 +744,6 @@ queue_control_packets(struct sk_buff *skb, struct sk_buff_head *queue,
                nskb = skb->next;
                skb->next = NULL;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-               /* Until 2.6.22, the start of the transport header was
-                * also the start of data to be checksummed.  Linux
-                * 2.6.22 introduced the csum_start field for this
-                * purpose, but we should point the transport header to
-                * it anyway for backward compatibility, as
-                * dev_queue_xmit() does even in 2.6.28. */
-               skb_set_transport_header(skb, skb->csum_start - skb_headroom(skb));
-#endif
-
                err = skb_cow(skb, sizeof *header);
                if (err)
                        goto err_kfree_skbs;
@@ -2201,19 +2191,25 @@ success:
        
        retval = 0;
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               __wsum csum = 0;
-               int csum_start, csum_offset;
+               if (copy_bytes == skb->len) {
+                       __wsum csum = 0;
+                       int csum_start, csum_offset;
 
-               csum_start = skb_transport_header(skb) - skb->data;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-               csum_offset = skb->csum_offset;
+                       /* Until 2.6.22, the start of the transport header was
+                        * also the start of data to be checksummed.  Linux
+                        * 2.6.22 introduced the csum_start field for this
+                        * purpose, but we should point the transport header to
+                        * it anyway for backward compatibility, as
+                        * dev_queue_xmit() does even in 2.6.28. */
+                       skb_set_transport_header(skb, skb->csum_start - skb_headroom(skb));
+                       csum_offset = skb->csum_offset;
 #else
-               csum_offset = skb->csum;
+                       csum_offset = skb->csum;
 #endif
-               if (csum_start + csum_offset + sizeof(__sum16) <= copy_bytes) {
+                       csum_start = skb_transport_header(skb) - skb->data;
                        retval = skb_copy_and_csum_datagram(skb, csum_start, buf + csum_start,
                                                            copy_bytes - csum_start, &csum);
-
                        if (!retval) {
                                __sum16 __user *csump;
 
@@ -2221,7 +2217,8 @@ success:
                                csump = (__sum16 __user *)(buf + csum_start + csum_offset);
                                put_user(csum_fold(csum), csump);
                        }
-               }
+               } else
+                       retval = skb_checksum_help(skb);
        }
 
        if (!retval) {