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