xref: /xnu-10002.81.5/bsd/netinet/in_cksum.c (revision 5e3eaea39dcf651e66cb99ba7d70e32cc4a99587)
1*5e3eaea3SApple OSS Distributions /*
2*5e3eaea3SApple OSS Distributions  * Copyright (c) 2000-2017 Apple Inc. All rights reserved.
3*5e3eaea3SApple OSS Distributions  *
4*5e3eaea3SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*5e3eaea3SApple OSS Distributions  *
6*5e3eaea3SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*5e3eaea3SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*5e3eaea3SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*5e3eaea3SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*5e3eaea3SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*5e3eaea3SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*5e3eaea3SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*5e3eaea3SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*5e3eaea3SApple OSS Distributions  *
15*5e3eaea3SApple OSS Distributions  * Please obtain a copy of the License at
16*5e3eaea3SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*5e3eaea3SApple OSS Distributions  *
18*5e3eaea3SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*5e3eaea3SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*5e3eaea3SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*5e3eaea3SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*5e3eaea3SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*5e3eaea3SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*5e3eaea3SApple OSS Distributions  * limitations under the License.
25*5e3eaea3SApple OSS Distributions  *
26*5e3eaea3SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*5e3eaea3SApple OSS Distributions  */
28*5e3eaea3SApple OSS Distributions /*
29*5e3eaea3SApple OSS Distributions  * Copyright (c) 1988, 1992, 1993
30*5e3eaea3SApple OSS Distributions  *	The Regents of the University of California.  All rights reserved.
31*5e3eaea3SApple OSS Distributions  *
32*5e3eaea3SApple OSS Distributions  * Redistribution and use in source and binary forms, with or without
33*5e3eaea3SApple OSS Distributions  * modification, are permitted provided that the following conditions
34*5e3eaea3SApple OSS Distributions  * are met:
35*5e3eaea3SApple OSS Distributions  * 1. Redistributions of source code must retain the above copyright
36*5e3eaea3SApple OSS Distributions  *    notice, this list of conditions and the following disclaimer.
37*5e3eaea3SApple OSS Distributions  * 2. Redistributions in binary form must reproduce the above copyright
38*5e3eaea3SApple OSS Distributions  *    notice, this list of conditions and the following disclaimer in the
39*5e3eaea3SApple OSS Distributions  *    documentation and/or other materials provided with the distribution.
40*5e3eaea3SApple OSS Distributions  * 3. All advertising materials mentioning features or use of this software
41*5e3eaea3SApple OSS Distributions  *    must display the following acknowledgement:
42*5e3eaea3SApple OSS Distributions  *	This product includes software developed by the University of
43*5e3eaea3SApple OSS Distributions  *	California, Berkeley and its contributors.
44*5e3eaea3SApple OSS Distributions  * 4. Neither the name of the University nor the names of its contributors
45*5e3eaea3SApple OSS Distributions  *    may be used to endorse or promote products derived from this software
46*5e3eaea3SApple OSS Distributions  *    without specific prior written permission.
47*5e3eaea3SApple OSS Distributions  *
48*5e3eaea3SApple OSS Distributions  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49*5e3eaea3SApple OSS Distributions  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50*5e3eaea3SApple OSS Distributions  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51*5e3eaea3SApple OSS Distributions  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52*5e3eaea3SApple OSS Distributions  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53*5e3eaea3SApple OSS Distributions  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54*5e3eaea3SApple OSS Distributions  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55*5e3eaea3SApple OSS Distributions  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56*5e3eaea3SApple OSS Distributions  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57*5e3eaea3SApple OSS Distributions  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58*5e3eaea3SApple OSS Distributions  * SUCH DAMAGE.
59*5e3eaea3SApple OSS Distributions  *
60*5e3eaea3SApple OSS Distributions  *	@(#)in_cksum.c	8.1 (Berkeley) 6/10/93
61*5e3eaea3SApple OSS Distributions  */
62*5e3eaea3SApple OSS Distributions 
63*5e3eaea3SApple OSS Distributions #include <sys/param.h>
64*5e3eaea3SApple OSS Distributions #include <machine/endian.h>
65*5e3eaea3SApple OSS Distributions #include <sys/mbuf.h>
66*5e3eaea3SApple OSS Distributions #include <kern/debug.h>
67*5e3eaea3SApple OSS Distributions #include <net/dlil.h>
68*5e3eaea3SApple OSS Distributions #include <netinet/in.h>
69*5e3eaea3SApple OSS Distributions #define _IP_VHL
70*5e3eaea3SApple OSS Distributions #include <netinet/ip.h>
71*5e3eaea3SApple OSS Distributions #include <netinet/ip_var.h>
72*5e3eaea3SApple OSS Distributions 
73*5e3eaea3SApple OSS Distributions /*
74*5e3eaea3SApple OSS Distributions  * Checksum routine for Internet Protocol family headers (Portable Version).
75*5e3eaea3SApple OSS Distributions  *
76*5e3eaea3SApple OSS Distributions  * This routine is very heavily used in the network
77*5e3eaea3SApple OSS Distributions  * code and should be modified for each CPU to be as fast as possible.
78*5e3eaea3SApple OSS Distributions  */
79*5e3eaea3SApple OSS Distributions #define REDUCE16 {                                                        \
80*5e3eaea3SApple OSS Distributions 	q_util.q = sum;                                                   \
81*5e3eaea3SApple OSS Distributions 	l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
82*5e3eaea3SApple OSS Distributions 	sum = l_util.s[0] + l_util.s[1];                                  \
83*5e3eaea3SApple OSS Distributions 	ADDCARRY(sum);                                                    \
84*5e3eaea3SApple OSS Distributions }
85*5e3eaea3SApple OSS Distributions 
86*5e3eaea3SApple OSS Distributions union l_util {
87*5e3eaea3SApple OSS Distributions 	uint16_t s[2];
88*5e3eaea3SApple OSS Distributions 	uint32_t l;
89*5e3eaea3SApple OSS Distributions };
90*5e3eaea3SApple OSS Distributions 
91*5e3eaea3SApple OSS Distributions union q_util {
92*5e3eaea3SApple OSS Distributions 	uint16_t s[4];
93*5e3eaea3SApple OSS Distributions 	uint32_t l[2];
94*5e3eaea3SApple OSS Distributions 	uint64_t q;
95*5e3eaea3SApple OSS Distributions };
96*5e3eaea3SApple OSS Distributions 
97*5e3eaea3SApple OSS Distributions extern uint32_t os_cpu_in_cksum(const void *, uint32_t, uint32_t);
98*5e3eaea3SApple OSS Distributions 
99*5e3eaea3SApple OSS Distributions /*
100*5e3eaea3SApple OSS Distributions  * Perform 16-bit 1's complement sum on a contiguous span.
101*5e3eaea3SApple OSS Distributions  */
102*5e3eaea3SApple OSS Distributions uint16_t
b_sum16(const void * buf,int len)103*5e3eaea3SApple OSS Distributions b_sum16(const void *buf, int len)
104*5e3eaea3SApple OSS Distributions {
105*5e3eaea3SApple OSS Distributions 	return (uint16_t)os_cpu_in_cksum(buf, len, 0);
106*5e3eaea3SApple OSS Distributions }
107*5e3eaea3SApple OSS Distributions 
108*5e3eaea3SApple OSS Distributions uint16_t inet_cksum_simple(struct mbuf *, int);
109*5e3eaea3SApple OSS Distributions /*
110*5e3eaea3SApple OSS Distributions  * For the exported _in_cksum symbol in BSDKernel symbol set.
111*5e3eaea3SApple OSS Distributions  */
112*5e3eaea3SApple OSS Distributions uint16_t
inet_cksum_simple(struct mbuf * m,int len)113*5e3eaea3SApple OSS Distributions inet_cksum_simple(struct mbuf *m, int len)
114*5e3eaea3SApple OSS Distributions {
115*5e3eaea3SApple OSS Distributions 	return inet_cksum(m, 0, 0, len);
116*5e3eaea3SApple OSS Distributions }
117*5e3eaea3SApple OSS Distributions 
118*5e3eaea3SApple OSS Distributions uint16_t
in_addword(uint16_t a,uint16_t b)119*5e3eaea3SApple OSS Distributions in_addword(uint16_t a, uint16_t b)
120*5e3eaea3SApple OSS Distributions {
121*5e3eaea3SApple OSS Distributions 	uint64_t sum = a + b;
122*5e3eaea3SApple OSS Distributions 
123*5e3eaea3SApple OSS Distributions 	ADDCARRY(sum);
124*5e3eaea3SApple OSS Distributions 	return (uint16_t)sum;
125*5e3eaea3SApple OSS Distributions }
126*5e3eaea3SApple OSS Distributions 
127*5e3eaea3SApple OSS Distributions uint16_t
in_pseudo(uint32_t a,uint32_t b,uint32_t c)128*5e3eaea3SApple OSS Distributions in_pseudo(uint32_t a, uint32_t b, uint32_t c)
129*5e3eaea3SApple OSS Distributions {
130*5e3eaea3SApple OSS Distributions 	uint64_t sum;
131*5e3eaea3SApple OSS Distributions 	union q_util q_util;
132*5e3eaea3SApple OSS Distributions 	union l_util l_util;
133*5e3eaea3SApple OSS Distributions 
134*5e3eaea3SApple OSS Distributions 	sum = (uint64_t)a + b + c;
135*5e3eaea3SApple OSS Distributions 	REDUCE16;
136*5e3eaea3SApple OSS Distributions 	return (uint16_t)sum;
137*5e3eaea3SApple OSS Distributions }
138*5e3eaea3SApple OSS Distributions 
139*5e3eaea3SApple OSS Distributions uint16_t
in_pseudo64(uint64_t a,uint64_t b,uint64_t c)140*5e3eaea3SApple OSS Distributions in_pseudo64(uint64_t a, uint64_t b, uint64_t c)
141*5e3eaea3SApple OSS Distributions {
142*5e3eaea3SApple OSS Distributions 	uint64_t sum;
143*5e3eaea3SApple OSS Distributions 	union q_util q_util;
144*5e3eaea3SApple OSS Distributions 	union l_util l_util;
145*5e3eaea3SApple OSS Distributions 
146*5e3eaea3SApple OSS Distributions 	sum = a + b + c;
147*5e3eaea3SApple OSS Distributions 	REDUCE16;
148*5e3eaea3SApple OSS Distributions 	return (uint16_t)sum;
149*5e3eaea3SApple OSS Distributions }
150*5e3eaea3SApple OSS Distributions 
151*5e3eaea3SApple OSS Distributions /*
152*5e3eaea3SApple OSS Distributions  * May be used on IP header with options.
153*5e3eaea3SApple OSS Distributions  */
154*5e3eaea3SApple OSS Distributions uint16_t
in_cksum_hdr_opt(const struct ip * ip)155*5e3eaea3SApple OSS Distributions in_cksum_hdr_opt(const struct ip *ip)
156*5e3eaea3SApple OSS Distributions {
157*5e3eaea3SApple OSS Distributions 	return ~b_sum16(ip, (IP_VHL_HL(ip->ip_vhl) << 2)) & 0xffff;
158*5e3eaea3SApple OSS Distributions }
159*5e3eaea3SApple OSS Distributions 
160*5e3eaea3SApple OSS Distributions /*
161*5e3eaea3SApple OSS Distributions  * A wrapper around the simple in_cksum_hdr() and the more complicated
162*5e3eaea3SApple OSS Distributions  * inet_cksum(); the former is chosen if the IP header is simple,
163*5e3eaea3SApple OSS Distributions  * contiguous and 32-bit aligned.  Also does some stats accounting.
164*5e3eaea3SApple OSS Distributions  */
165*5e3eaea3SApple OSS Distributions uint16_t
ip_cksum_hdr_dir(struct mbuf * m,uint32_t hlen,int out)166*5e3eaea3SApple OSS Distributions ip_cksum_hdr_dir(struct mbuf *m, uint32_t hlen, int out)
167*5e3eaea3SApple OSS Distributions {
168*5e3eaea3SApple OSS Distributions 	struct ip *ip = mtod(m, struct ip *);
169*5e3eaea3SApple OSS Distributions 
170*5e3eaea3SApple OSS Distributions 	if (out) {
171*5e3eaea3SApple OSS Distributions 		ipstat.ips_snd_swcsum++;
172*5e3eaea3SApple OSS Distributions 		ipstat.ips_snd_swcsum_bytes += hlen;
173*5e3eaea3SApple OSS Distributions 	} else {
174*5e3eaea3SApple OSS Distributions 		ipstat.ips_rcv_swcsum++;
175*5e3eaea3SApple OSS Distributions 		ipstat.ips_rcv_swcsum_bytes += hlen;
176*5e3eaea3SApple OSS Distributions 	}
177*5e3eaea3SApple OSS Distributions 
178*5e3eaea3SApple OSS Distributions 	if (hlen == sizeof(*ip) &&
179*5e3eaea3SApple OSS Distributions 	    m->m_len >= sizeof(*ip) && IP_HDR_ALIGNED_P(ip)) {
180*5e3eaea3SApple OSS Distributions 		return in_cksum_hdr(ip);
181*5e3eaea3SApple OSS Distributions 	}
182*5e3eaea3SApple OSS Distributions 
183*5e3eaea3SApple OSS Distributions 	return inet_cksum(m, 0, 0, hlen);
184*5e3eaea3SApple OSS Distributions }
185*5e3eaea3SApple OSS Distributions 
186*5e3eaea3SApple OSS Distributions uint16_t
ip_cksum_hdr_dir_buffer(const void * buffer,uint32_t hlen,uint32_t len,int out)187*5e3eaea3SApple OSS Distributions ip_cksum_hdr_dir_buffer(const void *buffer, uint32_t hlen, uint32_t len,
188*5e3eaea3SApple OSS Distributions     int out)
189*5e3eaea3SApple OSS Distributions {
190*5e3eaea3SApple OSS Distributions 	const struct ip *ip = buffer;
191*5e3eaea3SApple OSS Distributions 
192*5e3eaea3SApple OSS Distributions 	if (out) {
193*5e3eaea3SApple OSS Distributions 		ipstat.ips_snd_swcsum++;
194*5e3eaea3SApple OSS Distributions 		ipstat.ips_snd_swcsum_bytes += hlen;
195*5e3eaea3SApple OSS Distributions 	} else {
196*5e3eaea3SApple OSS Distributions 		ipstat.ips_rcv_swcsum++;
197*5e3eaea3SApple OSS Distributions 		ipstat.ips_rcv_swcsum_bytes += hlen;
198*5e3eaea3SApple OSS Distributions 	}
199*5e3eaea3SApple OSS Distributions 
200*5e3eaea3SApple OSS Distributions 	if (hlen == sizeof(*ip) &&
201*5e3eaea3SApple OSS Distributions 	    len >= sizeof(*ip) && IP_HDR_ALIGNED_P(ip)) {
202*5e3eaea3SApple OSS Distributions 		return in_cksum_hdr(ip);
203*5e3eaea3SApple OSS Distributions 	}
204*5e3eaea3SApple OSS Distributions 
205*5e3eaea3SApple OSS Distributions 	return inet_cksum_buffer(buffer, 0, 0, hlen);
206*5e3eaea3SApple OSS Distributions }
207*5e3eaea3SApple OSS Distributions 
208*5e3eaea3SApple OSS Distributions /*
209*5e3eaea3SApple OSS Distributions  * m MUST contain at least an IP header, if nxt is specified;
210*5e3eaea3SApple OSS Distributions  * nxt is the upper layer protocol number;
211*5e3eaea3SApple OSS Distributions  * off is an offset where TCP/UDP/ICMP header starts;
212*5e3eaea3SApple OSS Distributions  * len is a total length of a transport segment (e.g. TCP header + TCP payload)
213*5e3eaea3SApple OSS Distributions  */
214*5e3eaea3SApple OSS Distributions uint16_t
inet_cksum(struct mbuf * m,uint32_t nxt,uint32_t off,uint32_t len)215*5e3eaea3SApple OSS Distributions inet_cksum(struct mbuf *m, uint32_t nxt, uint32_t off, uint32_t len)
216*5e3eaea3SApple OSS Distributions {
217*5e3eaea3SApple OSS Distributions 	uint32_t sum;
218*5e3eaea3SApple OSS Distributions 
219*5e3eaea3SApple OSS Distributions 	sum = m_sum16(m, off, len);
220*5e3eaea3SApple OSS Distributions 
221*5e3eaea3SApple OSS Distributions 	/* include pseudo header checksum? */
222*5e3eaea3SApple OSS Distributions 	if (nxt != 0) {
223*5e3eaea3SApple OSS Distributions 		struct ip *ip;
224*5e3eaea3SApple OSS Distributions 		unsigned char buf[sizeof((*ip))] __attribute__((aligned(8)));
225*5e3eaea3SApple OSS Distributions 		uint32_t mlen;
226*5e3eaea3SApple OSS Distributions 
227*5e3eaea3SApple OSS Distributions 		/*
228*5e3eaea3SApple OSS Distributions 		 * Sanity check
229*5e3eaea3SApple OSS Distributions 		 *
230*5e3eaea3SApple OSS Distributions 		 * Use m_length2() instead of m_length(), as we cannot rely on
231*5e3eaea3SApple OSS Distributions 		 * the caller setting m_pkthdr.len correctly, if the mbuf is
232*5e3eaea3SApple OSS Distributions 		 * a M_PKTHDR one.
233*5e3eaea3SApple OSS Distributions 		 */
234*5e3eaea3SApple OSS Distributions 		if ((mlen = m_length2(m, NULL)) < sizeof(*ip)) {
235*5e3eaea3SApple OSS Distributions 			panic("%s: mbuf %p too short (%d) for IPv4 header",
236*5e3eaea3SApple OSS Distributions 			    __func__, m, mlen);
237*5e3eaea3SApple OSS Distributions 			/* NOTREACHED */
238*5e3eaea3SApple OSS Distributions 		}
239*5e3eaea3SApple OSS Distributions 
240*5e3eaea3SApple OSS Distributions 		/*
241*5e3eaea3SApple OSS Distributions 		 * In case the IP header is not contiguous, or not 32-bit
242*5e3eaea3SApple OSS Distributions 		 * aligned, copy it to a local buffer.  Note here that we
243*5e3eaea3SApple OSS Distributions 		 * expect the data pointer to point to the IP header.
244*5e3eaea3SApple OSS Distributions 		 */
245*5e3eaea3SApple OSS Distributions 		if ((sizeof(*ip) > m->m_len) ||
246*5e3eaea3SApple OSS Distributions 		    !IP_HDR_ALIGNED_P(mtod(m, caddr_t))) {
247*5e3eaea3SApple OSS Distributions 			m_copydata(m, 0, sizeof(*ip), (caddr_t)buf);
248*5e3eaea3SApple OSS Distributions 			ip = (struct ip *)(void *)buf;
249*5e3eaea3SApple OSS Distributions 		} else {
250*5e3eaea3SApple OSS Distributions 			ip = (struct ip *)(void *)(m->m_data);
251*5e3eaea3SApple OSS Distributions 		}
252*5e3eaea3SApple OSS Distributions 
253*5e3eaea3SApple OSS Distributions 		/* add pseudo header checksum */
254*5e3eaea3SApple OSS Distributions 		sum += in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
255*5e3eaea3SApple OSS Distributions 		    htonl(len + nxt));
256*5e3eaea3SApple OSS Distributions 
257*5e3eaea3SApple OSS Distributions 		/* fold in carry bits */
258*5e3eaea3SApple OSS Distributions 		ADDCARRY(sum);
259*5e3eaea3SApple OSS Distributions 	}
260*5e3eaea3SApple OSS Distributions 
261*5e3eaea3SApple OSS Distributions 	return ~sum & 0xffff;
262*5e3eaea3SApple OSS Distributions }
263*5e3eaea3SApple OSS Distributions 
264*5e3eaea3SApple OSS Distributions /*
265*5e3eaea3SApple OSS Distributions  * buffer MUST contain at least an IP header, if nxt is specified;
266*5e3eaea3SApple OSS Distributions  * nxt is the upper layer protocol number;
267*5e3eaea3SApple OSS Distributions  * off is an offset where TCP/UDP/ICMP header starts;
268*5e3eaea3SApple OSS Distributions  * len is a total length of a transport segment (e.g. TCP header + TCP payload)
269*5e3eaea3SApple OSS Distributions  */
270*5e3eaea3SApple OSS Distributions uint16_t
inet_cksum_buffer(const void * buffer,uint32_t nxt,uint32_t off,uint32_t len)271*5e3eaea3SApple OSS Distributions inet_cksum_buffer(const void *buffer, uint32_t nxt, uint32_t off,
272*5e3eaea3SApple OSS Distributions     uint32_t len)
273*5e3eaea3SApple OSS Distributions {
274*5e3eaea3SApple OSS Distributions 	uint32_t sum;
275*5e3eaea3SApple OSS Distributions 
276*5e3eaea3SApple OSS Distributions 	if (off >= len) {
277*5e3eaea3SApple OSS Distributions 		panic("%s: off (%d) >= len (%d)", __func__, off, len);
278*5e3eaea3SApple OSS Distributions 	}
279*5e3eaea3SApple OSS Distributions 
280*5e3eaea3SApple OSS Distributions 	sum = b_sum16(&((const uint8_t *)buffer)[off], len);
281*5e3eaea3SApple OSS Distributions 
282*5e3eaea3SApple OSS Distributions 	/* include pseudo header checksum? */
283*5e3eaea3SApple OSS Distributions 	if (nxt != 0) {
284*5e3eaea3SApple OSS Distributions 		const struct ip *ip;
285*5e3eaea3SApple OSS Distributions 		unsigned char buf[sizeof((*ip))] __attribute__((aligned(8)));
286*5e3eaea3SApple OSS Distributions 
287*5e3eaea3SApple OSS Distributions 		/*
288*5e3eaea3SApple OSS Distributions 		 * In case the IP header is not contiguous, or not 32-bit
289*5e3eaea3SApple OSS Distributions 		 * aligned, copy it to a local buffer.  Note here that we
290*5e3eaea3SApple OSS Distributions 		 * expect the data pointer to point to the IP header.
291*5e3eaea3SApple OSS Distributions 		 */
292*5e3eaea3SApple OSS Distributions 		if (!IP_HDR_ALIGNED_P(buffer)) {
293*5e3eaea3SApple OSS Distributions 			memcpy(buf, buffer, sizeof(*ip));
294*5e3eaea3SApple OSS Distributions 			ip = (const struct ip *)(const void *)buf;
295*5e3eaea3SApple OSS Distributions 		} else {
296*5e3eaea3SApple OSS Distributions 			ip = (const struct ip *)buffer;
297*5e3eaea3SApple OSS Distributions 		}
298*5e3eaea3SApple OSS Distributions 
299*5e3eaea3SApple OSS Distributions 		/* add pseudo header checksum */
300*5e3eaea3SApple OSS Distributions 		sum += in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
301*5e3eaea3SApple OSS Distributions 		    htonl(len + nxt));
302*5e3eaea3SApple OSS Distributions 
303*5e3eaea3SApple OSS Distributions 		/* fold in carry bits */
304*5e3eaea3SApple OSS Distributions 		ADDCARRY(sum);
305*5e3eaea3SApple OSS Distributions 	}
306*5e3eaea3SApple OSS Distributions 
307*5e3eaea3SApple OSS Distributions 	return ~sum & 0xffff;
308*5e3eaea3SApple OSS Distributions }
309*5e3eaea3SApple OSS Distributions 
310*5e3eaea3SApple OSS Distributions #if DEBUG || DEVELOPMENT
311*5e3eaea3SApple OSS Distributions #include <pexpert/pexpert.h>
312*5e3eaea3SApple OSS Distributions 
313*5e3eaea3SApple OSS Distributions #define CKSUM_ERR kprintf
314*5e3eaea3SApple OSS Distributions 
315*5e3eaea3SApple OSS Distributions /*
316*5e3eaea3SApple OSS Distributions  * The following routines implement the portable, reference implementation
317*5e3eaea3SApple OSS Distributions  * of os_cpu_in_cksum_mbuf().  This is currently used only for validating
318*5e3eaea3SApple OSS Distributions  * the correctness of the platform-specific implementation, at boot time
319*5e3eaea3SApple OSS Distributions  * in dlil_verify_sum16().  It returns the 32-bit accumulator without doing
320*5e3eaea3SApple OSS Distributions  * a 1's complement on it.
321*5e3eaea3SApple OSS Distributions  */
322*5e3eaea3SApple OSS Distributions #if !defined(__LP64__)
323*5e3eaea3SApple OSS Distributions /* 32-bit version */
324*5e3eaea3SApple OSS Distributions uint32_t
in_cksum_mbuf_ref(struct mbuf * m,int len,int off,uint32_t initial_sum)325*5e3eaea3SApple OSS Distributions in_cksum_mbuf_ref(struct mbuf *m, int len, int off, uint32_t initial_sum)
326*5e3eaea3SApple OSS Distributions {
327*5e3eaea3SApple OSS Distributions 	int mlen;
328*5e3eaea3SApple OSS Distributions 	uint32_t sum, partial;
329*5e3eaea3SApple OSS Distributions 	unsigned int final_acc;
330*5e3eaea3SApple OSS Distributions 	uint8_t *data;
331*5e3eaea3SApple OSS Distributions 	boolean_t needs_swap, started_on_odd;
332*5e3eaea3SApple OSS Distributions 
333*5e3eaea3SApple OSS Distributions 	VERIFY(len >= 0);
334*5e3eaea3SApple OSS Distributions 	VERIFY(off >= 0);
335*5e3eaea3SApple OSS Distributions 
336*5e3eaea3SApple OSS Distributions 	needs_swap = FALSE;
337*5e3eaea3SApple OSS Distributions 	started_on_odd = FALSE;
338*5e3eaea3SApple OSS Distributions 	sum = (initial_sum >> 16) + (initial_sum & 0xffff);
339*5e3eaea3SApple OSS Distributions 
340*5e3eaea3SApple OSS Distributions 	for (;;) {
341*5e3eaea3SApple OSS Distributions 		if (__improbable(m == NULL)) {
342*5e3eaea3SApple OSS Distributions 			CKSUM_ERR("%s: out of data\n", __func__);
343*5e3eaea3SApple OSS Distributions 			return (uint32_t)-1;
344*5e3eaea3SApple OSS Distributions 		}
345*5e3eaea3SApple OSS Distributions 		mlen = m->m_len;
346*5e3eaea3SApple OSS Distributions 		if (mlen > off) {
347*5e3eaea3SApple OSS Distributions 			mlen -= off;
348*5e3eaea3SApple OSS Distributions 			data = mtod(m, uint8_t *) + off;
349*5e3eaea3SApple OSS Distributions 			goto post_initial_offset;
350*5e3eaea3SApple OSS Distributions 		}
351*5e3eaea3SApple OSS Distributions 		off -= mlen;
352*5e3eaea3SApple OSS Distributions 		if (len == 0) {
353*5e3eaea3SApple OSS Distributions 			break;
354*5e3eaea3SApple OSS Distributions 		}
355*5e3eaea3SApple OSS Distributions 		m = m->m_next;
356*5e3eaea3SApple OSS Distributions 	}
357*5e3eaea3SApple OSS Distributions 
358*5e3eaea3SApple OSS Distributions 	for (; len > 0; m = m->m_next) {
359*5e3eaea3SApple OSS Distributions 		if (__improbable(m == NULL)) {
360*5e3eaea3SApple OSS Distributions 			CKSUM_ERR("%s: out of data\n", __func__);
361*5e3eaea3SApple OSS Distributions 			return (uint32_t)-1;
362*5e3eaea3SApple OSS Distributions 		}
363*5e3eaea3SApple OSS Distributions 		mlen = m->m_len;
364*5e3eaea3SApple OSS Distributions 		data = mtod(m, uint8_t *);
365*5e3eaea3SApple OSS Distributions post_initial_offset:
366*5e3eaea3SApple OSS Distributions 		if (mlen == 0) {
367*5e3eaea3SApple OSS Distributions 			continue;
368*5e3eaea3SApple OSS Distributions 		}
369*5e3eaea3SApple OSS Distributions 		if (mlen > len) {
370*5e3eaea3SApple OSS Distributions 			mlen = len;
371*5e3eaea3SApple OSS Distributions 		}
372*5e3eaea3SApple OSS Distributions 		len -= mlen;
373*5e3eaea3SApple OSS Distributions 
374*5e3eaea3SApple OSS Distributions 		partial = 0;
375*5e3eaea3SApple OSS Distributions 		if ((uintptr_t)data & 1) {
376*5e3eaea3SApple OSS Distributions 			/* Align on word boundary */
377*5e3eaea3SApple OSS Distributions 			started_on_odd = !started_on_odd;
378*5e3eaea3SApple OSS Distributions #if BYTE_ORDER == LITTLE_ENDIAN
379*5e3eaea3SApple OSS Distributions 			partial = *data << 8;
380*5e3eaea3SApple OSS Distributions #else /* BYTE_ORDER != LITTLE_ENDIAN */
381*5e3eaea3SApple OSS Distributions 			partial = *data;
382*5e3eaea3SApple OSS Distributions #endif /* BYTE_ORDER != LITTLE_ENDIAN */
383*5e3eaea3SApple OSS Distributions 			++data;
384*5e3eaea3SApple OSS Distributions 			--mlen;
385*5e3eaea3SApple OSS Distributions 		}
386*5e3eaea3SApple OSS Distributions 		needs_swap = started_on_odd;
387*5e3eaea3SApple OSS Distributions 		while (mlen >= 32) {
388*5e3eaea3SApple OSS Distributions 			__builtin_prefetch(data + 32);
389*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)data;
390*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 2);
391*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 4);
392*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 6);
393*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 8);
394*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 10);
395*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 12);
396*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 14);
397*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 16);
398*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 18);
399*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 20);
400*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 22);
401*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 24);
402*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 26);
403*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 28);
404*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 30);
405*5e3eaea3SApple OSS Distributions 			data += 32;
406*5e3eaea3SApple OSS Distributions 			mlen -= 32;
407*5e3eaea3SApple OSS Distributions 			if (__improbable(partial & 0xc0000000)) {
408*5e3eaea3SApple OSS Distributions 				if (needs_swap) {
409*5e3eaea3SApple OSS Distributions 					partial = (partial << 8) +
410*5e3eaea3SApple OSS Distributions 					    (partial >> 24);
411*5e3eaea3SApple OSS Distributions 				}
412*5e3eaea3SApple OSS Distributions 				sum += (partial >> 16);
413*5e3eaea3SApple OSS Distributions 				sum += (partial & 0xffff);
414*5e3eaea3SApple OSS Distributions 				partial = 0;
415*5e3eaea3SApple OSS Distributions 			}
416*5e3eaea3SApple OSS Distributions 		}
417*5e3eaea3SApple OSS Distributions 		if (mlen & 16) {
418*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)data;
419*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 2);
420*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 4);
421*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 6);
422*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 8);
423*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 10);
424*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 12);
425*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 14);
426*5e3eaea3SApple OSS Distributions 			data += 16;
427*5e3eaea3SApple OSS Distributions 			mlen -= 16;
428*5e3eaea3SApple OSS Distributions 		}
429*5e3eaea3SApple OSS Distributions 		/*
430*5e3eaea3SApple OSS Distributions 		 * mlen is not updated below as the remaining tests
431*5e3eaea3SApple OSS Distributions 		 * are using bit masks, which are not affected.
432*5e3eaea3SApple OSS Distributions 		 */
433*5e3eaea3SApple OSS Distributions 		if (mlen & 8) {
434*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)data;
435*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 2);
436*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 4);
437*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 6);
438*5e3eaea3SApple OSS Distributions 			data += 8;
439*5e3eaea3SApple OSS Distributions 		}
440*5e3eaea3SApple OSS Distributions 		if (mlen & 4) {
441*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)data;
442*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)(data + 2);
443*5e3eaea3SApple OSS Distributions 			data += 4;
444*5e3eaea3SApple OSS Distributions 		}
445*5e3eaea3SApple OSS Distributions 		if (mlen & 2) {
446*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)data;
447*5e3eaea3SApple OSS Distributions 			data += 2;
448*5e3eaea3SApple OSS Distributions 		}
449*5e3eaea3SApple OSS Distributions 		if (mlen & 1) {
450*5e3eaea3SApple OSS Distributions #if BYTE_ORDER == LITTLE_ENDIAN
451*5e3eaea3SApple OSS Distributions 			partial += *data;
452*5e3eaea3SApple OSS Distributions #else /* BYTE_ORDER != LITTLE_ENDIAN */
453*5e3eaea3SApple OSS Distributions 			partial += *data << 8;
454*5e3eaea3SApple OSS Distributions #endif /* BYTE_ORDER != LITTLE_ENDIAN */
455*5e3eaea3SApple OSS Distributions 			started_on_odd = !started_on_odd;
456*5e3eaea3SApple OSS Distributions 		}
457*5e3eaea3SApple OSS Distributions 
458*5e3eaea3SApple OSS Distributions 		if (needs_swap) {
459*5e3eaea3SApple OSS Distributions 			partial = (partial << 8) + (partial >> 24);
460*5e3eaea3SApple OSS Distributions 		}
461*5e3eaea3SApple OSS Distributions 		sum += (partial >> 16) + (partial & 0xffff);
462*5e3eaea3SApple OSS Distributions 		/*
463*5e3eaea3SApple OSS Distributions 		 * Reduce sum to allow potential byte swap
464*5e3eaea3SApple OSS Distributions 		 * in the next iteration without carry.
465*5e3eaea3SApple OSS Distributions 		 */
466*5e3eaea3SApple OSS Distributions 		sum = (sum >> 16) + (sum & 0xffff);
467*5e3eaea3SApple OSS Distributions 	}
468*5e3eaea3SApple OSS Distributions 	final_acc = ((sum >> 16) & 0xffff) + (sum & 0xffff);
469*5e3eaea3SApple OSS Distributions 	final_acc = (final_acc >> 16) + (final_acc & 0xffff);
470*5e3eaea3SApple OSS Distributions 	return final_acc & 0xffff;
471*5e3eaea3SApple OSS Distributions }
472*5e3eaea3SApple OSS Distributions 
473*5e3eaea3SApple OSS Distributions #else /* __LP64__ */
474*5e3eaea3SApple OSS Distributions /* 64-bit version */
475*5e3eaea3SApple OSS Distributions uint32_t
in_cksum_mbuf_ref(struct mbuf * m,int len,int off,uint32_t initial_sum)476*5e3eaea3SApple OSS Distributions in_cksum_mbuf_ref(struct mbuf *m, int len, int off, uint32_t initial_sum)
477*5e3eaea3SApple OSS Distributions {
478*5e3eaea3SApple OSS Distributions 	int mlen;
479*5e3eaea3SApple OSS Distributions 	uint64_t sum, partial;
480*5e3eaea3SApple OSS Distributions 	unsigned int final_acc;
481*5e3eaea3SApple OSS Distributions 	uint8_t *data;
482*5e3eaea3SApple OSS Distributions 	boolean_t needs_swap, started_on_odd;
483*5e3eaea3SApple OSS Distributions 
484*5e3eaea3SApple OSS Distributions 	VERIFY(len >= 0);
485*5e3eaea3SApple OSS Distributions 	VERIFY(off >= 0);
486*5e3eaea3SApple OSS Distributions 
487*5e3eaea3SApple OSS Distributions 	needs_swap = FALSE;
488*5e3eaea3SApple OSS Distributions 	started_on_odd = FALSE;
489*5e3eaea3SApple OSS Distributions 	sum = initial_sum;
490*5e3eaea3SApple OSS Distributions 
491*5e3eaea3SApple OSS Distributions 	for (;;) {
492*5e3eaea3SApple OSS Distributions 		if (__improbable(m == NULL)) {
493*5e3eaea3SApple OSS Distributions 			CKSUM_ERR("%s: out of data\n", __func__);
494*5e3eaea3SApple OSS Distributions 			return (uint32_t)-1;
495*5e3eaea3SApple OSS Distributions 		}
496*5e3eaea3SApple OSS Distributions 		mlen = m->m_len;
497*5e3eaea3SApple OSS Distributions 		if (mlen > off) {
498*5e3eaea3SApple OSS Distributions 			mlen -= off;
499*5e3eaea3SApple OSS Distributions 			data = mtod(m, uint8_t *) + off;
500*5e3eaea3SApple OSS Distributions 			goto post_initial_offset;
501*5e3eaea3SApple OSS Distributions 		}
502*5e3eaea3SApple OSS Distributions 		off -= mlen;
503*5e3eaea3SApple OSS Distributions 		if (len == 0) {
504*5e3eaea3SApple OSS Distributions 			break;
505*5e3eaea3SApple OSS Distributions 		}
506*5e3eaea3SApple OSS Distributions 		m = m->m_next;
507*5e3eaea3SApple OSS Distributions 	}
508*5e3eaea3SApple OSS Distributions 
509*5e3eaea3SApple OSS Distributions 	for (; len > 0; m = m->m_next) {
510*5e3eaea3SApple OSS Distributions 		if (__improbable(m == NULL)) {
511*5e3eaea3SApple OSS Distributions 			CKSUM_ERR("%s: out of data\n", __func__);
512*5e3eaea3SApple OSS Distributions 			return (uint32_t)-1;
513*5e3eaea3SApple OSS Distributions 		}
514*5e3eaea3SApple OSS Distributions 		mlen = m->m_len;
515*5e3eaea3SApple OSS Distributions 		data = mtod(m, uint8_t *);
516*5e3eaea3SApple OSS Distributions post_initial_offset:
517*5e3eaea3SApple OSS Distributions 		if (mlen == 0) {
518*5e3eaea3SApple OSS Distributions 			continue;
519*5e3eaea3SApple OSS Distributions 		}
520*5e3eaea3SApple OSS Distributions 		if (mlen > len) {
521*5e3eaea3SApple OSS Distributions 			mlen = len;
522*5e3eaea3SApple OSS Distributions 		}
523*5e3eaea3SApple OSS Distributions 		len -= mlen;
524*5e3eaea3SApple OSS Distributions 
525*5e3eaea3SApple OSS Distributions 		partial = 0;
526*5e3eaea3SApple OSS Distributions 		if ((uintptr_t)data & 1) {
527*5e3eaea3SApple OSS Distributions 			/* Align on word boundary */
528*5e3eaea3SApple OSS Distributions 			started_on_odd = !started_on_odd;
529*5e3eaea3SApple OSS Distributions #if BYTE_ORDER == LITTLE_ENDIAN
530*5e3eaea3SApple OSS Distributions 			partial = *data << 8;
531*5e3eaea3SApple OSS Distributions #else /* BYTE_ORDER != LITTLE_ENDIAN */
532*5e3eaea3SApple OSS Distributions 			partial = *data;
533*5e3eaea3SApple OSS Distributions #endif /* BYTE_ORDER != LITTLE_ENDIAN */
534*5e3eaea3SApple OSS Distributions 			++data;
535*5e3eaea3SApple OSS Distributions 			--mlen;
536*5e3eaea3SApple OSS Distributions 		}
537*5e3eaea3SApple OSS Distributions 		needs_swap = started_on_odd;
538*5e3eaea3SApple OSS Distributions 		if ((uintptr_t)data & 2) {
539*5e3eaea3SApple OSS Distributions 			if (mlen < 2) {
540*5e3eaea3SApple OSS Distributions 				goto trailing_bytes;
541*5e3eaea3SApple OSS Distributions 			}
542*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)data;
543*5e3eaea3SApple OSS Distributions 			data += 2;
544*5e3eaea3SApple OSS Distributions 			mlen -= 2;
545*5e3eaea3SApple OSS Distributions 		}
546*5e3eaea3SApple OSS Distributions 		while (mlen >= 64) {
547*5e3eaea3SApple OSS Distributions 			__builtin_prefetch(data + 32);
548*5e3eaea3SApple OSS Distributions 			__builtin_prefetch(data + 64);
549*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)data;
550*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 4);
551*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 8);
552*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 12);
553*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 16);
554*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 20);
555*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 24);
556*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 28);
557*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 32);
558*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 36);
559*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 40);
560*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 44);
561*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 48);
562*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 52);
563*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 56);
564*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 60);
565*5e3eaea3SApple OSS Distributions 			data += 64;
566*5e3eaea3SApple OSS Distributions 			mlen -= 64;
567*5e3eaea3SApple OSS Distributions 			if (__improbable(partial & (3ULL << 62))) {
568*5e3eaea3SApple OSS Distributions 				if (needs_swap) {
569*5e3eaea3SApple OSS Distributions 					partial = (partial << 8) +
570*5e3eaea3SApple OSS Distributions 					    (partial >> 56);
571*5e3eaea3SApple OSS Distributions 				}
572*5e3eaea3SApple OSS Distributions 				sum += (partial >> 32);
573*5e3eaea3SApple OSS Distributions 				sum += (partial & 0xffffffff);
574*5e3eaea3SApple OSS Distributions 				partial = 0;
575*5e3eaea3SApple OSS Distributions 			}
576*5e3eaea3SApple OSS Distributions 		}
577*5e3eaea3SApple OSS Distributions 		/*
578*5e3eaea3SApple OSS Distributions 		 * mlen is not updated below as the remaining tests
579*5e3eaea3SApple OSS Distributions 		 * are using bit masks, which are not affected.
580*5e3eaea3SApple OSS Distributions 		 */
581*5e3eaea3SApple OSS Distributions 		if (mlen & 32) {
582*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)data;
583*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 4);
584*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 8);
585*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 12);
586*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 16);
587*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 20);
588*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 24);
589*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 28);
590*5e3eaea3SApple OSS Distributions 			data += 32;
591*5e3eaea3SApple OSS Distributions 		}
592*5e3eaea3SApple OSS Distributions 		if (mlen & 16) {
593*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)data;
594*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 4);
595*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 8);
596*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 12);
597*5e3eaea3SApple OSS Distributions 			data += 16;
598*5e3eaea3SApple OSS Distributions 		}
599*5e3eaea3SApple OSS Distributions 		if (mlen & 8) {
600*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)data;
601*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)(data + 4);
602*5e3eaea3SApple OSS Distributions 			data += 8;
603*5e3eaea3SApple OSS Distributions 		}
604*5e3eaea3SApple OSS Distributions 		if (mlen & 4) {
605*5e3eaea3SApple OSS Distributions 			partial += *(uint32_t *)(void *)data;
606*5e3eaea3SApple OSS Distributions 			data += 4;
607*5e3eaea3SApple OSS Distributions 		}
608*5e3eaea3SApple OSS Distributions 		if (mlen & 2) {
609*5e3eaea3SApple OSS Distributions 			partial += *(uint16_t *)(void *)data;
610*5e3eaea3SApple OSS Distributions 			data += 2;
611*5e3eaea3SApple OSS Distributions 		}
612*5e3eaea3SApple OSS Distributions trailing_bytes:
613*5e3eaea3SApple OSS Distributions 		if (mlen & 1) {
614*5e3eaea3SApple OSS Distributions #if BYTE_ORDER == LITTLE_ENDIAN
615*5e3eaea3SApple OSS Distributions 			partial += *data;
616*5e3eaea3SApple OSS Distributions #else /* BYTE_ORDER != LITTLE_ENDIAN */
617*5e3eaea3SApple OSS Distributions 			partial += *data << 8;
618*5e3eaea3SApple OSS Distributions #endif /* BYTE_ORDER != LITTLE_ENDIAN */
619*5e3eaea3SApple OSS Distributions 			started_on_odd = !started_on_odd;
620*5e3eaea3SApple OSS Distributions 		}
621*5e3eaea3SApple OSS Distributions 
622*5e3eaea3SApple OSS Distributions 		if (needs_swap) {
623*5e3eaea3SApple OSS Distributions 			partial = (partial << 8) + (partial >> 56);
624*5e3eaea3SApple OSS Distributions 		}
625*5e3eaea3SApple OSS Distributions 		sum += (partial >> 32) + (partial & 0xffffffff);
626*5e3eaea3SApple OSS Distributions 		/*
627*5e3eaea3SApple OSS Distributions 		 * Reduce sum to allow potential byte swap
628*5e3eaea3SApple OSS Distributions 		 * in the next iteration without carry.
629*5e3eaea3SApple OSS Distributions 		 */
630*5e3eaea3SApple OSS Distributions 		sum = (sum >> 32) + (sum & 0xffffffff);
631*5e3eaea3SApple OSS Distributions 	}
632*5e3eaea3SApple OSS Distributions 	final_acc = (sum >> 48) + ((sum >> 32) & 0xffff) +
633*5e3eaea3SApple OSS Distributions 	    ((sum >> 16) & 0xffff) + (sum & 0xffff);
634*5e3eaea3SApple OSS Distributions 	final_acc = (final_acc >> 16) + (final_acc & 0xffff);
635*5e3eaea3SApple OSS Distributions 	final_acc = (final_acc >> 16) + (final_acc & 0xffff);
636*5e3eaea3SApple OSS Distributions 	return final_acc & 0xffff;
637*5e3eaea3SApple OSS Distributions }
638*5e3eaea3SApple OSS Distributions #endif /* __LP64 */
639*5e3eaea3SApple OSS Distributions #endif /* DEBUG || DEVELOPMENT */
640