Commit | Line | Data |
---|---|---|
f07f290a PR |
1 | /*- |
2 | * Copyright (c) 1990 The Regents of the University of California. | |
77389cf5 PR |
3 | * All rights reserved. |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
f07f290a PR |
32 | * |
33 | * from tahoe: in_cksum.c 1.2 86/01/05 | |
34 | * @(#)in_cksum.c 1.3 (Berkeley) 1/19/91 | |
35 | * | |
36 | * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE | |
37 | * -------------------- ----- ---------------------- | |
38 | * CURRENT PATCH LEVEL: 1 00104 | |
39 | * -------------------- ----- ---------------------- | |
40 | * | |
41 | * 24 Jul 92 Bakul Shah Optimized some more | |
42 | * | |
43 | * 920724 i386 changes by Bakul Shah <bvs@bitblocks.com> | |
77389cf5 PR |
44 | */ |
45 | ||
f07f290a PR |
46 | #include "param.h" |
47 | #include "sys/mbuf.h" | |
77389cf5 PR |
48 | |
49 | /* | |
50 | * Checksum routine for Internet Protocol family headers. | |
51 | * | |
52 | * This routine is very heavily used in the network | |
53 | * code and should be modified for each CPU to be as fast as possible. | |
54 | * | |
f07f290a | 55 | * This implementation is 386 version. |
77389cf5 PR |
56 | */ |
57 | ||
58 | #undef ADDCARRY | |
f07f290a PR |
59 | #define ADDCARRY(x) if ((x) > 0xffff) (x) -= 0xffff |
60 | #define REDUCE {sum = (sum & 0xffff) + (sum >> 16); ADDCARRY(sum);} | |
77389cf5 | 61 | |
f07f290a PR |
62 | /* |
63 | * Thanks to gcc we don't have to guess | |
64 | * which registers contain sum & w. | |
65 | */ | |
66 | #define CLC asm("clc") | |
67 | #define ADD(n) asm("adcl " #n "(%2), %0": "=r"(sum): "0"(sum), "r"(w)) | |
68 | #define MOP asm("adcl $0, %0": "=r"(sum): "0"(sum)) | |
69 | ||
70 | in_cksum(m, len) | |
71 | register struct mbuf *m; | |
77389cf5 PR |
72 | register int len; |
73 | { | |
f07f290a PR |
74 | register u_short *w; |
75 | register unsigned sum = 0; | |
76 | register int mlen = 0; | |
77 | int byte_swapped = 0; | |
78 | union { char c[2]; u_short s; } su; | |
79 | ||
80 | for (;m && len; m = m->m_next) { | |
81 | if (m->m_len == 0) | |
82 | continue; | |
83 | w = mtod(m, u_short *); | |
84 | if (mlen == -1) { | |
85 | /* | |
86 | * The first byte of this mbuf is the continuation | |
87 | * of a word spanning between this mbuf and the | |
88 | * last mbuf. | |
89 | */ | |
77389cf5 | 90 | |
f07f290a PR |
91 | /* su.c[0] is already saved when scanning previous |
92 | * mbuf. sum was REDUCEd when we found mlen == -1 | |
93 | */ | |
94 | su.c[1] = *(u_char *)w; | |
95 | sum += su.s; | |
96 | w = (u_short *)((char *)w + 1); | |
97 | mlen = m->m_len - 1; | |
98 | len--; | |
99 | } else | |
100 | mlen = m->m_len; | |
101 | if (len < mlen) | |
102 | mlen = len; | |
103 | len -= mlen; | |
77389cf5 | 104 | /* |
f07f290a PR |
105 | * Force to long boundary so we do longword aligned |
106 | * memory operations | |
77389cf5 | 107 | */ |
f07f290a PR |
108 | if (3 & (int) w) { |
109 | REDUCE; | |
110 | if ((1 & (int) w) && (mlen > 0)) { | |
111 | sum <<= 8; | |
112 | su.c[0] = *(char *)w; | |
113 | w = (u_short *)((char *)w + 1); | |
114 | mlen--; | |
115 | byte_swapped = 1; | |
116 | } | |
117 | if ((2 & (int) w) && (mlen >= 2)) { | |
118 | sum += *w++; | |
119 | mlen -= 2; | |
120 | } | |
121 | } | |
122 | /* | |
123 | * Do as much of the checksum as possible 32 bits at at time. | |
124 | * In fact, this loop is unrolled to make overhead from | |
125 | * branches &c small. | |
126 | */ | |
127 | while ((mlen -= 32) >= 0) { | |
128 | /* | |
129 | * Clear the carry flag, add with carry 16 words | |
130 | * and fold-in last carry by adding a 0 with carry. | |
131 | */ | |
132 | CLC; | |
133 | ADD(0); ADD(4); ADD(8); ADD(12); | |
134 | ADD(16); ADD(20); ADD(24); ADD(28); | |
135 | MOP; w += 16; | |
136 | } | |
137 | mlen += 32; | |
138 | while ((mlen -= 8) >= 0) { | |
139 | CLC; | |
140 | ADD(0); ADD(4); | |
141 | MOP; | |
142 | w += 4; | |
143 | } | |
144 | mlen += 8; | |
145 | if (mlen == 0 && byte_swapped == 0) | |
146 | continue; /* worth 1% maybe ?? */ | |
147 | REDUCE; | |
148 | while ((mlen -= 2) >= 0) { | |
149 | sum += *w++; | |
77389cf5 | 150 | } |
f07f290a PR |
151 | if (byte_swapped) { |
152 | sum <<= 8; | |
153 | byte_swapped = 0; | |
154 | if (mlen == -1) { | |
155 | su.c[1] = *(char *)w; | |
156 | sum += su.s; | |
157 | mlen = 0; | |
158 | } else | |
159 | mlen = -1; | |
160 | } else if (mlen == -1) | |
77389cf5 | 161 | /* |
f07f290a PR |
162 | * This mbuf has odd number of bytes. |
163 | * There could be a word split betwen | |
164 | * this mbuf and the next mbuf. | |
165 | * Save the last byte (to prepend to next mbuf). | |
77389cf5 | 166 | */ |
f07f290a | 167 | su.c[0] = *(char *)w; |
77389cf5 | 168 | } |
f07f290a PR |
169 | |
170 | if (len) | |
171 | printf("cksum: out of data\n"); | |
172 | if (mlen == -1) { | |
77389cf5 PR |
173 | /* The last mbuf has odd # of bytes. Follow the |
174 | standard (the odd byte is shifted left by 8 bits) */ | |
f07f290a PR |
175 | su.c[1] = 0; |
176 | sum += su.s; | |
77389cf5 | 177 | } |
f07f290a | 178 | REDUCE; |
77389cf5 PR |
179 | return (~sum & 0xffff); |
180 | } | |
f07f290a | 181 |