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