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 */ 149 int 150 in6_cksum(struct mbuf *m, u_int8_t nxt, u_int32_t off, u_int32_t len) 151 { 152 struct ip6_hdr *ip6; 153 u_int16_t *w, scope; 154 int byte_swapped, mlen; 155 int sum; 156 union { 157 u_int16_t phs[4]; 158 struct { 159 u_int32_t ph_len; 160 u_int8_t ph_zero[3]; 161 u_int8_t ph_nxt; 162 } __packed ph; 163 } uph; 164 union { 165 u_int8_t c[2]; 166 u_int16_t s; 167 } s_util; 168 union { 169 u_int16_t s[2]; 170 u_int32_t l; 171 } l_util; 172 173 /* Sanity check. */ 174 KASSERT(m->m_pkthdr.len >= off + len, ("%s: mbuf len (%d) < off(%d)+" 175 "len(%d)", __func__, m->m_pkthdr.len, off, len)); 176 177 /* 178 * First create IP6 pseudo header and calculate a summary. 179 */ 180 uph.ph.ph_len = htonl(len); 181 uph.ph.ph_zero[0] = uph.ph.ph_zero[1] = uph.ph.ph_zero[2] = 0; 182 uph.ph.ph_nxt = nxt; 183 184 /* Payload length and upper layer identifier. */ 185 sum = uph.phs[0]; sum += uph.phs[1]; 186 sum += uph.phs[2]; sum += uph.phs[3]; 187 188 ip6 = mtod(m, struct ip6_hdr *); 189 190 /* IPv6 source address. */ 191 scope = in6_getscope(&ip6->ip6_src); 192 w = (u_int16_t *)&ip6->ip6_src; 193 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 194 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 195 if (scope != 0) 196 sum -= scope; 197 198 /* IPv6 destination address. */ 199 scope = in6_getscope(&ip6->ip6_dst); 200 w = (u_int16_t *)&ip6->ip6_dst; 201 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 202 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 203 if (scope != 0) 204 sum -= scope; 205 206 /* 207 * Secondly calculate a summary of the first mbuf excluding offset. 208 */ 209 while (off > 0) { 210 if (m->m_len <= off) 211 off -= m->m_len; 212 else 213 break; 214 m = m->m_next; 215 } 216 w = (u_int16_t *)(mtod(m, u_char *) + off); 217 mlen = m->m_len - off; 218 if (len < mlen) 219 mlen = len; 220 len -= mlen; 221 /* 222 * Force to even boundary. 223 */ 224 if ((1 & (long)w) && (mlen > 0)) { 225 REDUCE; 226 sum <<= 8; 227 s_util.c[0] = *(u_char *)w; 228 w = (u_int16_t *)((char *)w + 1); 229 mlen--; 230 byte_swapped = 1; 231 } else 232 byte_swapped = 0; 233 234 /* 235 * Unroll the loop to make overhead from 236 * branches &c small. 237 */ 238 while ((mlen -= 32) >= 0) { 239 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 240 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 241 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 242 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 243 w += 16; 244 } 245 mlen += 32; 246 while ((mlen -= 8) >= 0) { 247 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 248 w += 4; 249 } 250 mlen += 8; 251 if (mlen == 0 && byte_swapped == 0) 252 goto next; 253 REDUCE; 254 while ((mlen -= 2) >= 0) { 255 sum += *w++; 256 } 257 if (byte_swapped) { 258 REDUCE; 259 sum <<= 8; 260 byte_swapped = 0; 261 if (mlen == -1) { 262 s_util.c[1] = *(char *)w; 263 sum += s_util.s; 264 mlen = 0; 265 } else 266 mlen = -1; 267 } else if (mlen == -1) 268 s_util.c[0] = *(char *)w; 269 next: 270 m = m->m_next; 271 272 /* 273 * Lastly calculate a summary of the rest of mbufs. 274 */ 275 276 for (;m && len; m = m->m_next) { 277 if (m->m_len == 0) 278 continue; 279 w = mtod(m, u_int16_t *); 280 if (mlen == -1) { 281 /* 282 * The first byte of this mbuf is the continuation 283 * of a word spanning between this mbuf and the 284 * last mbuf. 285 * 286 * s_util.c[0] is already saved when scanning previous 287 * mbuf. 288 */ 289 s_util.c[1] = *(char *)w; 290 sum += s_util.s; 291 w = (u_int16_t *)((char *)w + 1); 292 mlen = m->m_len - 1; 293 len--; 294 } else 295 mlen = m->m_len; 296 if (len < mlen) 297 mlen = len; 298 len -= mlen; 299 /* 300 * Force to even boundary. 301 */ 302 if ((1 & (long) w) && (mlen > 0)) { 303 REDUCE; 304 sum <<= 8; 305 s_util.c[0] = *(u_char *)w; 306 w = (u_int16_t *)((char *)w + 1); 307 mlen--; 308 byte_swapped = 1; 309 } 310 /* 311 * Unroll the loop to make overhead from 312 * branches &c small. 313 */ 314 while ((mlen -= 32) >= 0) { 315 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 316 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 317 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 318 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 319 w += 16; 320 } 321 mlen += 32; 322 while ((mlen -= 8) >= 0) { 323 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 324 w += 4; 325 } 326 mlen += 8; 327 if (mlen == 0 && byte_swapped == 0) 328 continue; 329 REDUCE; 330 while ((mlen -= 2) >= 0) { 331 sum += *w++; 332 } 333 if (byte_swapped) { 334 REDUCE; 335 sum <<= 8; 336 byte_swapped = 0; 337 if (mlen == -1) { 338 s_util.c[1] = *(char *)w; 339 sum += s_util.s; 340 mlen = 0; 341 } else 342 mlen = -1; 343 } else if (mlen == -1) 344 s_util.c[0] = *(char *)w; 345 } 346 if (len) 347 panic("in6_cksum: out of data"); 348 if (mlen == -1) { 349 /* The last mbuf has odd # of bytes. Follow the 350 standard (the odd byte may be shifted left by 8 bits 351 or not as determined by endian-ness of the machine) */ 352 s_util.c[1] = 0; 353 sum += s_util.s; 354 } 355 REDUCE; 356 return (~sum & 0xffff); 357 } 358