Home | History | Annotate | Line # | Download | only in netinet6
in6_cksum.c revision 1.26
      1 /*	$NetBSD: in6_cksum.c,v 1.26 2008/03/10 22:29:13 yamt Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2008 Joerg Sonnenberger <joerg (at) NetBSD.org>.
      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  *
     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
     15  *    the documentation and/or other materials provided with the
     16  *    distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
     22  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
     24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     28  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: in6_cksum.c,v 1.26 2008/03/10 22:29:13 yamt Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/mbuf.h>
     37 #include <netinet/in.h>
     38 #include <netinet/ip6.h>
     39 
     40 /*
     41  * Checksum of the IPv6 pseudo header.
     42  *
     43  * off is supposed to be the skipped IPv6 header, len is the payload size.
     44  */
     45 
     46 int
     47 in6_cksum(struct mbuf *m, u_int8_t nxt, uint32_t off, uint32_t len)
     48 {
     49 	union {
     50 		uint16_t words[16];
     51 		struct {
     52 			struct in6_addr ip6_src;
     53 			struct in6_addr ip6_dst;
     54 		} addrs;
     55 	} u;
     56 	const struct in6_addr *in6_src;
     57 	const struct in6_addr *in6_dst;
     58 	const struct ip6_hdr *ip6;
     59 	uint32_t sum;
     60 	const uint16_t *w;
     61 	const char *cp;
     62 
     63 	if (__predict_false(off < sizeof(struct ip6_hdr)))
     64 		panic("in6_cksum: offset too short for IPv6 header");
     65 	if (__predict_false(m->m_len < sizeof(struct ip6_hdr)))
     66 		panic("in6_cksum: mbuf too short for IPv6 header");
     67 
     68 	if (nxt == 0)
     69 		return cpu_in_cksum(m, len, off, 0);
     70 
     71 	/*
     72 	 * Compute the equivalent of:
     73 	 * struct ip6_hdr_pseudo ip6;
     74 	 *
     75 	 * bzero(sizeof(*ip6));
     76 	 * ip6.ip6ph_nxt = nxt;
     77 	 * ip6.ip6ph_len = htonl(len);
     78 	 * ipv6.ip6ph_src = mtod(m, struct ip6_hdr *)->ip6_src;
     79 	 * in6_clearscope(&ip6->ip6ph_src);
     80 	 * ipv6.ip6ph_dst = mtod(m, struct ip6_hdr *)->ip6_dst;
     81 	 * in6_clearscope(&ip6->ip6ph_dst);
     82 	 * sum = one_add(&ip6);
     83 	 */
     84 
     85 #if BYTE_ORDER == LITTLE_ENDIAN
     86 	sum = ((len & 0xffff) + ((len >> 16) & 0xffff) + nxt) << 8;
     87 #else
     88 	sum = (len & 0xffff) + ((len >> 16) & 0xffff) + nxt;
     89 #endif
     90 	cp = mtod(m, const char *);
     91 	w = (const uint16_t *)(cp + offsetof(struct ip6_hdr, ip6_src));
     92 	ip6 = (const void *)cp;
     93 	if (__predict_true((uintptr_t)w % 2 == 0)) {
     94 		in6_src = &ip6->ip6_src;
     95 		in6_dst = &ip6->ip6_dst;
     96 	} else {
     97 		memcpy(&u, &ip6->ip6_src, 32);
     98 		w = u.words;
     99 		in6_src = &u.addrs.ip6_src;
    100 		in6_dst = &u.addrs.ip6_dst;
    101 	}
    102 
    103 	sum += w[0];
    104 	if (!IN6_IS_SCOPE_LINKLOCAL(in6_src) &&
    105 	    !IN6_IS_ADDR_MC_INTFACELOCAL(in6_src))
    106 		sum += w[1];
    107 	sum += w[2];
    108 	sum += w[3];
    109 	sum += w[4];
    110 	sum += w[5];
    111 	sum += w[6];
    112 	sum += w[7];
    113 	w += 8;
    114 	sum += w[0];
    115 	if (!IN6_IS_SCOPE_LINKLOCAL(in6_dst) &&
    116 	    !IN6_IS_ADDR_MC_INTFACELOCAL(in6_dst))
    117 		sum += w[1];
    118 	sum += w[2];
    119 	sum += w[3];
    120 	sum += w[4];
    121 	sum += w[5];
    122 	sum += w[6];
    123 	sum += w[7];
    124 
    125 	return cpu_in_cksum(m, len, off, sum);
    126 }
    127