]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/in_cksum.c
ac8b2648c8cdc751495bd8cabe8b7c4fea115a32
[apple/xnu.git] / bsd / netinet / in_cksum.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * Copyright (c) 1988, 1992, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 *
55 * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93
56 */
57
58 #include <sys/param.h>
59 #include <sys/mbuf.h>
60 #include <sys/kdebug.h>
61
62 #define DBG_FNC_IN_CKSUM NETDBG_CODE(DBG_NETIP, (3 << 8))
63
64 /*
65 * Checksum routine for Internet Protocol family headers (Portable Version).
66 *
67 * This routine is very heavily used in the network
68 * code and should be modified for each CPU to be as fast as possible.
69 */
70
71 union s_util {
72 char c[2];
73 u_short s;
74 };
75
76 union l_util {
77 u_int16_t s[2];
78 u_int32_t l;
79 };
80
81 union q_util {
82 u_int16_t s[4];
83 u_int32_t l[2];
84 u_int64_t q;
85 };
86
87 #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
88
89 #define REDUCE32 \
90 { \
91 q_util.q = sum; \
92 sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
93 }
94 #define REDUCE16 \
95 { \
96 q_util.q = sum; \
97 l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
98 sum = l_util.s[0] + l_util.s[1]; \
99 ADDCARRY(sum); \
100 }
101
102 #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
103
104
105 #if defined(ppc)
106
107 __inline unsigned short
108 in_addword(u_short a, u_short b)
109 {
110 union l_util l_util;
111 u_int32_t sum = a + b;
112 REDUCE;
113 return (sum);
114 }
115
116 __inline unsigned short
117 in_pseudo(u_int a, u_int b, u_int c)
118 {
119 u_int64_t sum;
120 union q_util q_util;
121 union l_util l_util;
122
123 sum = (u_int64_t) a + b + c;
124 REDUCE16;
125 return (sum);
126
127 }
128
129 int
130 in_cksum(m, len)
131 register struct mbuf *m;
132 register int len;
133 {
134 register u_short *w;
135 register int sum = 0;
136 register int mlen = 0;
137 int starting_on_odd = 0;
138
139
140 KERNEL_DEBUG(DBG_FNC_IN_CKSUM | DBG_FUNC_START, len,0,0,0,0);
141
142 for (;m && len; m = m->m_next) {
143 if (m->m_len == 0)
144 continue;
145 mlen = m->m_len;
146 w = mtod(m, u_short *);
147
148 if (len < mlen)
149 mlen = len;
150
151 sum = xsum_assym(w, mlen, sum, starting_on_odd);
152 len -= mlen;
153 if (mlen & 0x1)
154 {
155 if (starting_on_odd)
156 starting_on_odd = 0;
157 else
158 starting_on_odd = 1;
159 }
160 }
161
162 KERNEL_DEBUG(DBG_FNC_IN_CKSUM | DBG_FUNC_END, 0,0,0,0,0);
163 return (~sum & 0xffff);
164 }
165
166 u_short
167 in_cksum_skip(m, len, skip)
168 register struct mbuf *m;
169 register int len;
170 register int skip;
171 {
172 register u_short *w;
173 register int sum = 0;
174 register int mlen = 0;
175 int starting_on_odd = 0;
176
177 len -= skip;
178 for (; skip && m; m = m->m_next) {
179 if (m->m_len > skip) {
180 mlen = m->m_len - skip;
181 w = (u_short *)(m->m_data+skip);
182 goto skip_start;
183 } else {
184 skip -= m->m_len;
185 }
186 }
187 for (;m && len; m = m->m_next) {
188 if (m->m_len == 0)
189 continue;
190 mlen = m->m_len;
191 w = mtod(m, u_short *);
192
193 skip_start:
194 if (len < mlen)
195 mlen = len;
196 sum = xsum_assym(w, mlen, sum, starting_on_odd);
197 len -= mlen;
198 if (mlen & 0x1)
199 {
200 if (starting_on_odd)
201 starting_on_odd = 0;
202 else
203 starting_on_odd = 1;
204 }
205 }
206
207 return (~sum & 0xffff);
208 }
209 #else
210
211 u_short
212 in_addword(u_short a, u_short b)
213 {
214 union l_util l_util;
215 u_int32_t sum = a + b;
216 REDUCE(sum);
217 return (sum);
218 }
219
220 u_short
221 in_pseudo(u_int a, u_int b, u_int c)
222 {
223 u_int64_t sum;
224 union q_util q_util;
225 union l_util l_util;
226
227 sum = (u_int64_t) a + b + c;
228 REDUCE16;
229 return (sum);
230 }
231
232
233 int
234 in_cksum(m, len)
235 register struct mbuf *m;
236 register int len;
237 {
238 register u_short *w;
239 register int sum = 0;
240 register int mlen = 0;
241 int byte_swapped = 0;
242 union s_util s_util;
243 union l_util l_util;
244
245 KERNEL_DEBUG(DBG_FNC_IN_CKSUM | DBG_FUNC_START, len,0,0,0,0);
246
247 for (;m && len; m = m->m_next) {
248 if (m->m_len == 0)
249 continue;
250 w = mtod(m, u_short *);
251 if (mlen == -1) {
252 /*
253 * The first byte of this mbuf is the continuation
254 * of a word spanning between this mbuf and the
255 * last mbuf.
256 *
257 * s_util.c[0] is already saved when scanning previous
258 * mbuf.
259 */
260 s_util.c[1] = *(char *)w;
261 sum += s_util.s;
262 w = (u_short *)((char *)w + 1);
263 mlen = m->m_len - 1;
264 len--;
265 } else
266 mlen = m->m_len;
267 if (len < mlen)
268 mlen = len;
269 len -= mlen;
270 /*
271 * Force to even boundary.
272 */
273 if ((1 & (int) w) && (mlen > 0)) {
274 REDUCE;
275 sum <<= 8;
276 s_util.c[0] = *(u_char *)w;
277 w = (u_short *)((char *)w + 1);
278 mlen--;
279 byte_swapped = 1;
280 }
281 /*
282 * Unroll the loop to make overhead from
283 * branches &c small.
284 */
285 while ((mlen -= 32) >= 0) {
286 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
287 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
288 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
289 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
290 w += 16;
291 }
292 mlen += 32;
293 while ((mlen -= 8) >= 0) {
294 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
295 w += 4;
296 }
297 mlen += 8;
298 if (mlen == 0 && byte_swapped == 0)
299 continue;
300 REDUCE;
301 while ((mlen -= 2) >= 0) {
302 sum += *w++;
303 }
304 if (byte_swapped) {
305 REDUCE;
306 sum <<= 8;
307 byte_swapped = 0;
308 if (mlen == -1) {
309 s_util.c[1] = *(char *)w;
310 sum += s_util.s;
311 mlen = 0;
312 } else
313 mlen = -1;
314 } else if (mlen == -1)
315 s_util.c[0] = *(char *)w;
316 }
317 if (len)
318 printf("cksum: out of data\n");
319 if (mlen == -1) {
320 /* The last mbuf has odd # of bytes. Follow the
321 standard (the odd byte may be shifted left by 8 bits
322 or not as determined by endian-ness of the machine) */
323 s_util.c[1] = 0;
324 sum += s_util.s;
325 }
326 REDUCE;
327 KERNEL_DEBUG(DBG_FNC_IN_CKSUM | DBG_FUNC_END, 0,0,0,0,0);
328 return (~sum & 0xffff);
329 }
330
331 int
332 in_cksum_skip(m, len, skip)
333 register struct mbuf *m;
334 register u_short len;
335 register u_short skip;
336 {
337 register u_short *w;
338 register int sum = 0;
339 register int mlen = 0;
340 int byte_swapped = 0;
341 union s_util s_util;
342 union l_util l_util;
343
344 KERNEL_DEBUG(DBG_FNC_IN_CKSUM | DBG_FUNC_START, len,0,0,0,0);
345
346 len -= skip;
347 for (; skip && m; m = m->m_next) {
348 if (m->m_len > skip) {
349 mlen = m->m_len - skip;
350 w = (u_short *)(m->m_data+skip);
351 goto skip_start;
352 } else {
353 skip -= m->m_len;
354 }
355 }
356 for (;m && len; m = m->m_next) {
357 if (m->m_len == 0)
358 continue;
359 w = mtod(m, u_short *);
360
361 if (mlen == -1) {
362 /*
363 * The first byte of this mbuf is the continuation
364 * of a word spanning between this mbuf and the
365 * last mbuf.
366 *
367 * s_util.c[0] is already saved when scanning previous
368 * mbuf.
369 */
370 s_util.c[1] = *(char *)w;
371 sum += s_util.s;
372 w = (u_short *)((char *)w + 1);
373 mlen = m->m_len - 1;
374 len--;
375 } else {
376 mlen = m->m_len;
377 }
378 skip_start:
379 if (len < mlen)
380 mlen = len;
381
382 len -= mlen;
383 /*
384 * Force to even boundary.
385 */
386 if ((1 & (int) w) && (mlen > 0)) {
387 REDUCE;
388 sum <<= 8;
389 s_util.c[0] = *(u_char *)w;
390 w = (u_short *)((char *)w + 1);
391 mlen--;
392 byte_swapped = 1;
393 }
394 /*
395 * Unroll the loop to make overhead from
396 * branches &c small.
397 */
398 while ((mlen -= 32) >= 0) {
399 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
400 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
401 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
402 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
403 w += 16;
404 }
405 mlen += 32;
406 while ((mlen -= 8) >= 0) {
407 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
408 w += 4;
409 }
410 mlen += 8;
411 if (mlen == 0 && byte_swapped == 0)
412 continue;
413 REDUCE;
414 while ((mlen -= 2) >= 0) {
415 sum += *w++;
416 }
417 if (byte_swapped) {
418 REDUCE;
419 sum <<= 8;
420 byte_swapped = 0;
421 if (mlen == -1) {
422 s_util.c[1] = *(char *)w;
423 sum += s_util.s;
424 mlen = 0;
425 } else
426 mlen = -1;
427 } else if (mlen == -1)
428 s_util.c[0] = *(char *)w;
429 }
430 if (len)
431 printf("cksum: out of data\n");
432 if (mlen == -1) {
433 /* The last mbuf has odd # of bytes. Follow the
434 standard (the odd byte may be shifted left by 8 bits
435 or not as determined by endian-ness of the machine) */
436 s_util.c[1] = 0;
437 sum += s_util.s;
438 }
439 REDUCE;
440 KERNEL_DEBUG(DBG_FNC_IN_CKSUM | DBG_FUNC_END, 0,0,0,0,0);
441 return (~sum & 0xffff);
442 }
443
444 #endif