aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/vxlan.c2
-rw-r--r--include/linux/skbuff.h24
-rw-r--r--net/core/datagram.c14
-rw-r--r--net/ipv4/gre_offload.c6
-rw-r--r--net/ipv4/udp_offload.c1
-rw-r--r--net/sunrpc/socklib.c3
6 files changed, 33 insertions, 17 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 4e2caaf8b5da..1610d51dbb5c 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -565,6 +565,7 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff
565 goto out; 565 goto out;
566 } 566 }
567 skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */ 567 skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */
568 skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr));
568 569
569 off_eth = skb_gro_offset(skb); 570 off_eth = skb_gro_offset(skb);
570 hlen = off_eth + sizeof(*eh); 571 hlen = off_eth + sizeof(*eh);
@@ -599,6 +600,7 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff
599 } 600 }
600 601
601 skb_gro_pull(skb, sizeof(*eh)); /* pull inner eth header */ 602 skb_gro_pull(skb, sizeof(*eh)); /* pull inner eth header */
603 skb_gro_postpull_rcsum(skb, eh, sizeof(*eh));
602 pp = ptype->callbacks.gro_receive(head, skb); 604 pp = ptype->callbacks.gro_receive(head, skb);
603 605
604out_unlock: 606out_unlock:
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 1f50bfe2243d..5b5cd3189c98 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -572,7 +572,9 @@ 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 __u8 csum_complete_sw:1;
577 /* 3/5 bit hole (depending on ndisc_nodetype presence) */
576 kmemcheck_bitfield_end(flags2); 578 kmemcheck_bitfield_end(flags2);
577 579
578#if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL 580#if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
@@ -2735,7 +2737,7 @@ __sum16 __skb_checksum_complete(struct sk_buff *skb);
2735 2737
2736static inline int skb_csum_unnecessary(const struct sk_buff *skb) 2738static inline int skb_csum_unnecessary(const struct sk_buff *skb)
2737{ 2739{
2738 return skb->ip_summed & CHECKSUM_UNNECESSARY; 2740 return ((skb->ip_summed & CHECKSUM_UNNECESSARY) || skb->csum_valid);
2739} 2741}
2740 2742
2741/** 2743/**
@@ -2769,10 +2771,8 @@ static inline bool __skb_checksum_validate_needed(struct sk_buff *skb,
2769 bool zero_okay, 2771 bool zero_okay,
2770 __sum16 check) 2772 __sum16 check)
2771{ 2773{
2772 if (skb_csum_unnecessary(skb)) { 2774 if (skb_csum_unnecessary(skb) || (zero_okay && !check)) {
2773 return false; 2775 skb->csum_valid = 1;
2774 } else if (zero_okay && !check) {
2775 skb->ip_summed = CHECKSUM_UNNECESSARY;
2776 return false; 2776 return false;
2777 } 2777 }
2778 2778
@@ -2799,15 +2799,20 @@ static inline __sum16 __skb_checksum_validate_complete(struct sk_buff *skb,
2799{ 2799{
2800 if (skb->ip_summed == CHECKSUM_COMPLETE) { 2800 if (skb->ip_summed == CHECKSUM_COMPLETE) {
2801 if (!csum_fold(csum_add(psum, skb->csum))) { 2801 if (!csum_fold(csum_add(psum, skb->csum))) {
2802 skb->ip_summed = CHECKSUM_UNNECESSARY; 2802 skb->csum_valid = 1;
2803 return 0; 2803 return 0;
2804 } 2804 }
2805 } 2805 }
2806 2806
2807 skb->csum = psum; 2807 skb->csum = psum;
2808 2808
2809 if (complete || skb->len <= CHECKSUM_BREAK) 2809 if (complete || skb->len <= CHECKSUM_BREAK) {
2810 return __skb_checksum_complete(skb); 2810 __sum16 csum;
2811
2812 csum = __skb_checksum_complete(skb);
2813 skb->csum_valid = !csum;
2814 return csum;
2815 }
2811 2816
2812 return 0; 2817 return 0;
2813} 2818}
@@ -2831,6 +2836,7 @@ static inline __wsum null_compute_pseudo(struct sk_buff *skb, int proto)
2831 zero_okay, check, compute_pseudo) \ 2836 zero_okay, check, compute_pseudo) \
2832({ \ 2837({ \
2833 __sum16 __ret = 0; \ 2838 __sum16 __ret = 0; \
2839 skb->csum_valid = 0; \
2834 if (__skb_checksum_validate_needed(skb, zero_okay, check)) \ 2840 if (__skb_checksum_validate_needed(skb, zero_okay, check)) \
2835 __ret = __skb_checksum_validate_complete(skb, \ 2841 __ret = __skb_checksum_validate_complete(skb, \
2836 complete, compute_pseudo(skb, proto)); \ 2842 complete, compute_pseudo(skb, proto)); \
diff --git a/net/core/datagram.c b/net/core/datagram.c
index a16ed7bbe376..6b1c04ca1d50 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -739,11 +739,15 @@ __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 (likely(!sum)) { 742 if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && !sum &&
743 if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) 743 !skb->csum_complete_sw)
744 netdev_rx_csum_fault(skb->dev); 744 netdev_rx_csum_fault(skb->dev);
745 skb->ip_summed = CHECKSUM_UNNECESSARY; 745
746 } 746 /* Save checksum complete for later use */
747 skb->csum = sum;
748 skb->ip_summed = CHECKSUM_COMPLETE;
749 skb->csum_complete_sw = 1;
750
747 return sum; 751 return sum;
748} 752}
749EXPORT_SYMBOL(__skb_checksum_complete_head); 753EXPORT_SYMBOL(__skb_checksum_complete_head);
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c
index 24deb3928b9e..eb92deb12666 100644
--- a/net/ipv4/gre_offload.c
+++ b/net/ipv4/gre_offload.c
@@ -131,10 +131,12 @@ static __sum16 gro_skb_checksum(struct sk_buff *skb)
131 csum_partial(skb->data, skb_gro_offset(skb), 0)); 131 csum_partial(skb->data, skb_gro_offset(skb), 0));
132 sum = csum_fold(NAPI_GRO_CB(skb)->csum); 132 sum = csum_fold(NAPI_GRO_CB(skb)->csum);
133 if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) { 133 if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) {
134 if (unlikely(!sum)) 134 if (unlikely(!sum) && !skb->csum_complete_sw)
135 netdev_rx_csum_fault(skb->dev); 135 netdev_rx_csum_fault(skb->dev);
136 } else 136 } else {
137 skb->ip_summed = CHECKSUM_COMPLETE; 137 skb->ip_summed = CHECKSUM_COMPLETE;
138 skb->csum_complete_sw = 1;
139 }
138 140
139 return sum; 141 return sum;
140} 142}
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 7b1840110173..546d2d439dda 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -200,6 +200,7 @@ unflush:
200 } 200 }
201 201
202 skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */ 202 skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */
203 skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr));
203 pp = uo_priv->offload->callbacks.gro_receive(head, skb); 204 pp = uo_priv->offload->callbacks.gro_receive(head, skb);
204 205
205out_unlock: 206out_unlock:
diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c
index 0a648c502fc3..2df87f78e518 100644
--- a/net/sunrpc/socklib.c
+++ b/net/sunrpc/socklib.c
@@ -173,7 +173,8 @@ int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb)
173 return -1; 173 return -1;
174 if (csum_fold(desc.csum)) 174 if (csum_fold(desc.csum))
175 return -1; 175 return -1;
176 if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) 176 if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) &&
177 !skb->csum_complete_sw)
177 netdev_rx_csum_fault(skb->dev); 178 netdev_rx_csum_fault(skb->dev);
178 return 0; 179 return 0;
179no_checksum: 180no_checksum: