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