aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/skbuff.h
diff options
context:
space:
mode:
authorTom Herbert <therbert@google.com>2014-06-10 21:54:13 -0400
committerDavid S. Miller <davem@davemloft.net>2014-06-11 18:46:12 -0400
commit5d0c2b95bc57cf8fdc0e7b3e9d7e751eb65ad052 (patch)
tree7614df8920d998a75dda7c1530ec6fc4d558d1f4 /include/linux/skbuff.h
parent1054cc150cf760f7b58ec8d2983ee7c85fb1df0a (diff)
net: Preserve CHECKSUM_COMPLETE at validation
Currently when the first checksum in a packet is validated using CHECKSUM_COMPLETE, ip_summed is overwritten to be CHECKSUM_UNNECESSARY so that any subsequent checksums in the packet are not correctly validated. This patch adds csum_valid flag in sk_buff and uses that to indicate validated checksum instead of setting CHECKSUM_UNNECESSARY. The bit is set accordingly in the skb_checksum_validate_* functions. The flag is checked in skb_checksum_complete, so that validation is communicated between checksum_init and checksum_complete sequence in TCP and UDP. Signed-off-by: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/linux/skbuff.h')
-rw-r--r--include/linux/skbuff.h23
1 files changed, 14 insertions, 9 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 1f50bfe2243d..72a53805858a 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -572,7 +572,8 @@ struct sk_buff {
572 */ 572 */
573 __u8 encapsulation:1; 573 __u8 encapsulation:1;
574 __u8 encap_hdr_csum:1; 574 __u8 encap_hdr_csum:1;
575 /* 5/7 bit hole (depending on ndisc_nodetype presence) */ 575 __u8 csum_valid:1;
576 /* 4/6 bit hole (depending on ndisc_nodetype presence) */
576 kmemcheck_bitfield_end(flags2); 577 kmemcheck_bitfield_end(flags2);
577 578
578#if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL 579#if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
@@ -2735,7 +2736,7 @@ __sum16 __skb_checksum_complete(struct sk_buff *skb);
2735 2736
2736static inline int skb_csum_unnecessary(const struct sk_buff *skb) 2737static inline int skb_csum_unnecessary(const struct sk_buff *skb)
2737{ 2738{
2738 return skb->ip_summed & CHECKSUM_UNNECESSARY; 2739 return ((skb->ip_summed & CHECKSUM_UNNECESSARY) || skb->csum_valid);
2739} 2740}
2740 2741
2741/** 2742/**
@@ -2769,10 +2770,8 @@ static inline bool __skb_checksum_validate_needed(struct sk_buff *skb,
2769 bool zero_okay, 2770 bool zero_okay,
2770 __sum16 check) 2771 __sum16 check)
2771{ 2772{
2772 if (skb_csum_unnecessary(skb)) { 2773 if (skb_csum_unnecessary(skb) || (zero_okay && !check)) {
2773 return false; 2774 skb->csum_valid = 1;
2774 } else if (zero_okay && !check) {
2775 skb->ip_summed = CHECKSUM_UNNECESSARY;
2776 return false; 2775 return false;
2777 } 2776 }
2778 2777
@@ -2799,15 +2798,20 @@ static inline __sum16 __skb_checksum_validate_complete(struct sk_buff *skb,
2799{ 2798{
2800 if (skb->ip_summed == CHECKSUM_COMPLETE) { 2799 if (skb->ip_summed == CHECKSUM_COMPLETE) {
2801 if (!csum_fold(csum_add(psum, skb->csum))) { 2800 if (!csum_fold(csum_add(psum, skb->csum))) {
2802 skb->ip_summed = CHECKSUM_UNNECESSARY; 2801 skb->csum_valid = 1;
2803 return 0; 2802 return 0;
2804 } 2803 }
2805 } 2804 }
2806 2805
2807 skb->csum = psum; 2806 skb->csum = psum;
2808 2807
2809 if (complete || skb->len <= CHECKSUM_BREAK) 2808 if (complete || skb->len <= CHECKSUM_BREAK) {
2810 return __skb_checksum_complete(skb); 2809 __sum16 csum;
2810
2811 csum = __skb_checksum_complete(skb);
2812 skb->csum_valid = !csum;
2813 return csum;
2814 }
2811 2815
2812 return 0; 2816 return 0;
2813} 2817}
@@ -2831,6 +2835,7 @@ static inline __wsum null_compute_pseudo(struct sk_buff *skb, int proto)
2831 zero_okay, check, compute_pseudo) \ 2835 zero_okay, check, compute_pseudo) \
2832({ \ 2836({ \
2833 __sum16 __ret = 0; \ 2837 __sum16 __ret = 0; \
2838 skb->csum_valid = 0; \
2834 if (__skb_checksum_validate_needed(skb, zero_okay, check)) \ 2839 if (__skb_checksum_validate_needed(skb, zero_okay, check)) \
2835 __ret = __skb_checksum_validate_complete(skb, \ 2840 __ret = __skb_checksum_validate_complete(skb, \
2836 complete, compute_pseudo(skb, proto)); \ 2841 complete, compute_pseudo(skb, proto)); \