xref: /freebsd/sys/netinet6/in6_cksum.c (revision 29a3d1b0d2ee8511f9822ceab1a469f8ddc9fe9c)
1686cdd19SJun-ichiro itojun Hagino /*	$FreeBSD$	*/
229a3d1b0SJun-ichiro itojun Hagino /*	$KAME: in6_cksum.c,v 1.9 2000/09/09 15:33:31 itojun Exp $	*/
3686cdd19SJun-ichiro itojun Hagino 
482cd038dSYoshinobu Inoue /*
582cd038dSYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
682cd038dSYoshinobu Inoue  * All rights reserved.
782cd038dSYoshinobu Inoue  *
882cd038dSYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
982cd038dSYoshinobu Inoue  * modification, are permitted provided that the following conditions
1082cd038dSYoshinobu Inoue  * are met:
1182cd038dSYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
1282cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
1382cd038dSYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
1482cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
1582cd038dSYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
1682cd038dSYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
1782cd038dSYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
1882cd038dSYoshinobu Inoue  *    without specific prior written permission.
1982cd038dSYoshinobu Inoue  *
2082cd038dSYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2182cd038dSYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2282cd038dSYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2382cd038dSYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2482cd038dSYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2582cd038dSYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2682cd038dSYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2782cd038dSYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2882cd038dSYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2982cd038dSYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3082cd038dSYoshinobu Inoue  * SUCH DAMAGE.
3182cd038dSYoshinobu Inoue  */
3282cd038dSYoshinobu Inoue 
3382cd038dSYoshinobu Inoue /*
3482cd038dSYoshinobu Inoue  * Copyright (c) 1988, 1992, 1993
3582cd038dSYoshinobu Inoue  *	The Regents of the University of California.  All rights reserved.
3682cd038dSYoshinobu Inoue  *
3782cd038dSYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
3882cd038dSYoshinobu Inoue  * modification, are permitted provided that the following conditions
3982cd038dSYoshinobu Inoue  * are met:
4082cd038dSYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
4182cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
4282cd038dSYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
4382cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
4482cd038dSYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
4582cd038dSYoshinobu Inoue  * 3. All advertising materials mentioning features or use of this software
4682cd038dSYoshinobu Inoue  *    must display the following acknowledgement:
4782cd038dSYoshinobu Inoue  *	This product includes software developed by the University of
4882cd038dSYoshinobu Inoue  *	California, Berkeley and its contributors.
4982cd038dSYoshinobu Inoue  * 4. Neither the name of the University nor the names of its contributors
5082cd038dSYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
5182cd038dSYoshinobu Inoue  *    without specific prior written permission.
5282cd038dSYoshinobu Inoue  *
5382cd038dSYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5482cd038dSYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5582cd038dSYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5682cd038dSYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5782cd038dSYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5882cd038dSYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5982cd038dSYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6082cd038dSYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6182cd038dSYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6282cd038dSYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6382cd038dSYoshinobu Inoue  * SUCH DAMAGE.
6482cd038dSYoshinobu Inoue  *
6582cd038dSYoshinobu Inoue  *	@(#)in_cksum.c	8.1 (Berkeley) 6/10/93
6682cd038dSYoshinobu Inoue  */
6782cd038dSYoshinobu Inoue 
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>
7382cd038dSYoshinobu Inoue 
7482cd038dSYoshinobu Inoue #include <net/net_osdep.h>
7582cd038dSYoshinobu Inoue 
7682cd038dSYoshinobu Inoue /*
7782cd038dSYoshinobu Inoue  * Checksum routine for Internet Protocol family headers (Portable Version).
7882cd038dSYoshinobu Inoue  *
7982cd038dSYoshinobu Inoue  * This routine is very heavily used in the network
8082cd038dSYoshinobu Inoue  * code and should be modified for each CPU to be as fast as possible.
8182cd038dSYoshinobu Inoue  */
8282cd038dSYoshinobu Inoue 
8382cd038dSYoshinobu Inoue #define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
8482cd038dSYoshinobu Inoue #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
8582cd038dSYoshinobu Inoue 
8682cd038dSYoshinobu Inoue /*
8782cd038dSYoshinobu Inoue  * m MUST contain a continuous IP6 header.
8882cd038dSYoshinobu Inoue  * off is a offset where TCP/UDP/ICMP6 header starts.
8982cd038dSYoshinobu Inoue  * len is a total length of a transport segment.
9082cd038dSYoshinobu Inoue  * (e.g. TCP header + TCP payload)
9182cd038dSYoshinobu Inoue  */
9282cd038dSYoshinobu Inoue 
9382cd038dSYoshinobu Inoue int
9482cd038dSYoshinobu Inoue in6_cksum(m, nxt, off, len)
9582cd038dSYoshinobu Inoue 	register struct mbuf *m;
9682cd038dSYoshinobu Inoue 	u_int8_t nxt;
97686cdd19SJun-ichiro itojun Hagino 	u_int32_t off, len;
9882cd038dSYoshinobu Inoue {
9982cd038dSYoshinobu Inoue 	register u_int16_t *w;
10082cd038dSYoshinobu Inoue 	register int sum = 0;
10182cd038dSYoshinobu Inoue 	register int mlen = 0;
10282cd038dSYoshinobu Inoue 	int byte_swapped = 0;
103686cdd19SJun-ichiro itojun Hagino #if 0
104686cdd19SJun-ichiro itojun Hagino 	int srcifid = 0, dstifid = 0;
105686cdd19SJun-ichiro itojun Hagino #endif
10682cd038dSYoshinobu Inoue 	struct ip6_hdr *ip6;
10729a3d1b0SJun-ichiro itojun Hagino 	union {
10829a3d1b0SJun-ichiro itojun Hagino 		u_int16_t phs[4];
10929a3d1b0SJun-ichiro itojun Hagino 		struct {
11029a3d1b0SJun-ichiro itojun Hagino 			u_int32_t	ph_len;
11129a3d1b0SJun-ichiro itojun Hagino 			u_int8_t	ph_zero[3];
11229a3d1b0SJun-ichiro itojun Hagino 			u_int8_t	ph_nxt;
11329a3d1b0SJun-ichiro itojun Hagino 		} ph __attribute__((__packed__));
11429a3d1b0SJun-ichiro itojun Hagino 	} uph;
11582cd038dSYoshinobu Inoue 	union {
11682cd038dSYoshinobu Inoue 		u_int8_t	c[2];
11782cd038dSYoshinobu Inoue 		u_int16_t	s;
11882cd038dSYoshinobu Inoue 	} s_util;
11982cd038dSYoshinobu Inoue 	union {
12082cd038dSYoshinobu Inoue 		u_int16_t s[2];
12182cd038dSYoshinobu Inoue 		u_int32_t l;
12282cd038dSYoshinobu Inoue 	} l_util;
12382cd038dSYoshinobu Inoue 
12482cd038dSYoshinobu Inoue 	/* sanity check */
12582cd038dSYoshinobu Inoue 	if (m->m_pkthdr.len < off + len) {
12682cd038dSYoshinobu Inoue 		panic("in6_cksum: mbuf len (%d) < off+len (%d+%d)\n",
12782cd038dSYoshinobu Inoue 			m->m_pkthdr.len, off, len);
12882cd038dSYoshinobu Inoue 	}
12982cd038dSYoshinobu Inoue 
13029a3d1b0SJun-ichiro itojun Hagino 	bzero(&uph, sizeof(uph));
13129a3d1b0SJun-ichiro itojun Hagino 
13282cd038dSYoshinobu Inoue 	/*
13382cd038dSYoshinobu Inoue 	 * First create IP6 pseudo header and calculate a summary.
13482cd038dSYoshinobu Inoue 	 */
13582cd038dSYoshinobu Inoue 	ip6 = mtod(m, struct ip6_hdr *);
136686cdd19SJun-ichiro itojun Hagino #if 0
137686cdd19SJun-ichiro itojun Hagino 	if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
138686cdd19SJun-ichiro itojun Hagino 		srcifid = ip6->ip6_src.s6_addr16[1];
139686cdd19SJun-ichiro itojun Hagino 		ip6->ip6_src.s6_addr16[1] = 0;
140686cdd19SJun-ichiro itojun Hagino 	}
141686cdd19SJun-ichiro itojun Hagino 	if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
142686cdd19SJun-ichiro itojun Hagino 		dstifid = ip6->ip6_dst.s6_addr16[1];
143686cdd19SJun-ichiro itojun Hagino 		ip6->ip6_dst.s6_addr16[1] = 0;
144686cdd19SJun-ichiro itojun Hagino 	}
145686cdd19SJun-ichiro itojun Hagino #endif
14682cd038dSYoshinobu Inoue 	w = (u_int16_t *)&ip6->ip6_src;
14782cd038dSYoshinobu Inoue 	uph.ph.ph_len = htonl(len);
14882cd038dSYoshinobu Inoue 	uph.ph.ph_nxt = nxt;
14982cd038dSYoshinobu Inoue 
15082cd038dSYoshinobu Inoue 	/* IPv6 source address */
15182cd038dSYoshinobu Inoue 	sum += w[0];
15282cd038dSYoshinobu Inoue 	if (!IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
15382cd038dSYoshinobu Inoue 		sum += w[1];
15482cd038dSYoshinobu Inoue 	sum += w[2]; sum += w[3]; sum += w[4]; sum += w[5];
15582cd038dSYoshinobu Inoue 	sum += w[6]; sum += w[7];
15682cd038dSYoshinobu Inoue 	/* IPv6 destination address */
15782cd038dSYoshinobu Inoue 	sum += w[8];
15882cd038dSYoshinobu Inoue 	if (!IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
15982cd038dSYoshinobu Inoue 		sum += w[9];
16082cd038dSYoshinobu Inoue 	sum += w[10]; sum += w[11]; sum += w[12]; sum += w[13];
16182cd038dSYoshinobu Inoue 	sum += w[14]; sum += w[15];
16282cd038dSYoshinobu Inoue 	/* Payload length and upper layer identifier */
16382cd038dSYoshinobu Inoue 	sum += uph.phs[0];  sum += uph.phs[1];
16482cd038dSYoshinobu Inoue 	sum += uph.phs[2];  sum += uph.phs[3];
16582cd038dSYoshinobu Inoue 
166686cdd19SJun-ichiro itojun Hagino #if 0
167686cdd19SJun-ichiro itojun Hagino 	if (srcifid)
168686cdd19SJun-ichiro itojun Hagino 		ip6->ip6_src.s6_addr16[1] = srcifid;
169686cdd19SJun-ichiro itojun Hagino 	if (dstifid)
170686cdd19SJun-ichiro itojun Hagino 		ip6->ip6_dst.s6_addr16[1] = dstifid;
171686cdd19SJun-ichiro itojun Hagino #endif
17282cd038dSYoshinobu Inoue 	/*
17382cd038dSYoshinobu Inoue 	 * Secondly calculate a summary of the first mbuf excluding offset.
17482cd038dSYoshinobu Inoue 	 */
17582cd038dSYoshinobu Inoue 	while (m != NULL && off > 0) {
17682cd038dSYoshinobu Inoue 		if (m->m_len <= off)
17782cd038dSYoshinobu Inoue 			off -= m->m_len;
17882cd038dSYoshinobu Inoue 		else
17982cd038dSYoshinobu Inoue 			break;
18082cd038dSYoshinobu Inoue 		m = m->m_next;
18182cd038dSYoshinobu Inoue 	}
18282cd038dSYoshinobu Inoue 	w = (u_int16_t *)(mtod(m, u_char *) + off);
18382cd038dSYoshinobu Inoue 	mlen = m->m_len - off;
18482cd038dSYoshinobu Inoue 	if (len < mlen)
18582cd038dSYoshinobu Inoue 		mlen = len;
18682cd038dSYoshinobu Inoue 	len -= mlen;
18782cd038dSYoshinobu Inoue 	/*
18882cd038dSYoshinobu Inoue 	 * Force to even boundary.
18982cd038dSYoshinobu Inoue 	 */
19082cd038dSYoshinobu Inoue 	if ((1 & (long) w) && (mlen > 0)) {
19182cd038dSYoshinobu Inoue 		REDUCE;
19282cd038dSYoshinobu Inoue 		sum <<= 8;
19382cd038dSYoshinobu Inoue 		s_util.c[0] = *(u_char *)w;
19482cd038dSYoshinobu Inoue 		w = (u_int16_t *)((char *)w + 1);
19582cd038dSYoshinobu Inoue 		mlen--;
19682cd038dSYoshinobu Inoue 		byte_swapped = 1;
19782cd038dSYoshinobu Inoue 	}
19882cd038dSYoshinobu Inoue 	/*
19982cd038dSYoshinobu Inoue 	 * Unroll the loop to make overhead from
20082cd038dSYoshinobu Inoue 	 * branches &c small.
20182cd038dSYoshinobu Inoue 	 */
20282cd038dSYoshinobu Inoue 	while ((mlen -= 32) >= 0) {
20382cd038dSYoshinobu Inoue 		sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
20482cd038dSYoshinobu Inoue 		sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
20582cd038dSYoshinobu Inoue 		sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
20682cd038dSYoshinobu Inoue 		sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
20782cd038dSYoshinobu Inoue 		w += 16;
20882cd038dSYoshinobu Inoue 	}
20982cd038dSYoshinobu Inoue 	mlen += 32;
21082cd038dSYoshinobu Inoue 	while ((mlen -= 8) >= 0) {
21182cd038dSYoshinobu Inoue 		sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
21282cd038dSYoshinobu Inoue 		w += 4;
21382cd038dSYoshinobu Inoue 	}
21482cd038dSYoshinobu Inoue 	mlen += 8;
21582cd038dSYoshinobu Inoue 	if (mlen == 0 && byte_swapped == 0)
21682cd038dSYoshinobu Inoue 		goto next;
21782cd038dSYoshinobu Inoue 	REDUCE;
21882cd038dSYoshinobu Inoue 	while ((mlen -= 2) >= 0) {
21982cd038dSYoshinobu Inoue 		sum += *w++;
22082cd038dSYoshinobu Inoue 	}
22182cd038dSYoshinobu Inoue 	if (byte_swapped) {
22282cd038dSYoshinobu Inoue 		REDUCE;
22382cd038dSYoshinobu Inoue 		sum <<= 8;
22482cd038dSYoshinobu Inoue 		byte_swapped = 0;
22582cd038dSYoshinobu Inoue 		if (mlen == -1) {
22682cd038dSYoshinobu Inoue 			s_util.c[1] = *(char *)w;
22782cd038dSYoshinobu Inoue 			sum += s_util.s;
22882cd038dSYoshinobu Inoue 			mlen = 0;
22982cd038dSYoshinobu Inoue 		} else
23082cd038dSYoshinobu Inoue 			mlen = -1;
23182cd038dSYoshinobu Inoue 	} else if (mlen == -1)
23282cd038dSYoshinobu Inoue 		s_util.c[0] = *(char *)w;
23382cd038dSYoshinobu Inoue  next:
23482cd038dSYoshinobu Inoue 	m = m->m_next;
23582cd038dSYoshinobu Inoue 
23682cd038dSYoshinobu Inoue 	/*
23782cd038dSYoshinobu Inoue 	 * Lastly calculate a summary of the rest of mbufs.
23882cd038dSYoshinobu Inoue 	 */
23982cd038dSYoshinobu Inoue 
24082cd038dSYoshinobu Inoue 	for (;m && len; m = m->m_next) {
24182cd038dSYoshinobu Inoue 		if (m->m_len == 0)
24282cd038dSYoshinobu Inoue 			continue;
24382cd038dSYoshinobu Inoue 		w = mtod(m, u_int16_t *);
24482cd038dSYoshinobu Inoue 		if (mlen == -1) {
24582cd038dSYoshinobu Inoue 			/*
24682cd038dSYoshinobu Inoue 			 * The first byte of this mbuf is the continuation
24782cd038dSYoshinobu Inoue 			 * of a word spanning between this mbuf and the
24882cd038dSYoshinobu Inoue 			 * last mbuf.
24982cd038dSYoshinobu Inoue 			 *
25082cd038dSYoshinobu Inoue 			 * s_util.c[0] is already saved when scanning previous
25182cd038dSYoshinobu Inoue 			 * mbuf.
25282cd038dSYoshinobu Inoue 			 */
25382cd038dSYoshinobu Inoue 			s_util.c[1] = *(char *)w;
25482cd038dSYoshinobu Inoue 			sum += s_util.s;
25582cd038dSYoshinobu Inoue 			w = (u_int16_t *)((char *)w + 1);
25682cd038dSYoshinobu Inoue 			mlen = m->m_len - 1;
25782cd038dSYoshinobu Inoue 			len--;
25882cd038dSYoshinobu Inoue 		} else
25982cd038dSYoshinobu Inoue 			mlen = m->m_len;
26082cd038dSYoshinobu Inoue 		if (len < mlen)
26182cd038dSYoshinobu Inoue 			mlen = len;
26282cd038dSYoshinobu Inoue 		len -= mlen;
26382cd038dSYoshinobu Inoue 		/*
26482cd038dSYoshinobu Inoue 		 * Force to even boundary.
26582cd038dSYoshinobu Inoue 		 */
26682cd038dSYoshinobu Inoue 		if ((1 & (long) w) && (mlen > 0)) {
26782cd038dSYoshinobu Inoue 			REDUCE;
26882cd038dSYoshinobu Inoue 			sum <<= 8;
26982cd038dSYoshinobu Inoue 			s_util.c[0] = *(u_char *)w;
27082cd038dSYoshinobu Inoue 			w = (u_int16_t *)((char *)w + 1);
27182cd038dSYoshinobu Inoue 			mlen--;
27282cd038dSYoshinobu Inoue 			byte_swapped = 1;
27382cd038dSYoshinobu Inoue 		}
27482cd038dSYoshinobu Inoue 		/*
27582cd038dSYoshinobu Inoue 		 * Unroll the loop to make overhead from
27682cd038dSYoshinobu Inoue 		 * branches &c small.
27782cd038dSYoshinobu Inoue 		 */
27882cd038dSYoshinobu Inoue 		while ((mlen -= 32) >= 0) {
27982cd038dSYoshinobu Inoue 			sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
28082cd038dSYoshinobu Inoue 			sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
28182cd038dSYoshinobu Inoue 			sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
28282cd038dSYoshinobu Inoue 			sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
28382cd038dSYoshinobu Inoue 			w += 16;
28482cd038dSYoshinobu Inoue 		}
28582cd038dSYoshinobu Inoue 		mlen += 32;
28682cd038dSYoshinobu Inoue 		while ((mlen -= 8) >= 0) {
28782cd038dSYoshinobu Inoue 			sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
28882cd038dSYoshinobu Inoue 			w += 4;
28982cd038dSYoshinobu Inoue 		}
29082cd038dSYoshinobu Inoue 		mlen += 8;
29182cd038dSYoshinobu Inoue 		if (mlen == 0 && byte_swapped == 0)
29282cd038dSYoshinobu Inoue 			continue;
29382cd038dSYoshinobu Inoue 		REDUCE;
29482cd038dSYoshinobu Inoue 		while ((mlen -= 2) >= 0) {
29582cd038dSYoshinobu Inoue 			sum += *w++;
29682cd038dSYoshinobu Inoue 		}
29782cd038dSYoshinobu Inoue 		if (byte_swapped) {
29882cd038dSYoshinobu Inoue 			REDUCE;
29982cd038dSYoshinobu Inoue 			sum <<= 8;
30082cd038dSYoshinobu Inoue 			byte_swapped = 0;
30182cd038dSYoshinobu Inoue 			if (mlen == -1) {
30282cd038dSYoshinobu Inoue 				s_util.c[1] = *(char *)w;
30382cd038dSYoshinobu Inoue 				sum += s_util.s;
30482cd038dSYoshinobu Inoue 				mlen = 0;
30582cd038dSYoshinobu Inoue 			} else
30682cd038dSYoshinobu Inoue 				mlen = -1;
30782cd038dSYoshinobu Inoue 		} else if (mlen == -1)
30882cd038dSYoshinobu Inoue 			s_util.c[0] = *(char *)w;
30982cd038dSYoshinobu Inoue 	}
31082cd038dSYoshinobu Inoue 	if (len)
31182cd038dSYoshinobu Inoue 		panic("in6_cksum: out of data\n");
31282cd038dSYoshinobu Inoue 	if (mlen == -1) {
31382cd038dSYoshinobu Inoue 		/* The last mbuf has odd # of bytes. Follow the
31482cd038dSYoshinobu Inoue 		   standard (the odd byte may be shifted left by 8 bits
31582cd038dSYoshinobu Inoue 		   or not as determined by endian-ness of the machine) */
31682cd038dSYoshinobu Inoue 		s_util.c[1] = 0;
31782cd038dSYoshinobu Inoue 		sum += s_util.s;
31882cd038dSYoshinobu Inoue 	}
31982cd038dSYoshinobu Inoue 	REDUCE;
32082cd038dSYoshinobu Inoue 	return (~sum & 0xffff);
32182cd038dSYoshinobu Inoue }
322