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