diff options
author | Tom Herbert <therbert@google.com> | 2014-06-10 21:54:13 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-06-11 18:46:12 -0400 |
commit | 5d0c2b95bc57cf8fdc0e7b3e9d7e751eb65ad052 (patch) | |
tree | 7614df8920d998a75dda7c1530ec6fc4d558d1f4 /include/linux/skbuff.h | |
parent | 1054cc150cf760f7b58ec8d2983ee7c85fb1df0a (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.h | 23 |
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 | ||
2736 | static inline int skb_csum_unnecessary(const struct sk_buff *skb) | 2737 | static 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)); \ |