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