1/*
2 * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29/*
30 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 *    notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 *    notice, this list of conditions and the following disclaimer in the
40 *    documentation and/or other materials provided with the distribution.
41 * 3. Neither the name of the project nor the names of its contributors
42 *    may be used to endorse or promote products derived from this software
43 *    without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58/*
59 * Copyright (c) 1988, 1992, 1993
60 *	The Regents of the University of California.  All rights reserved.
61 *
62 * Redistribution and use in source and binary forms, with or without
63 * modification, are permitted provided that the following conditions
64 * are met:
65 * 1. Redistributions of source code must retain the above copyright
66 *    notice, this list of conditions and the following disclaimer.
67 * 2. Redistributions in binary form must reproduce the above copyright
68 *    notice, this list of conditions and the following disclaimer in the
69 *    documentation and/or other materials provided with the distribution.
70 * 3. All advertising materials mentioning features or use of this software
71 *    must display the following acknowledgement:
72 *	This product includes software developed by the University of
73 *	California, Berkeley and its contributors.
74 * 4. Neither the name of the University nor the names of its contributors
75 *    may be used to endorse or promote products derived from this software
76 *    without specific prior written permission.
77 *
78 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
79 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
80 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
81 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
82 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
83 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
84 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
85 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
86 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
87 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
88 * SUCH DAMAGE.
89 *
90 *	@(#)in_cksum.c	8.1 (Berkeley) 6/10/93
91 */
92
93/*-
94 * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
95 * All rights reserved.
96 *
97 * Redistribution and use in source and binary forms, with or without
98 * modification, are permitted provided that the following conditions
99 * are met:
100 *
101 * 1. Redistributions of source code must retain the above copyright
102 *    notice, this list of conditions and the following disclaimer.
103 * 2. Redistributions in binary form must reproduce the above copyright
104 *    notice, this list of conditions and the following disclaimer in
105 *    the documentation and/or other materials provided with the
106 *    distribution.
107 *
108 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
109 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
110 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
111 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
112 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
113 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
114 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
115 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
116 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
117 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
118 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
119 * SUCH DAMAGE.
120 */
121
122#include <sys/param.h>
123#include <sys/mbuf.h>
124#include <sys/systm.h>
125#include <kern/debug.h>
126#include <netinet/in.h>
127#include <netinet/ip6.h>
128
129#include <net/net_osdep.h>
130
131#include <machine/endian.h>
132
133
134
135/*
136 * Checksum routine for Internet Protocol family headers (Portable Version).
137 *
138 * This routine is very heavily used in the network
139 * code and should be modified for each CPU to be as fast as possible.
140 */
141
142#define ADDCARRY(x)  do { if (x > 65535) { x -= 65535; } } while (0)
143#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
144
145/*
146 * m MUST contain a continuous IP6 header.
147 * off is a offset where TCP/UDP/ICMP6 header starts.
148 * len is a total length of a transport segment.
149 * (e.g. TCP header + TCP payload)
150 */
151
152u_int16_t
153inet6_cksum(struct mbuf *m, unsigned int nxt, unsigned int off,
154    unsigned int len)
155{
156	u_int16_t *w;
157	int sum = 0;
158	int mlen = 0;
159	int byte_swapped = 0;
160	struct ip6_hdr *ip6;
161	union {
162		u_int16_t phs[4];
163		struct {
164			u_int32_t	ph_len;
165			u_int8_t	ph_zero[3];
166			u_int8_t	ph_nxt;
167		} ph __attribute__((__packed__));
168	} uph;
169	union {
170		u_int8_t	c[2];
171		u_int16_t	s;
172	} s_util;
173	union {
174		u_int16_t s[2];
175		u_int32_t l;
176	} l_util;
177
178	/* sanity check */
179	if ((m->m_flags & M_PKTHDR) && m->m_pkthdr.len < off + len) {
180		panic("inet6_cksum: mbuf len (%d) < off+len (%d+%d)\n",
181		    m->m_pkthdr.len, off, len);
182	}
183
184	if (nxt != 0) {
185		bzero(&uph, sizeof (uph));
186
187		/*
188		 * First create IP6 pseudo header and calculate a summary.
189		 */
190		ip6 = mtod(m, struct ip6_hdr *);
191		w = (u_int16_t *)&ip6->ip6_src;
192		uph.ph.ph_len = htonl(len);
193		uph.ph.ph_nxt = nxt;
194
195		/* IPv6 source address */
196		sum += w[0];
197		if (!IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
198			sum += w[1];
199		sum += w[2]; sum += w[3]; sum += w[4]; sum += w[5];
200		sum += w[6]; sum += w[7];
201		/* IPv6 destination address */
202		sum += w[8];
203		if (!IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
204			sum += w[9];
205		sum += w[10]; sum += w[11]; sum += w[12]; sum += w[13];
206		sum += w[14]; sum += w[15];
207		/* Payload length and upper layer identifier */
208		sum += uph.phs[0];  sum += uph.phs[1];
209		sum += uph.phs[2];  sum += uph.phs[3];
210	}
211
212	/*
213	 * Secondly calculate a summary of the first mbuf excluding offset.
214	 */
215	while (m != NULL && off > 0) {
216		if (m->m_len <= off)
217			off -= m->m_len;
218		else
219			break;
220		m = m->m_next;
221	}
222	w = (u_int16_t *)(void *)(mtod(m, u_char *) + off);
223	mlen = m->m_len - off;
224	if (len < mlen)
225		mlen = len;
226	len -= mlen;
227	/*
228	 * Force to even boundary.
229	 */
230	if ((1 & (intptr_t) w) && (mlen > 0)) {
231		REDUCE;
232		sum <<= 8;
233		s_util.c[0] = *(u_char *)w;
234		w = (u_int16_t *)(void *)((char *)w + 1);
235		mlen--;
236		byte_swapped = 1;
237	}
238	/*
239	 * Unroll the loop to make overhead from
240	 * branches &c small.
241	 */
242	while ((mlen -= 32) >= 0) {
243		sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
244		sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
245		sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
246		sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
247		w += 16;
248	}
249	mlen += 32;
250	while ((mlen -= 8) >= 0) {
251		sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
252		w += 4;
253	}
254	mlen += 8;
255	if (mlen == 0 && byte_swapped == 0)
256		goto next;
257	REDUCE;
258	while ((mlen -= 2) >= 0) {
259		sum += *w++;
260	}
261	if (byte_swapped) {
262		REDUCE;
263		sum <<= 8;
264		byte_swapped = 0;
265		if (mlen == -1) {
266			s_util.c[1] = *(char *)w;
267			sum += s_util.s;
268			mlen = 0;
269		} else
270			mlen = -1;
271	} else if (mlen == -1)
272		s_util.c[0] = *(char *)w;
273 next:
274	m = m->m_next;
275
276	/*
277	 * Lastly calculate a summary of the rest of mbufs.
278	 */
279
280	for (;m && len; m = m->m_next) {
281		if (m->m_len == 0)
282			continue;
283		w = mtod(m, u_int16_t *);
284		if (mlen == -1) {
285			/*
286			 * The first byte of this mbuf is the continuation
287			 * of a word spanning between this mbuf and the
288			 * last mbuf.
289			 *
290			 * s_util.c[0] is already saved when scanning previous
291			 * mbuf.
292			 */
293			s_util.c[1] = *(char *)w;
294			sum += s_util.s;
295			w = (u_int16_t *)(void *)((char *)w + 1);
296			mlen = m->m_len - 1;
297			len--;
298		} else
299			mlen = m->m_len;
300		if (len < mlen)
301			mlen = len;
302		len -= mlen;
303		/*
304		 * Force to even boundary.
305		 */
306		if ((1 & (intptr_t) w) && (mlen > 0)) {
307			REDUCE;
308			sum <<= 8;
309			s_util.c[0] = *(u_char *)w;
310			w = (u_int16_t *)(void *)((char *)w + 1);
311			mlen--;
312			byte_swapped = 1;
313		}
314		/*
315		 * Unroll the loop to make overhead from
316		 * branches &c small.
317		 */
318		while ((mlen -= 32) >= 0) {
319			sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
320			sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
321			sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
322			sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
323			w += 16;
324		}
325		mlen += 32;
326		while ((mlen -= 8) >= 0) {
327			sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
328			w += 4;
329		}
330		mlen += 8;
331		if (mlen == 0 && byte_swapped == 0)
332			continue;
333		REDUCE;
334		while ((mlen -= 2) >= 0) {
335			sum += *w++;
336		}
337		if (byte_swapped) {
338			REDUCE;
339			sum <<= 8;
340			byte_swapped = 0;
341			if (mlen == -1) {
342				s_util.c[1] = *(char *)w;
343				sum += s_util.s;
344				mlen = 0;
345			} else
346				mlen = -1;
347		} else if (mlen == -1)
348			s_util.c[0] = *(char *)w;
349	}
350	if (len)
351		printf("inet6_cksum: out of data by %d\n", len);
352	if (mlen == -1) {
353		/* The last mbuf has odd # of bytes. Follow the
354		   standard (the odd byte may be shifted left by 8 bits
355		   or not as determined by endian-ness of the machine) */
356		s_util.c[1] = 0;
357		sum += s_util.s;
358	}
359	REDUCE;
360	return (~sum & 0xffff);
361}
362
363