Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netinet/in_cksum.c
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-4-Clause
3
*
4
* Copyright (c) 1988, 1992, 1993
5
* The Regents of the University of California. All rights reserved.
6
* Copyright (c) 1996
7
* Matt Thomas <[email protected]>
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
14
* 2. Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in the
16
* documentation and/or other materials provided with the distribution.
17
* 3. All advertising materials mentioning features or use of this software
18
* must display the following acknowledgement:
19
* This product includes software developed by the University of
20
* California, Berkeley and its contributors.
21
* 4. Neither the name of the University nor the names of its contributors
22
* may be used to endorse or promote products derived from this software
23
* without specific prior written permission.
24
*
25
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35
* SUCH DAMAGE.
36
*/
37
38
#include <sys/param.h>
39
#include <sys/mbuf.h>
40
#include <sys/systm.h>
41
#include <netinet/in_systm.h>
42
#include <netinet/in.h>
43
#include <netinet/ip.h>
44
#include <machine/in_cksum.h>
45
46
/*
47
* These implementations may be overridden on a per-platform basis. On
48
* platforms with a direct map, the implementation of in_cksum() must handle
49
* unmapped mbufs.
50
*/
51
#ifndef HAVE_MD_IN_CKSUM
52
53
/*
54
* Checksum routine for Internet Protocol family headers
55
* (Portable Alpha version).
56
*
57
* This routine is very heavily used in the network
58
* code and should be modified for each CPU to be as fast as possible.
59
*/
60
61
#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
62
#define REDUCE32 \
63
{ \
64
q_util.q = sum; \
65
sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
66
}
67
#define REDUCE16 \
68
{ \
69
q_util.q = sum; \
70
l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
71
sum = l_util.s[0] + l_util.s[1]; \
72
ADDCARRY(sum); \
73
}
74
75
static const u_int32_t in_masks[] = {
76
#if _BYTE_ORDER == _LITTLE_ENDIAN
77
/*0 bytes*/ /*1 byte*/ /*2 bytes*/ /*3 bytes*/
78
0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF, /* offset 0 */
79
0x00000000, 0x0000FF00, 0x00FFFF00, 0xFFFFFF00, /* offset 1 */
80
0x00000000, 0x00FF0000, 0xFFFF0000, 0xFFFF0000, /* offset 2 */
81
0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, /* offset 3 */
82
#else
83
/*0 bytes*/ /*1 byte*/ /*2 bytes*/ /*3 bytes*/
84
0x00000000, 0xFF000000, 0xFFFF0000, 0xFFFFFF00, /* offset 0 */
85
0x00000000, 0x00FF0000, 0x00FFFF00, 0x00FFFFFF, /* offset 1 */
86
0x00000000, 0x0000FF00, 0x0000FFFF, 0x0000FFFF, /* offset 2 */
87
0x00000000, 0x000000FF, 0x000000FF, 0x000000FF, /* offset 3 */
88
#endif
89
};
90
91
union l_util {
92
u_int16_t s[2];
93
u_int32_t l;
94
};
95
union q_util {
96
u_int16_t s[4];
97
u_int32_t l[2];
98
u_int64_t q;
99
};
100
101
static u_int64_t
102
in_cksumdata(const void *buf, int len)
103
{
104
const u_int32_t *lw = (const u_int32_t *) buf;
105
u_int64_t sum = 0;
106
u_int64_t prefilled;
107
int offset;
108
union q_util q_util;
109
110
if ((3 & (long) lw) == 0 && len == 20) {
111
sum = (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3] + lw[4];
112
REDUCE32;
113
return sum;
114
}
115
116
if ((offset = 3 & (long) lw) != 0) {
117
const u_int32_t *masks = in_masks + (offset << 2);
118
lw = (u_int32_t *) (((long) lw) - offset);
119
sum = *lw++ & masks[len >= 3 ? 3 : len];
120
len -= 4 - offset;
121
if (len <= 0) {
122
REDUCE32;
123
return sum;
124
}
125
}
126
#if 0
127
/*
128
* Force to cache line boundary.
129
*/
130
offset = 32 - (0x1f & (long) lw);
131
if (offset < 32 && len > offset) {
132
len -= offset;
133
if (4 & offset) {
134
sum += (u_int64_t) lw[0];
135
lw += 1;
136
}
137
if (8 & offset) {
138
sum += (u_int64_t) lw[0] + lw[1];
139
lw += 2;
140
}
141
if (16 & offset) {
142
sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
143
lw += 4;
144
}
145
}
146
#endif
147
/*
148
* access prefilling to start load of next cache line.
149
* then add current cache line
150
* save result of prefilling for loop iteration.
151
*/
152
prefilled = lw[0];
153
while ((len -= 32) >= 4) {
154
u_int64_t prefilling = lw[8];
155
sum += prefilled + lw[1] + lw[2] + lw[3]
156
+ lw[4] + lw[5] + lw[6] + lw[7];
157
lw += 8;
158
prefilled = prefilling;
159
}
160
if (len >= 0) {
161
sum += prefilled + lw[1] + lw[2] + lw[3]
162
+ lw[4] + lw[5] + lw[6] + lw[7];
163
lw += 8;
164
} else {
165
len += 32;
166
}
167
while ((len -= 16) >= 0) {
168
sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
169
lw += 4;
170
}
171
len += 16;
172
while ((len -= 4) >= 0) {
173
sum += (u_int64_t) *lw++;
174
}
175
len += 4;
176
if (len > 0)
177
sum += (u_int64_t) (in_masks[len] & *lw);
178
REDUCE32;
179
return sum;
180
}
181
182
u_short
183
in_addword(u_short a, u_short b)
184
{
185
u_int64_t sum = a + b;
186
187
ADDCARRY(sum);
188
return (sum);
189
}
190
191
u_short
192
in_pseudo(u_int32_t a, u_int32_t b, u_int32_t c)
193
{
194
u_int64_t sum;
195
union q_util q_util;
196
union l_util l_util;
197
198
sum = (u_int64_t) a + b + c;
199
REDUCE16;
200
return (sum);
201
}
202
203
struct cksum_skip_partial_args {
204
uint64_t csum;
205
int clen;
206
};
207
208
static int
209
in_cksum_skip_partial(void *arg, void *data, u_int len)
210
{
211
struct cksum_skip_partial_args *a;
212
213
a = arg;
214
if (((uintptr_t)data ^ a->clen) & 1)
215
a->csum += in_cksumdata(data, len) << 8;
216
else
217
a->csum += in_cksumdata(data, len);
218
a->clen += len;
219
return (0);
220
}
221
222
u_short
223
in_cksum_skip(struct mbuf *m, int len, int skip)
224
{
225
struct cksum_skip_partial_args a;
226
union q_util q_util;
227
union l_util l_util;
228
uint64_t sum;
229
230
len -= skip;
231
232
/*
233
* The use of m_apply() allows this routine to operate on unmapped
234
* mbufs.
235
*/
236
a.csum = 0;
237
a.clen = 0;
238
(void)m_apply(m, skip, len, in_cksum_skip_partial, &a);
239
sum = a.csum;
240
REDUCE16;
241
return (~sum & 0xffff);
242
}
243
244
u_int in_cksum_hdr(const struct ip *ip)
245
{
246
u_int64_t sum = in_cksumdata(ip, sizeof(struct ip));
247
union q_util q_util;
248
union l_util l_util;
249
REDUCE16;
250
return (~sum & 0xffff);
251
}
252
253
#endif /* !HAVE_MD_IN_CKSUM */
254
255