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