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