1 /* $OpenBSD: in6_cksum.c,v 1.15 2008/06/11 19:00:50 mcbride Exp $ */ 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. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 * 61 * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 62 */ 63 64 #include <sys/param.h> 65 #include <sys/mbuf.h> 66 #include <sys/systm.h> 67 #include <netinet/in.h> 68 #include <netinet/ip6.h> 69 70 /* 71 * Checksum routine for Internet Protocol family headers (Portable Version). 72 * 73 * This routine is very heavily used in the network 74 * code and should be modified for each CPU to be as fast as possible. 75 */ 76 77 #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) 78 #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} 79 80 /* 81 * m MUST contain a continuous IP6 header. 82 * off is a offset where TCP/UDP/ICMP6 header starts. 83 * len is a total length of a transport segment. 84 * (e.g. TCP header + TCP payload) 85 */ 86 87 int 88 in6_cksum(struct mbuf *m, u_int8_t nxt, u_int32_t off, u_int32_t len) 89 { 90 u_int16_t *w; 91 int sum = 0; 92 int mlen = 0; 93 int byte_swapped = 0; 94 struct ip6_hdr *ip6; 95 union { 96 u_int16_t phs[4]; 97 struct { 98 u_int32_t ph_len; 99 u_int8_t ph_zero[3]; 100 u_int8_t ph_nxt; 101 } ph __packed; 102 } uph; 103 union { 104 u_int8_t c[2]; 105 u_int16_t s; 106 } s_util; 107 union { 108 u_int16_t s[2]; 109 u_int32_t l; 110 } l_util; 111 112 /* sanity check */ 113 if (m->m_pkthdr.len < off + len) { 114 panic("in6_cksum: mbuf len (%d) < off+len (%d+%d)", 115 m->m_pkthdr.len, off, len); 116 } 117 118 bzero(&uph, sizeof(uph)); 119 120 /* 121 * First create IP6 pseudo header and calculate a summary. 122 */ 123 ip6 = mtod(m, struct ip6_hdr *); 124 w = (u_int16_t *)&ip6->ip6_src; 125 uph.ph.ph_len = htonl(len); 126 uph.ph.ph_nxt = nxt; 127 128 /* IPv6 source address */ 129 sum += w[0]; 130 if (!IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) 131 sum += w[1]; 132 sum += w[2]; sum += w[3]; sum += w[4]; sum += w[5]; 133 sum += w[6]; sum += w[7]; 134 /* IPv6 destination address */ 135 sum += w[8]; 136 if (!IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) 137 sum += w[9]; 138 sum += w[10]; sum += w[11]; sum += w[12]; sum += w[13]; 139 sum += w[14]; sum += w[15]; 140 /* Payload length and upper layer identifier */ 141 sum += uph.phs[0]; sum += uph.phs[1]; 142 sum += uph.phs[2]; sum += uph.phs[3]; 143 144 /* 145 * Secondly calculate a summary of the first mbuf excluding offset. 146 */ 147 while (m != NULL && off > 0) { 148 if (m->m_len <= off) 149 off -= m->m_len; 150 else 151 break; 152 m = m->m_next; 153 } 154 w = (u_int16_t *)(mtod(m, u_char *) + off); 155 mlen = m->m_len - off; 156 if (len < mlen) 157 mlen = len; 158 len -= mlen; 159 /* 160 * Force to even boundary. 161 */ 162 if ((1 & (long) w) && (mlen > 0)) { 163 REDUCE; 164 sum <<= 8; 165 s_util.c[0] = *(u_char *)w; 166 w = (u_int16_t *)((char *)w + 1); 167 mlen--; 168 byte_swapped = 1; 169 } 170 /* 171 * Unroll the loop to make overhead from 172 * branches &c small. 173 */ 174 while ((mlen -= 32) >= 0) { 175 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 176 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 177 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 178 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 179 w += 16; 180 } 181 mlen += 32; 182 while ((mlen -= 8) >= 0) { 183 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 184 w += 4; 185 } 186 mlen += 8; 187 if (mlen == 0 && byte_swapped == 0) 188 goto next; 189 REDUCE; 190 while ((mlen -= 2) >= 0) { 191 sum += *w++; 192 } 193 if (byte_swapped) { 194 REDUCE; 195 sum <<= 8; 196 byte_swapped = 0; 197 if (mlen == -1) { 198 s_util.c[1] = *(char *)w; 199 sum += s_util.s; 200 mlen = 0; 201 } else 202 mlen = -1; 203 } else if (mlen == -1) 204 s_util.c[0] = *(char *)w; 205 next: 206 m = m->m_next; 207 208 /* 209 * Lastly calculate a summary of the rest of mbufs. 210 */ 211 212 for (;m && len; m = m->m_next) { 213 if (m->m_len == 0) 214 continue; 215 w = mtod(m, u_int16_t *); 216 if (mlen == -1) { 217 /* 218 * The first byte of this mbuf is the continuation 219 * of a word spanning between this mbuf and the 220 * last mbuf. 221 * 222 * s_util.c[0] is already saved when scanning previous 223 * mbuf. 224 */ 225 s_util.c[1] = *(char *)w; 226 sum += s_util.s; 227 w = (u_int16_t *)((char *)w + 1); 228 mlen = m->m_len - 1; 229 len--; 230 } else 231 mlen = m->m_len; 232 if (len < mlen) 233 mlen = len; 234 len -= mlen; 235 /* 236 * Force to even boundary. 237 */ 238 if ((1 & (long) w) && (mlen > 0)) { 239 REDUCE; 240 sum <<= 8; 241 s_util.c[0] = *(u_char *)w; 242 w = (u_int16_t *)((char *)w + 1); 243 mlen--; 244 byte_swapped = 1; 245 } 246 /* 247 * Unroll the loop to make overhead from 248 * branches &c small. 249 */ 250 while ((mlen -= 32) >= 0) { 251 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 252 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 253 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 254 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 255 w += 16; 256 } 257 mlen += 32; 258 while ((mlen -= 8) >= 0) { 259 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 260 w += 4; 261 } 262 mlen += 8; 263 if (mlen == 0 && byte_swapped == 0) 264 continue; 265 REDUCE; 266 while ((mlen -= 2) >= 0) { 267 sum += *w++; 268 } 269 if (byte_swapped) { 270 REDUCE; 271 sum <<= 8; 272 byte_swapped = 0; 273 if (mlen == -1) { 274 s_util.c[1] = *(char *)w; 275 sum += s_util.s; 276 mlen = 0; 277 } else 278 mlen = -1; 279 } else if (mlen == -1) 280 s_util.c[0] = *(char *)w; 281 } 282 if (len) 283 panic("in6_cksum: out of data"); 284 if (mlen == -1) { 285 /* The last mbuf has odd # of bytes. Follow the 286 standard (the odd byte may be shifted left by 8 bits 287 or not as determined by endian-ness of the machine) */ 288 s_util.c[1] = 0; 289 sum += s_util.s; 290 } 291 REDUCE; 292 return (~sum & 0xffff); 293 } 294