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