]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/net/bsd_tcpip/v2_0/src/sys/netinet/in_cksum.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / net / bsd_tcpip / v2_0 / src / sys / netinet / in_cksum.c
1 //==========================================================================
2 //
3 //      src/sys/netinet/in_cksum.c
4 //
5 //==========================================================================
6 //####BSDCOPYRIGHTBEGIN####
7 //
8 // -------------------------------------------
9 //
10 // Portions of this software may have been derived from OpenBSD, 
11 // FreeBSD or other sources, and are covered by the appropriate
12 // copyright disclaimers included herein.
13 //
14 // Portions created by Red Hat are
15 // Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
16 //
17 // -------------------------------------------
18 //
19 //####BSDCOPYRIGHTEND####
20 //==========================================================================
21
22 /* $FreeBSD: src/sys/alpha/alpha/in_cksum.c,v 1.2.2.2 2001/05/04 15:36:43 ru Exp $ */
23 /* $NetBSD: in_cksum.c,v 1.7 1997/09/02 13:18:15 thorpej Exp $ */
24
25 /*
26  * Copyright (c) 1988, 1992, 1993
27  *      The Regents of the University of California.  All rights reserved.
28  * Copyright (c) 1996
29  *      Matt Thomas <matt@3am-software.com>
30  *
31  * Redistribution and use in source and binary forms, with or without
32  * modification, are permitted provided that the following conditions
33  * are met:
34  * 1. Redistributions of source code must retain the above copyright
35  *    notice, this list of conditions and the following disclaimer.
36  * 2. Redistributions in binary form must reproduce the above copyright
37  *    notice, this list of conditions and the following disclaimer in the
38  *    documentation and/or other materials provided with the distribution.
39  * 3. All advertising materials mentioning features or use of this software
40  *    must display the following acknowledgement:
41  *      This product includes software developed by the University of
42  *      California, Berkeley and its contributors.
43  * 4. Neither the name of the University nor the names of its contributors
44  *    may be used to endorse or promote products derived from this software
45  *    without specific prior written permission.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57  * SUCH DAMAGE.
58  *
59  *      @(#)in_cksum.c  8.1 (Berkeley) 6/10/93
60  */
61
62 #include <sys/param.h>
63 #include <sys/mbuf.h>
64 #include <netinet/in_systm.h>
65 #include <netinet/in.h>
66 #include <netinet/ip.h>
67
68 /*
69  * Checksum routine for Internet Protocol family headers
70  *    (Portable Alpha 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 #define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
77 #define REDUCE32                                                          \
78     {                                                                     \
79         q_util.q = sum;                                                   \
80         sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3];      \
81     }
82 #define REDUCE16                                                          \
83     {                                                                     \
84         q_util.q = sum;                                                   \
85         l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
86         sum = l_util.s[0] + l_util.s[1];                                  \
87         ADDCARRY(sum);                                                    \
88     }
89
90 static const u_int32_t in_masks[] = {
91 #if BYTE_ORDER == BIG_ENDIAN
92         /*0 bytes*/ /*1 byte*/  /*2 bytes*/ /*3 bytes*/
93         0x00000000, 0xFF000000, 0xFFFF0000, 0xFFFFFF00, /* offset 0 */
94         0x00000000, 0x00FF0000, 0x00FFFF00, 0x00FFFFFF, /* offset 1 */
95         0x00000000, 0x0000FF00, 0x0000FFFF, 0x0000FFFF, /* offset 2 */
96         0x00000000, 0x000000FF, 0x000000FF, 0x000000FF, /* offset 3 */
97 #else
98         /*0 bytes*/ /*1 byte*/  /*2 bytes*/ /*3 bytes*/
99         0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF, /* offset 0 */
100         0x00000000, 0x0000FF00, 0x00FFFF00, 0xFFFFFF00, /* offset 1 */
101         0x00000000, 0x00FF0000, 0xFFFF0000, 0xFFFF0000, /* offset 2 */
102         0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, /* offset 3 */
103 #endif
104 };
105
106 union l_util {
107         u_int16_t s[2];
108         u_int32_t l;
109 };
110 union q_util {
111         u_int16_t s[4];
112         u_int32_t l[2];
113         u_int64_t q;
114 };
115
116 u_int64_t       in_cksumdata __P((caddr_t buf, int len));
117
118 u_int64_t
119 in_cksumdata(caddr_t buf, int len)
120 {
121         const u_int32_t *lw = (u_int32_t *) buf;
122         u_int64_t sum = 0;
123         u_int64_t prefilled;
124         int offset;
125         union q_util q_util;
126
127         if ((3 & (long) lw) == 0 && len == 20) {
128              sum = (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3] + lw[4];
129              REDUCE32;
130              return sum;
131         }
132
133         if ((offset = 3 & (long) lw) != 0) {
134                 const u_int32_t *masks = in_masks + (offset << 2);
135                 lw = (u_int32_t *) (((long) lw) - offset);
136                 sum = *lw++ & masks[len >= 3 ? 3 : len];
137                 len -= 4 - offset;
138                 if (len <= 0) {
139                         REDUCE32;
140                         return sum;
141                 }
142         }
143 #if 0
144         /*
145          * Force to cache line boundary.
146          */
147         offset = 32 - (0x1f & (long) lw);
148         if (offset < 32 && len > offset) {
149                 len -= offset;
150                 if (4 & offset) {
151                         sum += (u_int64_t) lw[0];
152                         lw += 1;
153                 }
154                 if (8 & offset) {
155                         sum += (u_int64_t) lw[0] + lw[1];
156                         lw += 2;
157                 }
158                 if (16 & offset) {
159                         sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
160                         lw += 4;
161                 }
162         }
163 #endif
164         /*
165          * access prefilling to start load of next cache line.
166          * then add current cache line
167          * save result of prefilling for loop iteration.
168          */
169         prefilled = lw[0];
170         while ((len -= 32) >= 4) {
171                 u_int64_t prefilling = lw[8];
172                 sum += prefilled + lw[1] + lw[2] + lw[3]
173                         + lw[4] + lw[5] + lw[6] + lw[7];
174                 lw += 8;
175                 prefilled = prefilling;
176         }
177         if (len >= 0) {
178                 sum += prefilled + lw[1] + lw[2] + lw[3]
179                         + lw[4] + lw[5] + lw[6] + lw[7];
180                 lw += 8;
181         } else {
182                 len += 32;
183         }
184         while ((len -= 16) >= 0) {
185                 sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
186                 lw += 4;
187         }
188         len += 16;
189         while ((len -= 4) >= 0) {
190                 sum += (u_int64_t) *lw++;
191         }
192         len += 4;
193         if (len > 0)
194                 sum += (u_int64_t) (in_masks[len] & *lw);
195         REDUCE32;
196         return sum;
197 }
198
199 u_short
200 in_addword(u_short a, u_short b)
201 {
202         u_int32_t sum = a + b;
203
204         ADDCARRY(sum);
205         return (sum);
206 }
207
208 u_short
209 in_pseudo(u_int32_t a, u_int32_t b, u_int32_t c)
210 {
211         u_int64_t sum;
212         union q_util q_util;
213         union l_util l_util;
214                     
215         sum = (u_int64_t) a + b + c;
216         REDUCE16;
217         return (sum);
218 }
219
220 int
221 in_cksum(struct mbuf *m, int len)
222 {
223         register u_int64_t sum = 0;
224         register int mlen = 0;
225         register int clen = 0;
226         register caddr_t addr;
227         union q_util q_util;
228         union l_util l_util;
229
230         for (; m && len; m = m->m_next) {
231                 if (m->m_len == 0)
232                         continue;
233                 mlen = m->m_len;
234                 if (len < mlen)
235                         mlen = len;
236                 addr = mtod(m, caddr_t);
237                 if ((clen ^ (long) addr) & 1)
238                     sum += in_cksumdata(addr, mlen) << 8;
239                 else
240                     sum += in_cksumdata(addr, mlen);
241
242                 clen += mlen;
243                 len -= mlen;
244         }
245         REDUCE16;
246         return (~sum & 0xffff);
247 }
248
249 u_short
250 in_cksum_skip(struct mbuf *m, int len, int skip)
251 {
252         u_int64_t sum = 0;
253         int mlen = 0;
254         int clen = 0;
255         caddr_t addr;
256         union q_util q_util;
257         union l_util l_util;
258
259         len -= skip;
260         for (; skip && m; m = m->m_next) {
261                 if (m->m_len > skip) {
262                         mlen = m->m_len - skip;
263                         addr = mtod(m, caddr_t) + skip;
264                         goto skip_start;
265                 } else {
266                         skip -= m->m_len;
267                 }
268         }
269
270         for (; m && len; m = m->m_next) {
271                 if (m->m_len == 0)
272                         continue;
273                 mlen = m->m_len;
274                 addr = mtod(m, caddr_t);
275 skip_start:
276                 if (len < mlen)
277                         mlen = len;
278                 if ((clen ^ (long) addr) & 1)
279                     sum += in_cksumdata(addr, mlen) << 8;
280                 else
281                     sum += in_cksumdata(addr, mlen);
282
283                 clen += mlen;
284                 len -= mlen;
285         }
286         REDUCE16;
287         return (~sum & 0xffff);
288 }
289
290 u_int in_cksum_hdr(const struct ip *ip)
291 {
292     u_int64_t sum = in_cksumdata((caddr_t) ip, sizeof(struct ip));
293     union q_util q_util;
294     union l_util l_util;
295     REDUCE16;
296     return (~sum & 0xffff);
297 }