1 /*-
2 * Copyright (c) 1990 The Regents of the University of California.
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.
32 *
33 * from tahoe: in_cksum.c 1.2 86/01/05
34 * from: @(#)in_cksum.c 1.3 (Berkeley) 1/19/91
35 */
36
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD: releng/5.2/sys/i386/i386/in_cksum.c 115683 2003-06-02 06:43:15Z obrien $");
39
40 /*
41 * MPsafe: alfred
42 */
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/mbuf.h>
46
47 #include <netinet/in.h>
48 #include <netinet/in_systm.h>
49 #include <netinet/ip.h>
50
51 #include <machine/in_cksum.h>
52
53 /*
54 * Checksum routine for Internet Protocol family headers.
55 *
56 * This routine is very heavily used in the network
57 * code and should be modified for each CPU to be as fast as possible.
58 *
59 * This implementation is 386 version.
60 */
61
62 #undef ADDCARRY
63 #define ADDCARRY(x) if ((x) > 0xffff) (x) -= 0xffff
64 #define REDUCE {sum = (sum & 0xffff) + (sum >> 16); ADDCARRY(sum);}
65
66 /*
67 * These asm statements require __volatile because they pass information
68 * via the condition codes. GCC does not currently provide a way to specify
69 * the condition codes as an input or output operand.
70 *
71 * The LOAD macro below is effectively a prefetch into cache. GCC will
72 * load the value into a register but will not use it. Since modern CPUs
73 * reorder operations, this will generally take place in parallel with
74 * other calculations.
75 */
76 #define ADD(n) __asm __volatile \
77 ("addl %1, %0" : "+r" (sum) : \
78 "g" (((const u_int32_t *)w)[n / 4]))
79 #define ADDC(n) __asm __volatile \
80 ("adcl %1, %0" : "+r" (sum) : \
81 "g" (((const u_int32_t *)w)[n / 4]))
82 #define LOAD(n) __asm __volatile \
83 ("" : : "r" (((const u_int32_t *)w)[n / 4]))
84 #define MOP __asm __volatile \
85 ("adcl $0, %0" : "+r" (sum))
86
87 u_short
88 in_cksum_skip(m, len, skip)
89 struct mbuf *m;
90 int len;
91 int skip;
92 {
93 register u_short *w;
94 register unsigned sum = 0;
95 register int mlen = 0;
96 int byte_swapped = 0;
97 union { char c[2]; u_short s; } su;
98
99 len -= skip;
100 for (; skip && m; m = m->m_next) {
101 if (m->m_len > skip) {
102 mlen = m->m_len - skip;
103 w = (u_short *)(mtod(m, u_char *) + skip);
104 goto skip_start;
105 } else {
106 skip -= m->m_len;
107 }
108 }
109
110 for (;m && len; m = m->m_next) {
111 if (m->m_len == 0)
112 continue;
113 w = mtod(m, u_short *);
114 if (mlen == -1) {
115 /*
116 * The first byte of this mbuf is the continuation
117 * of a word spanning between this mbuf and the
118 * last mbuf.
119 */
120
121 /* su.c[0] is already saved when scanning previous
122 * mbuf. sum was REDUCEd when we found mlen == -1
123 */
124 su.c[1] = *(u_char *)w;
125 sum += su.s;
126 w = (u_short *)((char *)w + 1);
127 mlen = m->m_len - 1;
128 len--;
129 } else
130 mlen = m->m_len;
131 skip_start:
132 if (len < mlen)
133 mlen = len;
134 len -= mlen;
135 /*
136 * Force to long boundary so we do longword aligned
137 * memory operations
138 */
139 if (3 & (int) w) {
140 REDUCE;
141 if ((1 & (int) w) && (mlen > 0)) {
142 sum <<= 8;
143 su.c[0] = *(char *)w;
144 w = (u_short *)((char *)w + 1);
145 mlen--;
146 byte_swapped = 1;
147 }
148 if ((2 & (int) w) && (mlen >= 2)) {
149 sum += *w++;
150 mlen -= 2;
151 }
152 }
153 /*
154 * Advance to a 486 cache line boundary.
155 */
156 if (4 & (int) w && mlen >= 4) {
157 ADD(0);
158 MOP;
159 w += 2;
160 mlen -= 4;
161 }
162 if (8 & (int) w && mlen >= 8) {
163 ADD(0);
164 ADDC(4);
165 MOP;
166 w += 4;
167 mlen -= 8;
168 }
169 /*
170 * Do as much of the checksum as possible 32 bits at at time.
171 * In fact, this loop is unrolled to make overhead from
172 * branches &c small.
173 */
174 mlen -= 1;
175 while ((mlen -= 32) >= 0) {
176 /*
177 * Add with carry 16 words and fold in the last
178 * carry by adding a 0 with carry.
179 *
180 * The early ADD(16) and the LOAD(32) are to load
181 * the next 2 cache lines in advance on 486's. The
182 * 486 has a penalty of 2 clock cycles for loading
183 * a cache line, plus whatever time the external
184 * memory takes to load the first word(s) addressed.
185 * These penalties are unavoidable. Subsequent
186 * accesses to a cache line being loaded (and to
187 * other external memory?) are delayed until the
188 * whole load finishes. These penalties are mostly
189 * avoided by not accessing external memory for
190 * 8 cycles after the ADD(16) and 12 cycles after
191 * the LOAD(32). The loop terminates when mlen
192 * is initially 33 (not 32) to guaranteed that
193 * the LOAD(32) is within bounds.
194 */
195 ADD(16);
196 ADDC(0);
197 ADDC(4);
198 ADDC(8);
199 ADDC(12);
200 LOAD(32);
201 ADDC(20);
202 ADDC(24);
203 ADDC(28);
204 MOP;
205 w += 16;
206 }
207 mlen += 32 + 1;
208 if (mlen >= 32) {
209 ADD(16);
210 ADDC(0);
211 ADDC(4);
212 ADDC(8);
213 ADDC(12);
214 ADDC(20);
215 ADDC(24);
216 ADDC(28);
217 MOP;
218 w += 16;
219 mlen -= 32;
220 }
221 if (mlen >= 16) {
222 ADD(0);
223 ADDC(4);
224 ADDC(8);
225 ADDC(12);
226 MOP;
227 w += 8;
228 mlen -= 16;
229 }
230 if (mlen >= 8) {
231 ADD(0);
232 ADDC(4);
233 MOP;
234 w += 4;
235 mlen -= 8;
236 }
237 if (mlen == 0 && byte_swapped == 0)
238 continue; /* worth 1% maybe ?? */
239 REDUCE;
240 while ((mlen -= 2) >= 0) {
241 sum += *w++;
242 }
243 if (byte_swapped) {
244 sum <<= 8;
245 byte_swapped = 0;
246 if (mlen == -1) {
247 su.c[1] = *(char *)w;
248 sum += su.s;
249 mlen = 0;
250 } else
251 mlen = -1;
252 } else if (mlen == -1)
253 /*
254 * This mbuf has odd number of bytes.
255 * There could be a word split betwen
256 * this mbuf and the next mbuf.
257 * Save the last byte (to prepend to next mbuf).
258 */
259 su.c[0] = *(char *)w;
260 }
261
262 if (len)
263 printf("%s: out of data by %d\n", __func__, len);
264 if (mlen == -1) {
265 /* The last mbuf has odd # of bytes. Follow the
266 standard (the odd byte is shifted left by 8 bits) */
267 su.c[1] = 0;
268 sum += su.s;
269 }
270 REDUCE;
271 return (~sum & 0xffff);
272 }
Cache object: d26b039fccaac7f4321bba0fbc0decac
|