in6_cksum.c revision 235921
1/*-
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *	$KAME: in6_cksum.c,v 1.10 2000/12/03 00:53:59 itojun Exp $
30 */
31
32/*-
33 * Copyright (c) 1988, 1992, 1993
34 *	The Regents of the University of California.  All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 *    notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 *    notice, this list of conditions and the following disclaimer in the
43 *    documentation and/or other materials provided with the distribution.
44 * 4. Neither the name of the University nor the names of its contributors
45 *    may be used to endorse or promote products derived from this software
46 *    without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 *	@(#)in_cksum.c	8.1 (Berkeley) 6/10/93
61 */
62
63#include <sys/cdefs.h>
64__FBSDID("$FreeBSD: head/sys/netinet6/in6_cksum.c 235921 2012-05-24 18:05:10Z bz $");
65
66#include <sys/param.h>
67#include <sys/mbuf.h>
68#include <sys/systm.h>
69#include <netinet/in.h>
70#include <netinet/ip6.h>
71#include <netinet6/scope6_var.h>
72
73/*
74 * Checksum routine for Internet Protocol family headers (Portable Version).
75 *
76 * This routine is very heavily used in the network
77 * code and should be modified for each CPU to be as fast as possible.
78 */
79
80#define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
81#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; (void)ADDCARRY(sum);}
82
83/*
84 * m MUST contain a contiguous IP6 header.
85 * off is an offset where TCP/UDP/ICMP6 header starts.
86 * len is a total length of a transport segment.
87 * (e.g. TCP header + TCP payload)
88 */
89int
90in6_cksum(struct mbuf *m, u_int8_t nxt, u_int32_t off, u_int32_t len)
91{
92	struct ip6_hdr *ip6;
93	u_int16_t *w, scope;
94	int byte_swapped, mlen;
95	int sum;
96	union {
97		u_int16_t phs[4];
98		struct {
99			u_int32_t	ph_len;
100			u_int8_t	ph_zero[3];
101			u_int8_t	ph_nxt;
102		} __packed ph;
103	} uph;
104	union {
105		u_int8_t	c[2];
106		u_int16_t	s;
107	} s_util;
108	union {
109		u_int16_t s[2];
110		u_int32_t l;
111	} l_util;
112
113	/* Sanity check. */
114	KASSERT(m->m_pkthdr.len >= off + len, ("%s: mbuf len (%d) < off(%d)+"
115	    "len(%d)", __func__, m->m_pkthdr.len, off, len));
116
117	/*
118	 * First create IP6 pseudo header and calculate a summary.
119	 */
120	uph.ph.ph_len = htonl(len);
121	uph.ph.ph_zero[0] = uph.ph.ph_zero[1] = uph.ph.ph_zero[2] = 0;
122	uph.ph.ph_nxt = nxt;
123
124	/* Payload length and upper layer identifier. */
125	sum = uph.phs[0];  sum += uph.phs[1];
126	sum += uph.phs[2];  sum += uph.phs[3];
127
128	ip6 = mtod(m, struct ip6_hdr *);
129
130	/* IPv6 source address. */
131	scope = in6_getscope(&ip6->ip6_src);
132	w = (u_int16_t *)&ip6->ip6_src;
133	sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
134	sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
135	if (scope != 0)
136		sum -= scope;
137
138	/* IPv6 destination address. */
139	scope = in6_getscope(&ip6->ip6_dst);
140	w = (u_int16_t *)&ip6->ip6_dst;
141	sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
142	sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
143	if (scope != 0)
144		sum -= scope;
145
146	/*
147	 * Secondly calculate a summary of the first mbuf excluding offset.
148	 */
149	while (off > 0) {
150		if (m->m_len <= off)
151			off -= m->m_len;
152		else
153			break;
154		m = m->m_next;
155	}
156	w = (u_int16_t *)(mtod(m, u_char *) + off);
157	mlen = m->m_len - off;
158	if (len < mlen)
159		mlen = len;
160	len -= mlen;
161	/*
162	 * Force to even boundary.
163	 */
164	if ((1 & (long)w) && (mlen > 0)) {
165		REDUCE;
166		sum <<= 8;
167		s_util.c[0] = *(u_char *)w;
168		w = (u_int16_t *)((char *)w + 1);
169		mlen--;
170		byte_swapped = 1;
171	} else
172		byte_swapped = 0;
173
174	/*
175	 * Unroll the loop to make overhead from
176	 * branches &c small.
177	 */
178	while ((mlen -= 32) >= 0) {
179		sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
180		sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
181		sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
182		sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
183		w += 16;
184	}
185	mlen += 32;
186	while ((mlen -= 8) >= 0) {
187		sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
188		w += 4;
189	}
190	mlen += 8;
191	if (mlen == 0 && byte_swapped == 0)
192		goto next;
193	REDUCE;
194	while ((mlen -= 2) >= 0) {
195		sum += *w++;
196	}
197	if (byte_swapped) {
198		REDUCE;
199		sum <<= 8;
200		byte_swapped = 0;
201		if (mlen == -1) {
202			s_util.c[1] = *(char *)w;
203			sum += s_util.s;
204			mlen = 0;
205		} else
206			mlen = -1;
207	} else if (mlen == -1)
208		s_util.c[0] = *(char *)w;
209 next:
210	m = m->m_next;
211
212	/*
213	 * Lastly calculate a summary of the rest of mbufs.
214	 */
215
216	for (;m && len; m = m->m_next) {
217		if (m->m_len == 0)
218			continue;
219		w = mtod(m, u_int16_t *);
220		if (mlen == -1) {
221			/*
222			 * The first byte of this mbuf is the continuation
223			 * of a word spanning between this mbuf and the
224			 * last mbuf.
225			 *
226			 * s_util.c[0] is already saved when scanning previous
227			 * mbuf.
228			 */
229			s_util.c[1] = *(char *)w;
230			sum += s_util.s;
231			w = (u_int16_t *)((char *)w + 1);
232			mlen = m->m_len - 1;
233			len--;
234		} else
235			mlen = m->m_len;
236		if (len < mlen)
237			mlen = len;
238		len -= mlen;
239		/*
240		 * Force to even boundary.
241		 */
242		if ((1 & (long) w) && (mlen > 0)) {
243			REDUCE;
244			sum <<= 8;
245			s_util.c[0] = *(u_char *)w;
246			w = (u_int16_t *)((char *)w + 1);
247			mlen--;
248			byte_swapped = 1;
249		}
250		/*
251		 * Unroll the loop to make overhead from
252		 * branches &c small.
253		 */
254		while ((mlen -= 32) >= 0) {
255			sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
256			sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
257			sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
258			sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
259			w += 16;
260		}
261		mlen += 32;
262		while ((mlen -= 8) >= 0) {
263			sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
264			w += 4;
265		}
266		mlen += 8;
267		if (mlen == 0 && byte_swapped == 0)
268			continue;
269		REDUCE;
270		while ((mlen -= 2) >= 0) {
271			sum += *w++;
272		}
273		if (byte_swapped) {
274			REDUCE;
275			sum <<= 8;
276			byte_swapped = 0;
277			if (mlen == -1) {
278				s_util.c[1] = *(char *)w;
279				sum += s_util.s;
280				mlen = 0;
281			} else
282				mlen = -1;
283		} else if (mlen == -1)
284			s_util.c[0] = *(char *)w;
285	}
286	if (len)
287		panic("in6_cksum: out of data");
288	if (mlen == -1) {
289		/* The last mbuf has odd # of bytes. Follow the
290		   standard (the odd byte may be shifted left by 8 bits
291		   or not as determined by endian-ness of the machine) */
292		s_util.c[1] = 0;
293		sum += s_util.s;
294	}
295	REDUCE;
296	return (~sum & 0xffff);
297}
298