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