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