1/* SPDX-License-Identifier: BSD-3-Clause */
2/*
3 * Copyright (c) 1988, 1992, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93
31 * in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp
32 */
33
34#include "slirp.h"
35
36/*
37 * Checksum routine for Internet Protocol family headers (Portable Version).
38 *
39 * This routine is very heavily used in the network
40 * code and should be modified for each CPU to be as fast as possible.
41 *
42 * XXX Since we will never span more than 1 mbuf, we can optimise this
43 */
44
45#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
46#define REDUCE \
47 { \
48 l_util.l = sum; \
49 sum = l_util.s[0] + l_util.s[1]; \
50 (void)ADDCARRY(sum); \
51 }
52
53int cksum(struct mbuf *m, int len)
54{
55 register uint16_t *w;
56 register int sum = 0;
57 register int mlen = 0;
58 int byte_swapped = 0;
59
60 union {
61 uint8_t c[2];
62 uint16_t s;
63 } s_util;
64 union {
65 uint16_t s[2];
66 uint32_t l;
67 } l_util;
68
69 if (m->m_len == 0)
70 goto cont;
71 w = mtod(m, uint16_t *);
72
73 mlen = m->m_len;
74
75 if (len < mlen)
76 mlen = len;
77 len -= mlen;
78 /*
79 * Force to even boundary.
80 */
81 if ((1 & (uintptr_t)w) && (mlen > 0)) {
82 REDUCE;
83 sum <<= 8;
84 s_util.c[0] = *(uint8_t *)w;
85 w = (uint16_t *)((int8_t *)w + 1);
86 mlen--;
87 byte_swapped = 1;
88 }
89 /*
90 * Unroll the loop to make overhead from
91 * branches &c small.
92 */
93 while ((mlen -= 32) >= 0) {
94 sum += w[0];
95 sum += w[1];
96 sum += w[2];
97 sum += w[3];
98 sum += w[4];
99 sum += w[5];
100 sum += w[6];
101 sum += w[7];
102 sum += w[8];
103 sum += w[9];
104 sum += w[10];
105 sum += w[11];
106 sum += w[12];
107 sum += w[13];
108 sum += w[14];
109 sum += w[15];
110 w += 16;
111 }
112 mlen += 32;
113 while ((mlen -= 8) >= 0) {
114 sum += w[0];
115 sum += w[1];
116 sum += w[2];
117 sum += w[3];
118 w += 4;
119 }
120 mlen += 8;
121 if (mlen == 0 && byte_swapped == 0)
122 goto cont;
123 REDUCE;
124 while ((mlen -= 2) >= 0) {
125 sum += *w++;
126 }
127
128 if (byte_swapped) {
129 REDUCE;
130 sum <<= 8;
131 if (mlen == -1) {
132 s_util.c[1] = *(uint8_t *)w;
133 sum += s_util.s;
134 mlen = 0;
135 } else
136
137 mlen = -1;
138 } else if (mlen == -1)
139 s_util.c[0] = *(uint8_t *)w;
140
141cont:
142 if (len) {
143 DEBUG_ERROR("cksum: out of data");
144 DEBUG_ERROR(" len = %d", len);
145 }
146 if (mlen == -1) {
147 /* The last mbuf has odd # of bytes. Follow the
148 standard (the odd byte may be shifted left by 8 bits
149 or not as determined by endian-ness of the machine) */
150 s_util.c[1] = 0;
151 sum += s_util.s;
152 }
153 REDUCE;
154 return (~sum & 0xffff);
155}
156
157int ip6_cksum(struct mbuf *m)
158{
159 /* TODO: Optimize this by being able to pass the ip6_pseudohdr to cksum
160 * separately from the mbuf */
161 struct ip6 save_ip, *ip = mtod(m, struct ip6 *);
162 struct ip6_pseudohdr *ih = mtod(m, struct ip6_pseudohdr *);
163 int sum;
164
165 save_ip = *ip;
166
167 ih->ih_src = save_ip.ip_src;
168 ih->ih_dst = save_ip.ip_dst;
169 ih->ih_pl = htonl((uint32_t)ntohs(save_ip.ip_pl));
170 ih->ih_zero_hi = 0;
171 ih->ih_zero_lo = 0;
172 ih->ih_nh = save_ip.ip_nh;
173
174 sum = cksum(m, ((int)sizeof(struct ip6_pseudohdr)) + ntohl(ih->ih_pl));
175
176 *ip = save_ip;
177
178 return sum;
179}
180