|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Copyright (c) 1988 Regents of the University of California.
27: * All rights reserved.
28: *
29: * Redistribution and use in source and binary forms are permitted
30: * provided that this notice is preserved and that due credit is given
31: * to the University of California at Berkeley. The name of the University
32: * may not be used to endorse or promote products derived from this
33: * software without specific prior written permission. This software
34: * is provided ``as is'' without express or implied warranty.
35: *
36: * @(#)in_cksum.c 7.1 (Berkeley) 3/29/88
37: */
38:
39: /* HISTORY
40: * 26-May-94 Curtis Galloway at NeXT
41: * Grabbed the m68k code and added a Pentium-optimized checksummer.
42: * (See RFC 1107 for the checksum algorithm.)
43: *
44: * 06-Dec-92 Mac Gillon (mgillon) at NeXT
45: * Lifted the '020 code from 4.4. The compiler generates crummy
46: * code for the portable version.
47: */
48:
49: #include <sys/param.h>
50: #include <sys/mbuf.h>
51: #include <netinet/in.h>
52: #include <netinet/in_systm.h>
53:
54: #if defined(NX_CURRENT_COMPILER_RELEASE) && (NX_CURRENT_COMPILER_RELEASE < 320)
55: #define SIREG "e"
56: #else
57: #define SIREG "S"
58: #endif
59:
60:
61: #if DEBUG_OC
62:
63: static inline int
64: oc_cksum(
65: unsigned char *buf,
66: int len,
67: unsigned long oldsum
68: )
69: {
70: unsigned short *p = (unsigned short *)buf;
71:
72: for (; len>1; len -=2)
73: oldsum += *p++;
74: #if __BIG_ENDIAN__
75: if (len > 0)
76: oldsum += (*(unsigned char *)p) << 8;
77: #else
78: if (len > 0)
79: oldsum += *(unsigned char *)p;
80: #endif
81: oldsum = (oldsum >> 16) + (oldsum & 0xffff);
82: oldsum = (oldsum >> 16) + (oldsum & 0xffff);
83: return oldsum;
84: }
85:
86: #else DEBUG_OC
87:
88: static inline int
89: oc_cksum(
90: unsigned char *buf,
91: int len,
92: unsigned long oldsum
93: )
94: {
95: unsigned short sum;
96:
97: asm("
98: testb $1, %%ecx
99: jne 5f // one or three extra bytes
100: testb $2, %%ecx
101: jne 7f // two extra bytes
102: 0:
103: adc $0,%%eax //add carry if extra bytes
104: shr $3,%%ecx //we'll do two dwords per loop
105: jnc 1f //is there an odd dword in buffer?
106: add (%%esi),%%eax //checksum the odd dword
107: adc $0,%%eax //add carry if needed
108: add $4,%%esi //point to the next dword
109: 1:
110: test %%ecx, %%ecx
111: jz 4f
112: mov (%%esi),%%edx //preload the first dword
113: mov 4(%%esi),%%ebx //preload the second dword
114: dec %%ecx //we'll do 1 checksum outside the loop
115: jz 3f //only 1 checksum to do
116: add $8, %%esi //point to the next dword
117:
118: 2:
119: add %%edx,%%eax //cycle 1 U-pipe
120: mov (%%esi),%%edx //cycle 1 V-pipe
121: adc %%ebx,%%eax //cycle 2 U-pipe
122: mov 4(%%esi),%%ebx //cycle 2 V-pipe
123: adc $0,%%eax //cycle 3 U-pipe
124: add $8,%%esi //cycle 3 V-pipe
125: dec %%ecx //cycle 4 U-pipe
126: jnz 2b //cycle 4 V-pipe
127:
128: 3:
129: add %%edx,%%eax //checksum the last two dwords
130: adc %%ebx,%%eax
131: adc $0,%%eax
132: 4:
133: mov %%eax,%%edx //compress the 32-bit checksum
134: shr $16,%%edx //into a 16-bit checksum
135: add %%dx,%%ax
136: adc $0,%%eax
137: jmp 8f
138:
139: 5:
140: testb $2, %%ecx
141: je 6f // do one byte
142:
143: movzwl -3(%%esi,%%ecx),%%ebx
144: add %%ebx,%%eax // pick up two bytes and fall through
145:
146: 6:
147: movzbl -1(%%esi,%%ecx),%%ebx
148: adc %%ebx,%%eax
149: jmp 0b
150:
151: 7:
152: movzwl -2(%%esi,%%ecx),%%ebx
153: add %%ebx, %%eax
154: jmp 0b
155:
156: 8:
157: " : "=a" (sum) : "c" (len), SIREG (buf), "a" (oldsum) :
158: "eax", "ebx", "ecx", "edx", "esi");
159:
160: return sum;
161: }
162:
163: #endif DEBUG_OC
164:
165:
166:
167: /*
168: * Checksum routine for the Internet Protocol family.
169: *
170: * This isn't as bad as it looks. For ip headers the "while" isn't
171: * executed and we just drop through to the return statement at the
172: * end. For the usual tcp or udp packet (a single header mbuf
173: * chained onto a cluster of data, we make exactly one trip through
174: * the while (for the header mbuf) and never do the hairy code
175: * inside the "if". If fact, if m_copydata & sb_compact are doing
176: * their job, we should never do the hairy code inside the "if".
177: */
178: in_cksum(m, len)
179: register struct mbuf *m;
180: register int len;
181: {
182: register int sum = 0;
183: register int i;
184:
185: while (len > m->m_len) {
186: sum = oc_cksum(mtod(m, u_char *), i = m->m_len, sum);
187: m = m->m_next;
188: len -= i;
189: if (i & 1) {
190: /*
191: * ouch - we ended on an odd byte with more
192: * to do. This xfer is obviously not interested
193: * in performance so finish things slowly.
194: */
195: register u_char *cp;
196:
197: while (len > m->m_len) {
198: cp = mtod(m, u_char *);
199: if (i & 1) {
200: i = m->m_len - 1;
201: --len;
202: #if __BIG_ENDIAN__
203: sum += *cp++;
204: #else
205: sum += (*cp++) << 8;
206: #endif
207: } else
208: i = m->m_len;
209:
210: sum = oc_cksum(cp, i, sum);
211: m = m->m_next;
212: len -= i;
213: }
214: if (i & 1) {
215: cp = mtod(m, u_char *);
216: #if __BIG_ENDIAN__
217: sum += *cp++;
218: #else
219: sum += (*cp++) << 8;
220: #endif
221: return (0xffff & ~oc_cksum(cp, len - 1, sum));
222: }
223: }
224: }
225: return (0xffff & ~oc_cksum(mtod(m, u_char *), len, sum));
226: }
227:
228:
229: /*
230: * Checksum routine for Internet Protocol family headers (Portable Version).
231: *
232: * This routine is very heavily used in the network
233: * code and should be modified for each CPU to be as fast as possible.
234: */
235:
236: #ifdef notdef
237:
238: #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
239: #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
240:
241: in_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:
250: union {
251: char c[2];
252: u_short s;
253: } s_util;
254: union {
255: u_short s[2];
256: long l;
257: } l_util;
258:
259: for (;m && len; m = m->m_next) {
260: if (m->m_len == 0)
261: continue;
262: w = mtod(m, u_short *);
263: if (mlen == -1) {
264: /*
265: * The first byte of this mbuf is the continuation
266: * of a word spanning between this mbuf and the
267: * last mbuf.
268: *
269: * s_util.c[0] is already saved when scanning previous
270: * mbuf.
271: */
272: s_util.c[1] = *(char *)w;
273: sum += s_util.s;
274: w = (u_short *)((char *)w + 1);
275: mlen = m->m_len - 1;
276: len--;
277: } else
278: mlen = m->m_len;
279: if (len < mlen)
280: mlen = len;
281: len -= mlen;
282: /*
283: * Force to even boundary.
284: */
285: if ((1 & (int) w) && (mlen > 0)) {
286: REDUCE;
287: sum <<= 8;
288: s_util.c[0] = *(u_char *)w;
289: w = (u_short *)((char *)w + 1);
290: mlen--;
291: byte_swapped = 1;
292: }
293: /*
294: * Unroll the loop to make overhead from
295: * branches &c small.
296: */
297: while ((mlen -= 32) >= 0) {
298: sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
299: sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
300: sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
301: sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
302: w += 16;
303: }
304: mlen += 32;
305: while ((mlen -= 8) >= 0) {
306: sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
307: w += 4;
308: }
309: mlen += 8;
310: if (mlen == 0 && byte_swapped == 0)
311: continue;
312: REDUCE;
313: while ((mlen -= 2) >= 0) {
314: sum += *w++;
315: }
316: if (byte_swapped) {
317: REDUCE;
318: sum <<= 8;
319: byte_swapped = 0;
320: if (mlen == -1) {
321: s_util.c[1] = *(char *)w;
322: sum += s_util.s;
323: mlen = 0;
324: } else
325: mlen = -1;
326: } else if (mlen == -1)
327: s_util.c[0] = *(char *)w;
328: }
329: if (len)
330: printf("cksum: out of data\n");
331: if (mlen == -1) {
332: /* The last mbuf has odd # of bytes. Follow the
333: standard (the odd byte may be shifted left by 8 bits
334: or not as determined by endian-ness of the machine) */
335: s_util.c[1] = 0;
336: sum += s_util.s;
337: }
338: REDUCE;
339: return (~sum & 0xffff);
340: }
341: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.