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]; ADDCARRY(sum);} 82 83 /* 84 * m MUST contain a continuous IP6 header. 85 * off is an offset where TCP/UDP/ICMP6 header starts. 86 * len is a total length of a transport segment. 87 * (e.g. TCP header + TCP payload) 88 */ 89 int 90 in6_cksum(struct mbuf *m, u_int8_t nxt, u_int32_t off, u_int32_t len) 91 { 92 u_int16_t *w; 93 int sum = 0; 94 int mlen = 0; 95 int byte_swapped = 0; 96 struct ip6_hdr *ip6; 97 struct in6_addr in6; 98 union { 99 u_int16_t phs[4]; 100 struct { 101 u_int32_t ph_len; 102 u_int8_t ph_zero[3]; 103 u_int8_t ph_nxt; 104 } __packed ph; 105 } uph; 106 union { 107 u_int8_t c[2]; 108 u_int16_t s; 109 } s_util; 110 union { 111 u_int16_t s[2]; 112 u_int32_t l; 113 } l_util; 114 115 /* sanity check */ 116 if (m->m_pkthdr.len < off + len) { 117 panic("in6_cksum: mbuf len (%d) < off+len (%d+%d)", 118 m->m_pkthdr.len, off, len); 119 } 120 121 bzero(&uph, sizeof(uph)); 122 123 /* 124 * First create IP6 pseudo header and calculate a summary. 125 */ 126 ip6 = mtod(m, struct ip6_hdr *); 127 uph.ph.ph_len = htonl(len); 128 uph.ph.ph_nxt = nxt; 129 130 /* 131 * IPv6 source address. 132 * XXX: we'd like to avoid copying the address, but we can't due to 133 * the possibly embedded scope zone ID. 134 */ 135 in6 = ip6->ip6_src; 136 in6_clearscope(&in6); 137 w = (u_int16_t *)&in6; 138 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 139 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 140 141 /* IPv6 destination address */ 142 in6 = ip6->ip6_dst; 143 in6_clearscope(&in6); 144 w = (u_int16_t *)&in6; 145 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 146 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 147 148 /* Payload length and upper layer identifier */ 149 sum += uph.phs[0]; sum += uph.phs[1]; 150 sum += uph.phs[2]; sum += uph.phs[3]; 151 152 /* 153 * Secondly calculate a summary of the first mbuf excluding offset. 154 */ 155 while (off > 0) { 156 if (m->m_len <= off) 157 off -= m->m_len; 158 else 159 break; 160 m = m->m_next; 161 } 162 w = (u_int16_t *)(mtod(m, u_char *) + off); 163 mlen = m->m_len - off; 164 if (len < mlen) 165 mlen = len; 166 len -= mlen; 167 /* 168 * Force to even boundary. 169 */ 170 if ((1 & (long) w) && (mlen > 0)) { 171 REDUCE; 172 sum <<= 8; 173 s_util.c[0] = *(u_char *)w; 174 w = (u_int16_t *)((char *)w + 1); 175 mlen--; 176 byte_swapped = 1; 177 } 178 /* 179 * Unroll the loop to make overhead from 180 * branches &c small. 181 */ 182 while ((mlen -= 32) >= 0) { 183 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 184 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 185 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 186 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 187 w += 16; 188 } 189 mlen += 32; 190 while ((mlen -= 8) >= 0) { 191 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 192 w += 4; 193 } 194 mlen += 8; 195 if (mlen == 0 && byte_swapped == 0) 196 goto next; 197 REDUCE; 198 while ((mlen -= 2) >= 0) { 199 sum += *w++; 200 } 201 if (byte_swapped) { 202 REDUCE; 203 sum <<= 8; 204 byte_swapped = 0; 205 if (mlen == -1) { 206 s_util.c[1] = *(char *)w; 207 sum += s_util.s; 208 mlen = 0; 209 } else 210 mlen = -1; 211 } else if (mlen == -1) 212 s_util.c[0] = *(char *)w; 213 next: 214 m = m->m_next; 215 216 /* 217 * Lastly calculate a summary of the rest of mbufs. 218 */ 219 220 for (;m && len; m = m->m_next) { 221 if (m->m_len == 0) 222 continue; 223 w = mtod(m, u_int16_t *); 224 if (mlen == -1) { 225 /* 226 * The first byte of this mbuf is the continuation 227 * of a word spanning between this mbuf and the 228 * last mbuf. 229 * 230 * s_util.c[0] is already saved when scanning previous 231 * mbuf. 232 */ 233 s_util.c[1] = *(char *)w; 234 sum += s_util.s; 235 w = (u_int16_t *)((char *)w + 1); 236 mlen = m->m_len - 1; 237 len--; 238 } else 239 mlen = m->m_len; 240 if (len < mlen) 241 mlen = len; 242 len -= mlen; 243 /* 244 * Force to even boundary. 245 */ 246 if ((1 & (long) w) && (mlen > 0)) { 247 REDUCE; 248 sum <<= 8; 249 s_util.c[0] = *(u_char *)w; 250 w = (u_int16_t *)((char *)w + 1); 251 mlen--; 252 byte_swapped = 1; 253 } 254 /* 255 * Unroll the loop to make overhead from 256 * branches &c small. 257 */ 258 while ((mlen -= 32) >= 0) { 259 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 260 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 261 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 262 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 263 w += 16; 264 } 265 mlen += 32; 266 while ((mlen -= 8) >= 0) { 267 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 268 w += 4; 269 } 270 mlen += 8; 271 if (mlen == 0 && byte_swapped == 0) 272 continue; 273 REDUCE; 274 while ((mlen -= 2) >= 0) { 275 sum += *w++; 276 } 277 if (byte_swapped) { 278 REDUCE; 279 sum <<= 8; 280 byte_swapped = 0; 281 if (mlen == -1) { 282 s_util.c[1] = *(char *)w; 283 sum += s_util.s; 284 mlen = 0; 285 } else 286 mlen = -1; 287 } else if (mlen == -1) 288 s_util.c[0] = *(char *)w; 289 } 290 if (len) 291 panic("in6_cksum: out of data"); 292 if (mlen == -1) { 293 /* The last mbuf has odd # of bytes. Follow the 294 standard (the odd byte may be shifted left by 8 bits 295 or not as determined by endian-ness of the machine) */ 296 s_util.c[1] = 0; 297 sum += s_util.s; 298 } 299 REDUCE; 300 return (~sum & 0xffff); 301 } 302