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