git: dfd5240189ca - stable/13 - netinet: Implement in_cksum_skip() using m_apply()

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Wed, 01 Dec 2021 12:48:37 UTC
The branch stable/13 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=dfd5240189ca024b268e53df2f0a3076df57b240

commit dfd5240189ca024b268e53df2f0a3076df57b240
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2021-11-24 18:19:54 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2021-12-01 12:43:03 +0000

    netinet: Implement in_cksum_skip() using m_apply()
    
    This allows it to work with unmapped mbufs.  In particular,
    in_cksum_skip() calls no longer need to be preceded by calls to
    mb_unmapped_to_ext() to avoid a page fault.
    
    PR:             259645
    Reviewed by:    gallatin, glebius, jhb
    Sponsored by:   The FreeBSD Foundation
    
    (cherry picked from commit 0d9c3423f59bb305301f5a5bc7c8f5daf7b7aa52)
---
 sys/netinet/in_cksum.c | 63 +++++++++++++++++++++++++-------------------------
 1 file changed, 32 insertions(+), 31 deletions(-)

diff --git a/sys/netinet/in_cksum.c b/sys/netinet/in_cksum.c
index 581950c8afa4..98317d4dac4a 100644
--- a/sys/netinet/in_cksum.c
+++ b/sys/netinet/in_cksum.c
@@ -49,7 +49,9 @@ __FBSDID("$FreeBSD$");
 #include <machine/in_cksum.h>
 
 /*
- * These implementations may be overridden on a per-platform basis.
+ * These implementations may be overridden on a per-platform basis.  On
+ * platforms with a direct map, the implementation of in_cksum() must handle
+ * unmapped mbufs.
  */
 #ifndef HAVE_MD_IN_CKSUM
 
@@ -203,44 +205,43 @@ in_pseudo(u_int32_t a, u_int32_t b, u_int32_t c)
 	return (sum);
 }
 
+struct cksum_skip_partial_args {
+	uint64_t csum;
+	int clen;
+};
+
+static int
+in_cksum_skip_partial(void *arg, void *data, u_int len)
+{
+	struct cksum_skip_partial_args *a;
+
+	a = arg;
+        if (((uintptr_t)data ^ a->clen) & 1)
+                a->csum += in_cksumdata(data, len) << 8;
+        else
+                a->csum += in_cksumdata(data, len);
+	a->clen += len;
+	return (0);
+}
+
 u_short
 in_cksum_skip(struct mbuf *m, int len, int skip)
 {
-	u_int64_t sum = 0;
-	int mlen = 0;
-	int clen = 0;
-	caddr_t addr;
+	struct cksum_skip_partial_args a;
 	union q_util q_util;
 	union l_util l_util;
+	uint64_t sum;
 
 	len -= skip;
-	for (; skip && m; m = m->m_next) {
-		if (m->m_len > skip) {
-			mlen = m->m_len - skip;
-			addr = mtod(m, caddr_t) + skip;
-			goto skip_start;
-		} else {
-			skip -= m->m_len;
-		}
-	}
-
-	for (; m && len; m = m->m_next) {
-		if (m->m_len == 0)
-			continue;
-		mlen = m->m_len;
-		addr = mtod(m, caddr_t);
-skip_start:
-		if (len < mlen)
-			mlen = len;
-
-		if ((clen ^ (uintptr_t) addr) & 1)
-			sum += in_cksumdata(addr, mlen) << 8;
-		else
-			sum += in_cksumdata(addr, mlen);
 
-		clen += mlen;
-		len -= mlen;
-	}
+	/*
+	 * The use of m_apply() allows this routine to operate on unmapped
+	 * mbufs.
+	 */
+	a.csum = 0;
+	a.clen = 0;
+	(void)m_apply(m, skip, len, in_cksum_skip_partial, &a);
+	sum = a.csum;
 	REDUCE16;
 	return (~sum & 0xffff);
 }