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