xref: /freebsd/sys/netinet6/in6_cksum.c (revision 6775ef4188b4d4c023e76ebd2b71fa8c2c7e7cd2)
1caf43b02SWarner Losh /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
482cd038dSYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
582cd038dSYoshinobu Inoue  * All rights reserved.
682cd038dSYoshinobu Inoue  *
782cd038dSYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
882cd038dSYoshinobu Inoue  * modification, are permitted provided that the following conditions
982cd038dSYoshinobu Inoue  * are met:
1082cd038dSYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
1182cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
1282cd038dSYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
1382cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
1482cd038dSYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
1582cd038dSYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
1682cd038dSYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
1782cd038dSYoshinobu Inoue  *    without specific prior written permission.
1882cd038dSYoshinobu Inoue  *
1982cd038dSYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2082cd038dSYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2182cd038dSYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2282cd038dSYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2382cd038dSYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2482cd038dSYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2582cd038dSYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2682cd038dSYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2782cd038dSYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2882cd038dSYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2982cd038dSYoshinobu Inoue  * SUCH DAMAGE.
30b48287a3SDavid E. O'Brien  *
31b48287a3SDavid E. O'Brien  *	$KAME: in6_cksum.c,v 1.10 2000/12/03 00:53:59 itojun Exp $
3282cd038dSYoshinobu Inoue  */
3382cd038dSYoshinobu Inoue 
34caf43b02SWarner Losh /*-
3582cd038dSYoshinobu Inoue  * Copyright (c) 1988, 1992, 1993
3682cd038dSYoshinobu Inoue  *	The Regents of the University of California.  All rights reserved.
3782cd038dSYoshinobu Inoue  *
3882cd038dSYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
3982cd038dSYoshinobu Inoue  * modification, are permitted provided that the following conditions
4082cd038dSYoshinobu Inoue  * are met:
4182cd038dSYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
4282cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
4382cd038dSYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
4482cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
4582cd038dSYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
46fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
4782cd038dSYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
4882cd038dSYoshinobu Inoue  *    without specific prior written permission.
4982cd038dSYoshinobu Inoue  *
5082cd038dSYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5182cd038dSYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5282cd038dSYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5382cd038dSYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5482cd038dSYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5582cd038dSYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5682cd038dSYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5782cd038dSYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5882cd038dSYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5982cd038dSYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6082cd038dSYoshinobu Inoue  * SUCH DAMAGE.
6182cd038dSYoshinobu Inoue  *
6282cd038dSYoshinobu Inoue  *	@(#)in_cksum.c	8.1 (Berkeley) 6/10/93
6382cd038dSYoshinobu Inoue  */
6482cd038dSYoshinobu Inoue 
65b48287a3SDavid E. O'Brien #include <sys/cdefs.h>
66b48287a3SDavid E. O'Brien __FBSDID("$FreeBSD$");
67b48287a3SDavid E. O'Brien 
6882cd038dSYoshinobu Inoue #include <sys/param.h>
6982cd038dSYoshinobu Inoue #include <sys/mbuf.h>
7082cd038dSYoshinobu Inoue #include <sys/systm.h>
7182cd038dSYoshinobu Inoue #include <netinet/in.h>
72686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h>
73a1f7e5f8SHajimu UMEMOTO #include <netinet6/scope6_var.h>
7482cd038dSYoshinobu Inoue 
7582cd038dSYoshinobu Inoue /*
7682cd038dSYoshinobu Inoue  * Checksum routine for Internet Protocol family headers (Portable Version).
7782cd038dSYoshinobu Inoue  *
7882cd038dSYoshinobu Inoue  * This routine is very heavily used in the network
7982cd038dSYoshinobu Inoue  * code and should be modified for each CPU to be as fast as possible.
8082cd038dSYoshinobu Inoue  */
8182cd038dSYoshinobu Inoue 
8282cd038dSYoshinobu Inoue #define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
834c888125SRui Paulo #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; (void)ADDCARRY(sum);}
8482cd038dSYoshinobu Inoue 
85*6775ef41SMark Johnston union l_util {
86*6775ef41SMark Johnston 	uint16_t	s[2];
87*6775ef41SMark Johnston 	uint32_t	l;
88*6775ef41SMark Johnston };
89*6775ef41SMark Johnston 
90*6775ef41SMark Johnston union s_util {
91*6775ef41SMark Johnston 	uint8_t		c[2];
92*6775ef41SMark Johnston 	uint16_t	s;
93*6775ef41SMark Johnston };
94*6775ef41SMark Johnston 
95ecade87eSBjoern A. Zeeb static int
96ecade87eSBjoern A. Zeeb _in6_cksum_pseudo(struct ip6_hdr *ip6, uint32_t len, uint8_t nxt, uint16_t csum)
97ecade87eSBjoern A. Zeeb {
98ecade87eSBjoern A. Zeeb 	int sum;
99ecade87eSBjoern A. Zeeb 	uint16_t scope, *w;
100ecade87eSBjoern A. Zeeb 	union {
101ecade87eSBjoern A. Zeeb 		u_int16_t phs[4];
102ecade87eSBjoern A. Zeeb 		struct {
103ecade87eSBjoern A. Zeeb 			u_int32_t	ph_len;
104ecade87eSBjoern A. Zeeb 			u_int8_t	ph_zero[3];
105ecade87eSBjoern A. Zeeb 			u_int8_t	ph_nxt;
106ecade87eSBjoern A. Zeeb 		} __packed ph;
107ecade87eSBjoern A. Zeeb 	} uph;
108ecade87eSBjoern A. Zeeb 
109ecade87eSBjoern A. Zeeb 	sum = csum;
110ecade87eSBjoern A. Zeeb 
111ecade87eSBjoern A. Zeeb 	/*
112ecade87eSBjoern A. Zeeb 	 * First create IP6 pseudo header and calculate a summary.
113ecade87eSBjoern A. Zeeb 	 */
114ecade87eSBjoern A. Zeeb 	uph.ph.ph_len = htonl(len);
115ecade87eSBjoern A. Zeeb 	uph.ph.ph_zero[0] = uph.ph.ph_zero[1] = uph.ph.ph_zero[2] = 0;
116ecade87eSBjoern A. Zeeb 	uph.ph.ph_nxt = nxt;
117ecade87eSBjoern A. Zeeb 
118ecade87eSBjoern A. Zeeb 	/* Payload length and upper layer identifier. */
119ecade87eSBjoern A. Zeeb 	sum += uph.phs[0];  sum += uph.phs[1];
120ecade87eSBjoern A. Zeeb 	sum += uph.phs[2];  sum += uph.phs[3];
121ecade87eSBjoern A. Zeeb 
122ecade87eSBjoern A. Zeeb 	/* IPv6 source address. */
123ecade87eSBjoern A. Zeeb 	scope = in6_getscope(&ip6->ip6_src);
124ecade87eSBjoern A. Zeeb 	w = (u_int16_t *)&ip6->ip6_src;
125ecade87eSBjoern A. Zeeb 	sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
126ecade87eSBjoern A. Zeeb 	sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
127ecade87eSBjoern A. Zeeb 	if (scope != 0)
128ecade87eSBjoern A. Zeeb 		sum -= scope;
129ecade87eSBjoern A. Zeeb 
130ecade87eSBjoern A. Zeeb 	/* IPv6 destination address. */
131ecade87eSBjoern A. Zeeb 	scope = in6_getscope(&ip6->ip6_dst);
132ecade87eSBjoern A. Zeeb 	w = (u_int16_t *)&ip6->ip6_dst;
133ecade87eSBjoern A. Zeeb 	sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
134ecade87eSBjoern A. Zeeb 	sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
135ecade87eSBjoern A. Zeeb 	if (scope != 0)
136ecade87eSBjoern A. Zeeb 		sum -= scope;
137ecade87eSBjoern A. Zeeb 
138ecade87eSBjoern A. Zeeb 	return (sum);
139ecade87eSBjoern A. Zeeb }
140ecade87eSBjoern A. Zeeb 
141ecade87eSBjoern A. Zeeb int
142ecade87eSBjoern A. Zeeb in6_cksum_pseudo(struct ip6_hdr *ip6, uint32_t len, uint8_t nxt, uint16_t csum)
143ecade87eSBjoern A. Zeeb {
144*6775ef41SMark Johnston 	union l_util l_util;
145ecade87eSBjoern A. Zeeb 	int sum;
146ecade87eSBjoern A. Zeeb 
147ecade87eSBjoern A. Zeeb 	sum = _in6_cksum_pseudo(ip6, len, nxt, csum);
148ecade87eSBjoern A. Zeeb 	REDUCE;
149ecade87eSBjoern A. Zeeb 	return (sum);
150ecade87eSBjoern A. Zeeb }
151ecade87eSBjoern A. Zeeb 
152*6775ef41SMark Johnston static int
153*6775ef41SMark Johnston in6_cksumdata(void *data, int *lenp, uint8_t *residp, int rlen)
154*6775ef41SMark Johnston {
155*6775ef41SMark Johnston 	union l_util l_util;
156*6775ef41SMark Johnston 	union s_util s_util;
157*6775ef41SMark Johnston 	uint16_t *w;
158*6775ef41SMark Johnston 	int len, sum;
159*6775ef41SMark Johnston 	bool byte_swapped;
160*6775ef41SMark Johnston 
161*6775ef41SMark Johnston 	KASSERT(*lenp >= 0, ("%s: negative len %d", __func__, *lenp));
162*6775ef41SMark Johnston 	KASSERT(rlen == 0 || rlen == 1, ("%s: rlen %d", __func__, rlen));
163*6775ef41SMark Johnston 
164*6775ef41SMark Johnston 	len = *lenp;
165*6775ef41SMark Johnston 	sum = 0;
166*6775ef41SMark Johnston 
167*6775ef41SMark Johnston 	if (len == 0) {
168*6775ef41SMark Johnston 		len = rlen;
169*6775ef41SMark Johnston 		goto out;
170*6775ef41SMark Johnston 	}
171*6775ef41SMark Johnston 
172*6775ef41SMark Johnston 	byte_swapped = false;
173*6775ef41SMark Johnston 	w = data;
174*6775ef41SMark Johnston 
175*6775ef41SMark Johnston 	/*
176*6775ef41SMark Johnston 	 * Do we have a residual byte left over from the previous buffer?
177*6775ef41SMark Johnston 	 */
178*6775ef41SMark Johnston 	if (rlen == 1) {
179*6775ef41SMark Johnston 		s_util.c[0] = *residp;
180*6775ef41SMark Johnston 		s_util.c[1] = *(uint8_t *)w;
181*6775ef41SMark Johnston 		sum += s_util.s;
182*6775ef41SMark Johnston 		w = (uint16_t *)((uint8_t *)w + 1);
183*6775ef41SMark Johnston 		len--;
184*6775ef41SMark Johnston 		rlen = 0;
185*6775ef41SMark Johnston 	}
186*6775ef41SMark Johnston 
187*6775ef41SMark Johnston 	/*
188*6775ef41SMark Johnston 	 * Force to even boundary.
189*6775ef41SMark Johnston 	 */
190*6775ef41SMark Johnston 	if ((1 & (uintptr_t)w) && len > 0) {
191*6775ef41SMark Johnston 		REDUCE;
192*6775ef41SMark Johnston 		sum <<= 8;
193*6775ef41SMark Johnston 		s_util.c[0] = *(uint8_t *)w;
194*6775ef41SMark Johnston 		w = (uint16_t *)((uint8_t *)w + 1);
195*6775ef41SMark Johnston 		len--;
196*6775ef41SMark Johnston 		byte_swapped = true;
197*6775ef41SMark Johnston 	}
198*6775ef41SMark Johnston 
199*6775ef41SMark Johnston 	/*
200*6775ef41SMark Johnston 	 * Unroll the loop to make overhead from branches &c small.
201*6775ef41SMark Johnston 	 */
202*6775ef41SMark Johnston 	while ((len -= 32) >= 0) {
203*6775ef41SMark Johnston 		sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
204*6775ef41SMark Johnston 		sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
205*6775ef41SMark Johnston 		sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
206*6775ef41SMark Johnston 		sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
207*6775ef41SMark Johnston 		w += 16;
208*6775ef41SMark Johnston 	}
209*6775ef41SMark Johnston 	len += 32;
210*6775ef41SMark Johnston 	while ((len -= 8) >= 0) {
211*6775ef41SMark Johnston 		sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
212*6775ef41SMark Johnston 		w += 4;
213*6775ef41SMark Johnston 	}
214*6775ef41SMark Johnston 	len += 8;
215*6775ef41SMark Johnston 	if (len == 0 && !byte_swapped)
216*6775ef41SMark Johnston 		goto out;
217*6775ef41SMark Johnston 	REDUCE;
218*6775ef41SMark Johnston 	while ((len -= 2) >= 0) {
219*6775ef41SMark Johnston 		sum += *w++;
220*6775ef41SMark Johnston 	}
221*6775ef41SMark Johnston 	if (byte_swapped) {
222*6775ef41SMark Johnston 		REDUCE;
223*6775ef41SMark Johnston 		sum <<= 8;
224*6775ef41SMark Johnston 		if (len == -1) {
225*6775ef41SMark Johnston 			s_util.c[1] = *(uint8_t *)w;
226*6775ef41SMark Johnston 			sum += s_util.s;
227*6775ef41SMark Johnston 		} else /* len == -2 */
228*6775ef41SMark Johnston 			*residp = s_util.c[0];
229*6775ef41SMark Johnston 		len++;
230*6775ef41SMark Johnston 	} else if (len == -1)
231*6775ef41SMark Johnston 		*residp = *(uint8_t *)w;
232*6775ef41SMark Johnston out:
233*6775ef41SMark Johnston 	*lenp = len & 1;
234*6775ef41SMark Johnston 	return (sum);
235*6775ef41SMark Johnston }
236*6775ef41SMark Johnston 
237*6775ef41SMark Johnston struct in6_cksum_partial_arg {
238*6775ef41SMark Johnston 	int	sum;
239*6775ef41SMark Johnston 	int	rlen;
240*6775ef41SMark Johnston 	uint8_t	resid;
241*6775ef41SMark Johnston };
242*6775ef41SMark Johnston 
243*6775ef41SMark Johnston static int
244*6775ef41SMark Johnston in6_cksum_partial_one(void *_arg, void *data, u_int len)
245*6775ef41SMark Johnston {
246*6775ef41SMark Johnston 	struct in6_cksum_partial_arg *arg = _arg;
247*6775ef41SMark Johnston 
248*6775ef41SMark Johnston 	arg->sum += in6_cksumdata(data, &len, &arg->resid, arg->rlen);
249*6775ef41SMark Johnston 	arg->rlen = len;
250*6775ef41SMark Johnston 	return (0);
251*6775ef41SMark Johnston }
252*6775ef41SMark Johnston 
25382cd038dSYoshinobu Inoue /*
2546d79f3f6SRebecca Cran  * m MUST contain a contiguous IP6 header.
2559d5abbddSJens Schweikhardt  * off is an offset where TCP/UDP/ICMP6 header starts.
25682cd038dSYoshinobu Inoue  * len is a total length of a transport segment.
25782cd038dSYoshinobu Inoue  * (e.g. TCP header + TCP payload)
25876b96fbcSMichael Tuexen  * cov is the number of bytes to be taken into account for the checksum
25982cd038dSYoshinobu Inoue  */
26082cd038dSYoshinobu Inoue int
261*6775ef41SMark Johnston in6_cksum_partial(struct mbuf *m, uint8_t nxt, uint32_t off, uint32_t len,
262*6775ef41SMark Johnston     uint32_t cov)
26382cd038dSYoshinobu Inoue {
264*6775ef41SMark Johnston 	struct in6_cksum_partial_arg arg;
265*6775ef41SMark Johnston 	union l_util l_util;
266*6775ef41SMark Johnston 	union s_util s_util;
26782cd038dSYoshinobu Inoue 	struct ip6_hdr *ip6;
268*6775ef41SMark Johnston 	uint16_t *w, scope;
2692889eb8bSBjoern A. Zeeb 	int sum;
27029a3d1b0SJun-ichiro itojun Hagino 	union {
271*6775ef41SMark Johnston 		uint16_t phs[4];
27229a3d1b0SJun-ichiro itojun Hagino 		struct {
273*6775ef41SMark Johnston 			uint32_t	ph_len;
274*6775ef41SMark Johnston 			uint8_t		ph_zero[3];
275*6775ef41SMark Johnston 			uint8_t		ph_nxt;
2761c0ee39eSWarner Losh 		} __packed ph;
27729a3d1b0SJun-ichiro itojun Hagino 	} uph;
27882cd038dSYoshinobu Inoue 
2792889eb8bSBjoern A. Zeeb 	/* Sanity check. */
2802889eb8bSBjoern A. Zeeb 	KASSERT(m->m_pkthdr.len >= off + len, ("%s: mbuf len (%d) < off(%d)+"
2812889eb8bSBjoern A. Zeeb 	    "len(%d)", __func__, m->m_pkthdr.len, off, len));
282*6775ef41SMark Johnston 	KASSERT(m->m_len >= sizeof(*ip6),
283*6775ef41SMark Johnston 	    ("%s: mbuf len %d < sizeof(ip6)", __func__, m->m_len));
28429a3d1b0SJun-ichiro itojun Hagino 
28582cd038dSYoshinobu Inoue 	/*
28682cd038dSYoshinobu Inoue 	 * First create IP6 pseudo header and calculate a summary.
28782cd038dSYoshinobu Inoue 	 */
28882cd038dSYoshinobu Inoue 	uph.ph.ph_len = htonl(len);
2892889eb8bSBjoern A. Zeeb 	uph.ph.ph_zero[0] = uph.ph.ph_zero[1] = uph.ph.ph_zero[2] = 0;
29082cd038dSYoshinobu Inoue 	uph.ph.ph_nxt = nxt;
29182cd038dSYoshinobu Inoue 
2922889eb8bSBjoern A. Zeeb 	/* Payload length and upper layer identifier. */
2932889eb8bSBjoern A. Zeeb 	sum = uph.phs[0];  sum += uph.phs[1];
29482cd038dSYoshinobu Inoue 	sum += uph.phs[2];  sum += uph.phs[3];
29582cd038dSYoshinobu Inoue 
2962889eb8bSBjoern A. Zeeb 	ip6 = mtod(m, struct ip6_hdr *);
2972889eb8bSBjoern A. Zeeb 
2982889eb8bSBjoern A. Zeeb 	/* IPv6 source address. */
2992889eb8bSBjoern A. Zeeb 	scope = in6_getscope(&ip6->ip6_src);
300*6775ef41SMark Johnston 	w = (uint16_t *)&ip6->ip6_src;
3012889eb8bSBjoern A. Zeeb 	sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
3022889eb8bSBjoern A. Zeeb 	sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
3032889eb8bSBjoern A. Zeeb 	if (scope != 0)
3042889eb8bSBjoern A. Zeeb 		sum -= scope;
3052889eb8bSBjoern A. Zeeb 
3062889eb8bSBjoern A. Zeeb 	/* IPv6 destination address. */
3072889eb8bSBjoern A. Zeeb 	scope = in6_getscope(&ip6->ip6_dst);
308*6775ef41SMark Johnston 	w = (uint16_t *)&ip6->ip6_dst;
3092889eb8bSBjoern A. Zeeb 	sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
3102889eb8bSBjoern A. Zeeb 	sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
3112889eb8bSBjoern A. Zeeb 	if (scope != 0)
3122889eb8bSBjoern A. Zeeb 		sum -= scope;
3132889eb8bSBjoern A. Zeeb 
31482cd038dSYoshinobu Inoue 	/*
315*6775ef41SMark Johnston 	 * Loop over the rest of the mbuf chain and compute the rest of the
316*6775ef41SMark Johnston 	 * checksum.  m_apply() handles unmapped mbufs.
31782cd038dSYoshinobu Inoue 	 */
318*6775ef41SMark Johnston 	arg.sum = sum;
319*6775ef41SMark Johnston 	arg.rlen = 0;
320*6775ef41SMark Johnston 	(void)m_apply(m, off, cov, in6_cksum_partial_one, &arg);
321*6775ef41SMark Johnston 	sum = arg.sum;
3222889eb8bSBjoern A. Zeeb 
32382cd038dSYoshinobu Inoue 	/*
324*6775ef41SMark Johnston 	 * Handle a residual byte.
32582cd038dSYoshinobu Inoue 	 */
326*6775ef41SMark Johnston 	if (arg.rlen == 1) {
327*6775ef41SMark Johnston 		s_util.c[0] = arg.resid;
32882cd038dSYoshinobu Inoue 		s_util.c[1] = 0;
32982cd038dSYoshinobu Inoue 		sum += s_util.s;
33082cd038dSYoshinobu Inoue 	}
33182cd038dSYoshinobu Inoue 	REDUCE;
33282cd038dSYoshinobu Inoue 	return (~sum & 0xffff);
33382cd038dSYoshinobu Inoue }
33476b96fbcSMichael Tuexen 
33576b96fbcSMichael Tuexen int
336*6775ef41SMark Johnston in6_cksum(struct mbuf *m, uint8_t nxt, uint32_t off, uint32_t len)
33776b96fbcSMichael Tuexen {
33876b96fbcSMichael Tuexen 	return (in6_cksum_partial(m, nxt, off, len, len));
33976b96fbcSMichael Tuexen }
340