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