]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet6/in6_cksum.c
amd64: use register macros for gdb_cpu_getreg()
[FreeBSD/FreeBSD.git] / sys / netinet6 / in6_cksum.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  *      $KAME: in6_cksum.c,v 1.10 2000/12/03 00:53:59 itojun Exp $
32  */
33
34 /*-
35  * Copyright (c) 1988, 1992, 1993
36  *      The Regents of the University of California.  All rights reserved.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. Neither the name of the University nor the names of its contributors
47  *    may be used to endorse or promote products derived from this software
48  *    without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60  * SUCH DAMAGE.
61  *
62  *      @(#)in_cksum.c  8.1 (Berkeley) 6/10/93
63  */
64
65 #include <sys/cdefs.h>
66 __FBSDID("$FreeBSD$");
67
68 #include <sys/param.h>
69 #include <sys/mbuf.h>
70 #include <sys/systm.h>
71 #include <netinet/in.h>
72 #include <netinet/ip6.h>
73 #include <netinet6/scope6_var.h>
74
75 /*
76  * Checksum routine for Internet Protocol family headers (Portable Version).
77  *
78  * This routine is very heavily used in the network
79  * code and should be modified for each CPU to be as fast as possible.
80  */
81
82 #define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
83 #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; (void)ADDCARRY(sum);}
84
85 static int
86 _in6_cksum_pseudo(struct ip6_hdr *ip6, uint32_t len, uint8_t nxt, uint16_t csum)
87 {
88         int sum;
89         uint16_t scope, *w;
90         union {
91                 u_int16_t phs[4];
92                 struct {
93                         u_int32_t       ph_len;
94                         u_int8_t        ph_zero[3];
95                         u_int8_t        ph_nxt;
96                 } __packed ph;
97         } uph;
98
99         sum = csum;
100
101         /*
102          * First create IP6 pseudo header and calculate a summary.
103          */
104         uph.ph.ph_len = htonl(len);
105         uph.ph.ph_zero[0] = uph.ph.ph_zero[1] = uph.ph.ph_zero[2] = 0;
106         uph.ph.ph_nxt = nxt;
107
108         /* Payload length and upper layer identifier. */
109         sum += uph.phs[0];  sum += uph.phs[1];
110         sum += uph.phs[2];  sum += uph.phs[3];
111
112         /* IPv6 source address. */
113         scope = in6_getscope(&ip6->ip6_src);
114         w = (u_int16_t *)&ip6->ip6_src;
115         sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
116         sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
117         if (scope != 0)
118                 sum -= scope;
119
120         /* IPv6 destination address. */
121         scope = in6_getscope(&ip6->ip6_dst);
122         w = (u_int16_t *)&ip6->ip6_dst;
123         sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
124         sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
125         if (scope != 0)
126                 sum -= scope;
127
128         return (sum);
129 }
130
131 int
132 in6_cksum_pseudo(struct ip6_hdr *ip6, uint32_t len, uint8_t nxt, uint16_t csum)
133 {
134         int sum;
135         union {
136                 u_int16_t s[2];
137                 u_int32_t l;
138         } l_util;
139
140         sum = _in6_cksum_pseudo(ip6, len, nxt, csum);
141         REDUCE;
142         return (sum);
143 }
144
145 /*
146  * m MUST contain a contiguous IP6 header.
147  * off is an offset where TCP/UDP/ICMP6 header starts.
148  * len is a total length of a transport segment.
149  * (e.g. TCP header + TCP payload)
150  * cov is the number of bytes to be taken into account for the checksum
151  */
152 int
153 in6_cksum_partial(struct mbuf *m, u_int8_t nxt, u_int32_t off,
154     u_int32_t len, u_int32_t cov)
155 {
156         struct ip6_hdr *ip6;
157         u_int16_t *w, scope;
158         int byte_swapped, mlen;
159         int sum;
160         union {
161                 u_int16_t phs[4];
162                 struct {
163                         u_int32_t       ph_len;
164                         u_int8_t        ph_zero[3];
165                         u_int8_t        ph_nxt;
166                 } __packed ph;
167         } uph;
168         union {
169                 u_int8_t        c[2];
170                 u_int16_t       s;
171         } s_util;
172         union {
173                 u_int16_t s[2];
174                 u_int32_t l;
175         } l_util;
176
177         /* Sanity check. */
178         KASSERT(m->m_pkthdr.len >= off + len, ("%s: mbuf len (%d) < off(%d)+"
179             "len(%d)", __func__, m->m_pkthdr.len, off, len));
180
181         /*
182          * First create IP6 pseudo header and calculate a summary.
183          */
184         uph.ph.ph_len = htonl(len);
185         uph.ph.ph_zero[0] = uph.ph.ph_zero[1] = uph.ph.ph_zero[2] = 0;
186         uph.ph.ph_nxt = nxt;
187
188         /* Payload length and upper layer identifier. */
189         sum = uph.phs[0];  sum += uph.phs[1];
190         sum += uph.phs[2];  sum += uph.phs[3];
191
192         ip6 = mtod(m, struct ip6_hdr *);
193
194         /* IPv6 source address. */
195         scope = in6_getscope(&ip6->ip6_src);
196         w = (u_int16_t *)&ip6->ip6_src;
197         sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
198         sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
199         if (scope != 0)
200                 sum -= scope;
201
202         /* IPv6 destination address. */
203         scope = in6_getscope(&ip6->ip6_dst);
204         w = (u_int16_t *)&ip6->ip6_dst;
205         sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
206         sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
207         if (scope != 0)
208                 sum -= scope;
209
210         /*
211          * Secondly calculate a summary of the first mbuf excluding offset.
212          */
213         while (off > 0) {
214                 if (m->m_len <= off)
215                         off -= m->m_len;
216                 else
217                         break;
218                 m = m->m_next;
219         }
220         w = (u_int16_t *)(mtod(m, u_char *) + off);
221         mlen = m->m_len - off;
222         if (cov < mlen)
223                 mlen = cov;
224         cov -= mlen;
225         /*
226          * Force to even boundary.
227          */
228         if ((1 & (long)w) && (mlen > 0)) {
229                 REDUCE;
230                 sum <<= 8;
231                 s_util.c[0] = *(u_char *)w;
232                 w = (u_int16_t *)((char *)w + 1);
233                 mlen--;
234                 byte_swapped = 1;
235         } else
236                 byte_swapped = 0;
237
238         /*
239          * Unroll the loop to make overhead from
240          * branches &c small.
241          */
242         while ((mlen -= 32) >= 0) {
243                 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
244                 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
245                 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
246                 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
247                 w += 16;
248         }
249         mlen += 32;
250         while ((mlen -= 8) >= 0) {
251                 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
252                 w += 4;
253         }
254         mlen += 8;
255         if (mlen == 0 && byte_swapped == 0)
256                 goto next;
257         REDUCE;
258         while ((mlen -= 2) >= 0) {
259                 sum += *w++;
260         }
261         if (byte_swapped) {
262                 REDUCE;
263                 sum <<= 8;
264                 byte_swapped = 0;
265                 if (mlen == -1) {
266                         s_util.c[1] = *(char *)w;
267                         sum += s_util.s;
268                         mlen = 0;
269                 } else
270                         mlen = -1;
271         } else if (mlen == -1)
272                 s_util.c[0] = *(char *)w;
273  next:
274         m = m->m_next;
275
276         /*
277          * Lastly calculate a summary of the rest of mbufs.
278          */
279
280         for (;m && cov; m = m->m_next) {
281                 if (m->m_len == 0)
282                         continue;
283                 w = mtod(m, u_int16_t *);
284                 if (mlen == -1) {
285                         /*
286                          * The first byte of this mbuf is the continuation
287                          * of a word spanning between this mbuf and the
288                          * last mbuf.
289                          *
290                          * s_util.c[0] is already saved when scanning previous
291                          * mbuf.
292                          */
293                         s_util.c[1] = *(char *)w;
294                         sum += s_util.s;
295                         w = (u_int16_t *)((char *)w + 1);
296                         mlen = m->m_len - 1;
297                         cov--;
298                 } else
299                         mlen = m->m_len;
300                 if (cov < mlen)
301                         mlen = cov;
302                 cov -= mlen;
303                 /*
304                  * Force to even boundary.
305                  */
306                 if ((1 & (long) w) && (mlen > 0)) {
307                         REDUCE;
308                         sum <<= 8;
309                         s_util.c[0] = *(u_char *)w;
310                         w = (u_int16_t *)((char *)w + 1);
311                         mlen--;
312                         byte_swapped = 1;
313                 }
314                 /*
315                  * Unroll the loop to make overhead from
316                  * branches &c small.
317                  */
318                 while ((mlen -= 32) >= 0) {
319                         sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
320                         sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
321                         sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
322                         sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
323                         w += 16;
324                 }
325                 mlen += 32;
326                 while ((mlen -= 8) >= 0) {
327                         sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
328                         w += 4;
329                 }
330                 mlen += 8;
331                 if (mlen == 0 && byte_swapped == 0)
332                         continue;
333                 REDUCE;
334                 while ((mlen -= 2) >= 0) {
335                         sum += *w++;
336                 }
337                 if (byte_swapped) {
338                         REDUCE;
339                         sum <<= 8;
340                         byte_swapped = 0;
341                         if (mlen == -1) {
342                                 s_util.c[1] = *(char *)w;
343                                 sum += s_util.s;
344                                 mlen = 0;
345                         } else
346                                 mlen = -1;
347                 } else if (mlen == -1)
348                         s_util.c[0] = *(char *)w;
349         }
350         if (cov)
351                 panic("in6_cksum: out of data");
352         if (mlen == -1) {
353                 /* The last mbuf has odd # of bytes. Follow the
354                    standard (the odd byte may be shifted left by 8 bits
355                    or not as determined by endian-ness of the machine) */
356                 s_util.c[1] = 0;
357                 sum += s_util.s;
358         }
359         REDUCE;
360         return (~sum & 0xffff);
361 }
362
363 int
364 in6_cksum(struct mbuf *m, u_int8_t nxt, u_int32_t off, u_int32_t len)
365 {
366         return (in6_cksum_partial(m, nxt, off, len, len));
367 }