mirror of https://gitee.com/openkylin/linux.git
net: Fix save software checksum complete
Geert reported issues regarding checksum complete and UDP.
The logic introduced in commit 7e3cead517
("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>
This commit is contained in:
parent
4b28252cad
commit
46fb51eb96
|
@ -739,22 +739,38 @@ __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)
|
||||||
__sum16 sum;
|
__sum16 sum;
|
||||||
|
|
||||||
sum = csum_fold(skb_checksum(skb, 0, len, skb->csum));
|
sum = csum_fold(skb_checksum(skb, 0, len, skb->csum));
|
||||||
if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && !sum &&
|
if (likely(!sum)) {
|
||||||
|
if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) &&
|
||||||
!skb->csum_complete_sw)
|
!skb->csum_complete_sw)
|
||||||
netdev_rx_csum_fault(skb->dev);
|
netdev_rx_csum_fault(skb->dev);
|
||||||
|
}
|
||||||
/* Save checksum complete for later use */
|
skb->csum_valid = !sum;
|
||||||
skb->csum = sum;
|
|
||||||
skb->ip_summed = CHECKSUM_COMPLETE;
|
|
||||||
skb->csum_complete_sw = 1;
|
|
||||||
|
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__skb_checksum_complete_head);
|
EXPORT_SYMBOL(__skb_checksum_complete_head);
|
||||||
|
|
||||||
__sum16 __skb_checksum_complete(struct sk_buff *skb)
|
__sum16 __skb_checksum_complete(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
return __skb_checksum_complete_head(skb, skb->len);
|
__wsum csum;
|
||||||
|
__sum16 sum;
|
||||||
|
|
||||||
|
csum = skb_checksum(skb, 0, skb->len, 0);
|
||||||
|
|
||||||
|
/* skb->csum holds pseudo checksum */
|
||||||
|
sum = csum_fold(csum_add(skb->csum, csum));
|
||||||
|
if (likely(!sum)) {
|
||||||
|
if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) &&
|
||||||
|
!skb->csum_complete_sw)
|
||||||
|
netdev_rx_csum_fault(skb->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save full packet checksum */
|
||||||
|
skb->csum = csum;
|
||||||
|
skb->ip_summed = CHECKSUM_COMPLETE;
|
||||||
|
skb->csum_complete_sw = 1;
|
||||||
|
skb->csum_valid = !sum;
|
||||||
|
|
||||||
|
return sum;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__skb_checksum_complete);
|
EXPORT_SYMBOL(__skb_checksum_complete);
|
||||||
|
|
||||||
|
|
|
@ -689,6 +689,9 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
|
||||||
new->ooo_okay = old->ooo_okay;
|
new->ooo_okay = old->ooo_okay;
|
||||||
new->no_fcs = old->no_fcs;
|
new->no_fcs = old->no_fcs;
|
||||||
new->encapsulation = old->encapsulation;
|
new->encapsulation = old->encapsulation;
|
||||||
|
new->encap_hdr_csum = old->encap_hdr_csum;
|
||||||
|
new->csum_valid = old->csum_valid;
|
||||||
|
new->csum_complete_sw = old->csum_complete_sw;
|
||||||
#ifdef CONFIG_XFRM
|
#ifdef CONFIG_XFRM
|
||||||
new->sp = secpath_get(old->sp);
|
new->sp = secpath_get(old->sp);
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue