net: Move ip.h to net/ip.h
[akaros.git] / kern / src / net / ptclbsum.c
1 /* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
2  * Portions Copyright © 1997-1999 Vita Nuova Limited
3  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
4  *                                (www.vitanuova.com)
5  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
6  *
7  * Modified for the Akaros operating system:
8  * Copyright (c) 2013-2014 The Regents of the University of California
9  * Copyright (c) 2013-2015 Google Inc.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE. */
28
29 #include <vfs.h>
30 #include <kfs.h>
31 #include <slab.h>
32 #include <kmalloc.h>
33 #include <kref.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <assert.h>
37 #include <error.h>
38 #include <cpio.h>
39 #include <pmap.h>
40 #include <smp.h>
41 #include <net/ip.h>
42 #include <endian.h>
43
44 static short endian = 1;
45 static uint8_t *aendian = (uint8_t *) & endian;
46 #define LITTLE  *aendian
47
48
49 #ifdef CONFIG_X86
50
51 /* $NetBSD: in_cksum.c,v 1.7 1997/09/02 13:18:15 thorpej Exp $ */
52
53 /*-
54  * Copyright (c) 1988, 1992, 1993
55  *      The Regents of the University of California.  All rights reserved.
56  * Copyright (c) 1996
57  *      Matt Thomas <matt@3am-software.com>
58  *
59  * Redistribution and use in source and binary forms, with or without
60  * modification, are permitted provided that the following conditions
61  * are met:
62  * 1. Redistributions of source code must retain the above copyright
63  *    notice, this list of conditions and the following disclaimer.
64  * 2. Redistributions in binary form must reproduce the above copyright
65  *    notice, this list of conditions and the following disclaimer in the
66  *    documentation and/or other materials provided with the distribution.
67  * 3. All advertising materials mentioning features or use of this software
68  *    must display the following acknowledgement:
69  *      This product includes software developed by the University of
70  *      California, Berkeley and its contributors.
71  * 4. Neither the name of the University nor the names of its contributors
72  *    may be used to endorse or promote products derived from this software
73  *    without specific prior written permission.
74  *
75  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
76  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
77  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
78  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
79  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
80  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
81  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
82  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
83  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
84  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
85  * SUCH DAMAGE.
86  *
87  *      @(#)in_cksum.c  8.1 (Berkeley) 6/10/93
88  */
89
90 /*
91  * Checksum routine for Internet Protocol family headers
92  *    (Portable Alpha version).
93  *
94  * This routine is very heavily used in the network
95  * code and should be modified for each CPU to be as fast as possible.
96  */
97
98 #define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
99 #define REDUCE32                                                          \
100     {                                                                     \
101         q_util.q = sum;                                                   \
102         sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3];      \
103     }
104 #define REDUCE16                                                          \
105     {                                                                     \
106         q_util.q = sum;                                                   \
107         l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
108         sum = l_util.s[0] + l_util.s[1];                                  \
109         ADDCARRY(sum);                                                    \
110     }
111
112 static const uint32_t in_masks[] = {
113         /*0 bytes*/ /*1 byte*/  /*2 bytes*/ /*3 bytes*/
114         0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF, /* offset 0 */
115         0x00000000, 0x0000FF00, 0x00FFFF00, 0xFFFFFF00, /* offset 1 */
116         0x00000000, 0x00FF0000, 0xFFFF0000, 0xFFFF0000, /* offset 2 */
117         0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, /* offset 3 */
118 };
119
120 union l_util {
121         uint16_t s[2];
122         uint32_t l;
123 };
124 union q_util {
125         uint16_t s[4];
126         uint32_t l[2];
127         uint64_t q;
128 };
129
130 static uint64_t
131 in_cksumdata(const void *buf, int len)
132 {
133         const uint32_t *lw = (const uint32_t *) buf;
134         uint64_t sum = 0;
135         uint64_t prefilled;
136         int offset;
137         union q_util q_util;
138
139         if ((3 & (long) lw) == 0 && len == 20) {
140              sum = (uint64_t) lw[0] + lw[1] + lw[2] + lw[3] + lw[4];
141              REDUCE32;
142              return sum;
143         }
144
145         if ((offset = 3 & (long) lw) != 0) {
146                 const uint32_t *masks = in_masks + (offset << 2);
147                 lw = (uint32_t *) (((long) lw) - offset);
148                 sum = *lw++ & masks[len >= 3 ? 3 : len];
149                 len -= 4 - offset;
150                 if (len <= 0) {
151                         REDUCE32;
152                         return sum;
153                 }
154         }
155 #if 0
156         /*
157          * Force to cache line boundary.
158          */
159         offset = 32 - (0x1f & (long) lw);
160         if (offset < 32 && len > offset) {
161                 len -= offset;
162                 if (4 & offset) {
163                         sum += (uint64_t) lw[0];
164                         lw += 1;
165                 }
166                 if (8 & offset) {
167                         sum += (uint64_t) lw[0] + lw[1];
168                         lw += 2;
169                 }
170                 if (16 & offset) {
171                         sum += (uint64_t) lw[0] + lw[1] + lw[2] + lw[3];
172                         lw += 4;
173                 }
174         }
175 #endif
176         /*
177          * access prefilling to start load of next cache line.
178          * then add current cache line
179          * save result of prefilling for loop iteration.
180          */
181         prefilled = lw[0];
182         while ((len -= 32) >= 4) {
183                 uint64_t prefilling = lw[8];
184                 sum += prefilled + lw[1] + lw[2] + lw[3]
185                         + lw[4] + lw[5] + lw[6] + lw[7];
186                 lw += 8;
187                 prefilled = prefilling;
188         }
189         if (len >= 0) {
190                 sum += prefilled + lw[1] + lw[2] + lw[3]
191                         + lw[4] + lw[5] + lw[6] + lw[7];
192                 lw += 8;
193         } else {
194                 len += 32;
195         }
196         while ((len -= 16) >= 0) {
197                 sum += (uint64_t) lw[0] + lw[1] + lw[2] + lw[3];
198                 lw += 4;
199         }
200         len += 16;
201         while ((len -= 4) >= 0) {
202                 sum += (uint64_t) *lw++;
203         }
204         len += 4;
205         if (len > 0)
206                 sum += (uint64_t) (in_masks[len] & *lw);
207         REDUCE32;
208         return sum;
209 }
210 uint16_t ptclbsum(uint8_t * addr, int len)
211 {
212         uint64_t sum = in_cksumdata(addr, len);
213         union q_util q_util;
214         union l_util l_util;
215         if ((uintptr_t)addr & 1)
216                 sum <<= 8;
217         REDUCE16;
218         return cpu_to_be16(sum);
219 }
220 #else
221 uint16_t ptclbsum(uint8_t * addr, int len)
222 {
223         uint32_t losum, hisum, mdsum, x;
224         uint32_t t1, t2;
225
226         losum = 0;
227         hisum = 0;
228         mdsum = 0;
229
230         x = 0;
231         if ((uintptr_t) addr & 1) {
232                 if (len) {
233                         hisum += addr[0];
234                         len--;
235                         addr++;
236                 }
237                 x = 1;
238         }
239         while (len >= 16) {
240                 t1 = *(uint16_t *) (addr + 0);
241                 t2 = *(uint16_t *) (addr + 2);
242                 mdsum += t1;
243                 t1 = *(uint16_t *) (addr + 4);
244                 mdsum += t2;
245                 t2 = *(uint16_t *) (addr + 6);
246                 mdsum += t1;
247                 t1 = *(uint16_t *) (addr + 8);
248                 mdsum += t2;
249                 t2 = *(uint16_t *) (addr + 10);
250                 mdsum += t1;
251                 t1 = *(uint16_t *) (addr + 12);
252                 mdsum += t2;
253                 t2 = *(uint16_t *) (addr + 14);
254                 mdsum += t1;
255                 mdsum += t2;
256                 len -= 16;
257                 addr += 16;
258         }
259         while (len >= 2) {
260                 mdsum += *(uint16_t *) addr;
261                 len -= 2;
262                 addr += 2;
263         }
264         if (x) {
265                 if (len)
266                         losum += addr[0];
267                 if (LITTLE)
268                         losum += mdsum;
269                 else
270                         hisum += mdsum;
271         } else {
272                 if (len)
273                         hisum += addr[0];
274                 if (LITTLE)
275                         hisum += mdsum;
276                 else
277                         losum += mdsum;
278         }
279
280         losum += hisum >> 8;
281         losum += (hisum & 0xff) << 8;
282         while ((hisum = losum >> 16))
283                 losum = hisum + (losum & 0xffff);
284
285         return losum & 0xffff;
286 }
287 #endif