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