Line data Source code
1 : /* $OpenBSD: in4_cksum.c,v 1.10 2014/09/08 06:24:13 jsg Exp $ */
2 : /* $KAME: in4_cksum.c,v 1.10 2001/11/30 10:06:15 itojun Exp $ */
3 : /* $NetBSD: in_cksum.c,v 1.13 1996/10/13 02:03:03 christos Exp $ */
4 :
5 : /*
6 : * Copyright (C) 1999 WIDE Project.
7 : * All rights reserved.
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. Neither the name of the project nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
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/param.h>
66 : #include <sys/mbuf.h>
67 : #include <sys/systm.h>
68 : #include <sys/socket.h>
69 : #include <sys/socketvar.h>
70 : #include <netinet/in.h>
71 : #include <netinet/ip.h>
72 : #include <netinet/ip_var.h>
73 :
74 : /*
75 : * Checksum routine for Internet Protocol family headers (Portable Version).
76 : * This is only for IPv4 pseudo header checksum.
77 : * No need to clear non-pseudo-header fields in IPv4 header.
78 : * len is for actual payload size, and does not include IPv4 header and
79 : * skipped header chain (off + len should be equal to the whole packet).
80 : *
81 : * This routine is very heavily used in the network
82 : * code and should be modified for each CPU to be as fast as possible.
83 : */
84 :
85 : #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
86 : #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
87 :
88 : int
89 0 : in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len)
90 : {
91 : u_int16_t *w;
92 : int sum = 0;
93 : int mlen = 0;
94 : int byte_swapped = 0;
95 : union {
96 : struct ipovly ipov;
97 : u_int16_t w[10];
98 : } u;
99 : union {
100 : u_int8_t c[2];
101 : u_int16_t s;
102 : } s_util;
103 : union {
104 : u_int16_t s[2];
105 : u_int32_t l;
106 : } l_util;
107 :
108 0 : if (nxt != 0) {
109 : /* pseudo header */
110 0 : if (off < sizeof(struct ipovly))
111 0 : panic("in4_cksum: offset too short");
112 0 : if (m->m_len < sizeof(struct ip))
113 0 : panic("in4_cksum: bad mbuf chain");
114 : bzero(&u.ipov, sizeof(u.ipov));
115 0 : u.ipov.ih_len = htons(len);
116 : u.ipov.ih_pr = nxt;
117 0 : u.ipov.ih_src = mtod(m, struct ip *)->ip_src;
118 0 : u.ipov.ih_dst = mtod(m, struct ip *)->ip_dst;
119 : w = u.w;
120 : /* assumes sizeof(ipov) == 20 */
121 0 : sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; sum += w[4];
122 0 : sum += w[5]; sum += w[6]; sum += w[7]; sum += w[8]; sum += w[9];
123 0 : }
124 :
125 : /* skip unnecessary part */
126 0 : while (m && off > 0) {
127 0 : if (m->m_len > off)
128 : break;
129 0 : off -= m->m_len;
130 0 : m = m->m_next;
131 : }
132 :
133 0 : for (;m && len; m = m->m_next) {
134 0 : if (m->m_len == 0)
135 : continue;
136 0 : w = (u_int16_t *)(mtod(m, caddr_t) + off);
137 0 : if (mlen == -1) {
138 : /*
139 : * The first byte of this mbuf is the continuation
140 : * of a word spanning between this mbuf and the
141 : * last mbuf.
142 : *
143 : * s_util.c[0] is already saved when scanning previous
144 : * mbuf.
145 : */
146 0 : s_util.c[1] = *(u_int8_t *)w;
147 0 : sum += s_util.s;
148 0 : w = (u_int16_t *)((u_int8_t *)w + 1);
149 0 : mlen = m->m_len - off - 1;
150 0 : len--;
151 0 : } else
152 0 : mlen = m->m_len - off;
153 : off = 0;
154 0 : if (len < mlen)
155 0 : mlen = len;
156 0 : len -= mlen;
157 : /*
158 : * Force to even boundary.
159 : */
160 0 : if ((1 & (long) w) && (mlen > 0)) {
161 0 : REDUCE;
162 0 : sum <<= 8;
163 0 : s_util.c[0] = *(u_int8_t *)w;
164 0 : w = (u_int16_t *)((int8_t *)w + 1);
165 0 : mlen--;
166 : byte_swapped = 1;
167 0 : }
168 : /*
169 : * Unroll the loop to make overhead from
170 : * branches &c small.
171 : */
172 0 : while ((mlen -= 32) >= 0) {
173 0 : sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
174 0 : sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
175 0 : sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
176 0 : sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
177 0 : w += 16;
178 : }
179 : mlen += 32;
180 0 : while ((mlen -= 8) >= 0) {
181 0 : sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
182 0 : w += 4;
183 : }
184 : mlen += 8;
185 0 : if (mlen == 0 && byte_swapped == 0)
186 : continue;
187 0 : REDUCE;
188 0 : while ((mlen -= 2) >= 0) {
189 0 : sum += *w++;
190 : }
191 0 : if (byte_swapped) {
192 0 : REDUCE;
193 0 : sum <<= 8;
194 : byte_swapped = 0;
195 0 : if (mlen == -1) {
196 0 : s_util.c[1] = *(u_int8_t *)w;
197 0 : sum += s_util.s;
198 : mlen = 0;
199 0 : } else
200 : mlen = -1;
201 0 : } else if (mlen == -1)
202 0 : s_util.c[0] = *(u_int8_t *)w;
203 : }
204 0 : if (len)
205 0 : printf("cksum4: out of data\n");
206 0 : if (mlen == -1) {
207 : /* The last mbuf has odd # of bytes. Follow the
208 : standard (the odd byte may be shifted left by 8 bits
209 : or not as determined by endian-ness of the machine) */
210 : s_util.c[1] = 0;
211 0 : sum += s_util.s;
212 0 : }
213 0 : REDUCE;
214 0 : return (~sum & 0xffff);
215 : }
|