aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Herbert <therbert@google.com>2014-06-15 02:24:03 -0400
committerDavid S. Miller <davem@davemloft.net>2014-06-15 04:00:49 -0400
commit46fb51eb96cafb2c148b7b5119adb5e31a2bf3c4 (patch)
tree8deefff573270378b056f6f0915068a33578b2ad
parent4b28252cada3d0521ab59751f4240ecdfb9bba18 (diff)
net: Fix save software checksum complete
Geert reported issues regarding checksum complete and UDP. The logic introduced in commit 7e3cead5172927732f51fde ("net: Save software checksum complete") is not correct. This patch: 1) Restores code in __skb_checksum_complete_header except for setting CHECKSUM_UNNECESSARY. This function may be calculating checksum on something less than skb->len. 2) Adds saving checksum to __skb_checksum_complete. The full packet checksum 0..skb->len is calculated without adding in pseudo header. This value is saved in skb->csum and then the pseudo header is added to that to derive the checksum for validation. 3) In both __skb_checksum_complete_header and __skb_checksum_complete, set skb->csum_valid to whether checksum of zero was computed. This allows skb_csum_unnecessary to return true without changing to CHECKSUM_UNNECESSARY which was done previously. 4) Copy new csum related bits in __copy_skb_header. Reported-by: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/core/datagram.c36
-rw-r--r--net/core/skbuff.c3
2 files changed, 29 insertions, 10 deletions
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 6b1c04ca1d50..488dd1a825c0 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -739,22 +739,38 @@ __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)
739 __sum16 sum; 739 __sum16 sum;
740 740
741 sum = csum_fold(skb_checksum(skb, 0, len, skb->csum)); 741 sum = csum_fold(skb_checksum(skb, 0, len, skb->csum));
742 if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && !sum && 742 if (likely(!sum)) {
743 !skb->csum_complete_sw) 743 if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) &&
744 netdev_rx_csum_fault(skb->dev); 744 !skb->csum_complete_sw)
745 745 netdev_rx_csum_fault(skb->dev);
746 /* Save checksum complete for later use */ 746 }
747 skb->csum = sum; 747 skb->csum_valid = !sum;
748 skb->ip_summed = CHECKSUM_COMPLETE;
749 skb->csum_complete_sw = 1;
750
751 return sum; 748 return sum;
752} 749}
753EXPORT_SYMBOL(__skb_checksum_complete_head); 750EXPORT_SYMBOL(__skb_checksum_complete_head);
754 751
755__sum16 __skb_checksum_complete(struct sk_buff *skb) 752__sum16 __skb_checksum_complete(struct sk_buff *skb)
756{ 753{
757 return __skb_checksum_complete_head(skb, skb->len); 754 __wsum csum;
755 __sum16 sum;
756
757 csum = skb_checksum(skb, 0, skb->len, 0);
758
759 /* skb->csum holds pseudo checksum */
760 sum = csum_fold(csum_add(skb->csum, csum));
761 if (likely(!sum)) {
762 if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) &&
763 !skb->csum_complete_sw)
764 netdev_rx_csum_fault(skb->dev);
765 }
766
767 /* Save full packet checksum */
768 skb->csum = csum;
769 skb->ip_summed = CHECKSUM_COMPLETE;
770 skb->csum_complete_sw = 1;
771 skb->csum_valid = !sum;
772
773 return sum;
758} 774}
759EXPORT_SYMBOL(__skb_checksum_complete); 775EXPORT_SYMBOL(__skb_checksum_complete);
760 776
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index bf92824af3f7..9cd5344fad73 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -689,6 +689,9 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
689 new->ooo_okay = old->ooo_okay; 689 new->ooo_okay = old->ooo_okay;
690 new->no_fcs = old->no_fcs; 690 new->no_fcs = old->no_fcs;
691 new->encapsulation = old->encapsulation; 691 new->encapsulation = old->encapsulation;
692 new->encap_hdr_csum = old->encap_hdr_csum;
693 new->csum_valid = old->csum_valid;
694 new->csum_complete_sw = old->csum_complete_sw;
692#ifdef CONFIG_XFRM 695#ifdef CONFIG_XFRM
693 new->sp = secpath_get(old->sp); 696 new->sp = secpath_get(old->sp);
694#endif 697#endif