Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5d0c2b95 authored by Tom Herbert's avatar Tom Herbert Committed by David S. Miller
Browse files

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: default avatarTom Herbert <therbert@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1054cc15
Loading
Loading
Loading
Loading
+14 −9
Original line number Diff line number Diff line
@@ -572,7 +572,8 @@ struct sk_buff {
	 */
	__u8			encapsulation:1;
	__u8			encap_hdr_csum:1;
	/* 5/7 bit hole (depending on ndisc_nodetype presence) */
	__u8			csum_valid:1;
	/* 4/6 bit hole (depending on ndisc_nodetype presence) */
	kmemcheck_bitfield_end(flags2);

#if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
@@ -2735,7 +2736,7 @@ __sum16 __skb_checksum_complete(struct sk_buff *skb);

static inline int skb_csum_unnecessary(const struct sk_buff *skb)
{
	return skb->ip_summed & CHECKSUM_UNNECESSARY;
	return ((skb->ip_summed & CHECKSUM_UNNECESSARY) || skb->csum_valid);
}

/**
@@ -2769,10 +2770,8 @@ static inline bool __skb_checksum_validate_needed(struct sk_buff *skb,
						  bool zero_okay,
						  __sum16 check)
{
	if (skb_csum_unnecessary(skb)) {
		return false;
	} else if (zero_okay && !check) {
		skb->ip_summed = CHECKSUM_UNNECESSARY;
	if (skb_csum_unnecessary(skb) || (zero_okay && !check)) {
		skb->csum_valid = 1;
		return false;
	}

@@ -2799,15 +2798,20 @@ static inline __sum16 __skb_checksum_validate_complete(struct sk_buff *skb,
{
	if (skb->ip_summed == CHECKSUM_COMPLETE) {
		if (!csum_fold(csum_add(psum, skb->csum))) {
			skb->ip_summed = CHECKSUM_UNNECESSARY;
			skb->csum_valid = 1;
			return 0;
		}
	}

	skb->csum = psum;

	if (complete || skb->len <= CHECKSUM_BREAK)
		return __skb_checksum_complete(skb);
	if (complete || skb->len <= CHECKSUM_BREAK) {
		__sum16 csum;

		csum = __skb_checksum_complete(skb);
		skb->csum_valid = !csum;
		return csum;
	}

	return 0;
}
@@ -2831,6 +2835,7 @@ static inline __wsum null_compute_pseudo(struct sk_buff *skb, int proto)
				zero_okay, check, compute_pseudo)	\
({									\
	__sum16 __ret = 0;						\
	skb->csum_valid = 0;						\
	if (__skb_checksum_validate_needed(skb, zero_okay, check))	\
		__ret = __skb_checksum_validate_complete(skb,		\
				complete, compute_pseudo(skb, proto));	\