The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet6/in6_cksum.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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$");
   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 static int
   84 _in6_cksum_pseudo(struct ip6_hdr *ip6, uint32_t len, uint8_t nxt, uint16_t csum)
   85 {
   86         int sum;
   87         uint16_t scope, *w;
   88         union {
   89                 u_int16_t phs[4];
   90                 struct {
   91                         u_int32_t       ph_len;
   92                         u_int8_t        ph_zero[3];
   93                         u_int8_t        ph_nxt;
   94                 } __packed ph;
   95         } uph;
   96 
   97         sum = csum;
   98 
   99         /*
  100          * First create IP6 pseudo header and calculate a summary.
  101          */
  102         uph.ph.ph_len = htonl(len);
  103         uph.ph.ph_zero[0] = uph.ph.ph_zero[1] = uph.ph.ph_zero[2] = 0;
  104         uph.ph.ph_nxt = nxt;
  105 
  106         /* Payload length and upper layer identifier. */
  107         sum += uph.phs[0];  sum += uph.phs[1];
  108         sum += uph.phs[2];  sum += uph.phs[3];
  109 
  110         /* IPv6 source address. */
  111         scope = in6_getscope(&ip6->ip6_src);
  112         w = (u_int16_t *)&ip6->ip6_src;
  113         sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
  114         sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
  115         if (scope != 0)
  116                 sum -= scope;
  117 
  118         /* IPv6 destination address. */
  119         scope = in6_getscope(&ip6->ip6_dst);
  120         w = (u_int16_t *)&ip6->ip6_dst;
  121         sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
  122         sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
  123         if (scope != 0)
  124                 sum -= scope;
  125 
  126         return (sum);
  127 }
  128 
  129 int
  130 in6_cksum_pseudo(struct ip6_hdr *ip6, uint32_t len, uint8_t nxt, uint16_t csum)
  131 {
  132         int sum;
  133         union {
  134                 u_int16_t s[2];
  135                 u_int32_t l;
  136         } l_util;
  137 
  138         sum = _in6_cksum_pseudo(ip6, len, nxt, csum);
  139         REDUCE;
  140         return (sum);
  141 }
  142 
  143 /*
  144  * m MUST contain a contiguous IP6 header.
  145  * off is an offset where TCP/UDP/ICMP6 header starts.
  146  * len is a total length of a transport segment.
  147  * (e.g. TCP header + TCP payload)
  148  */
  149 int
  150 in6_cksum(struct mbuf *m, u_int8_t nxt, u_int32_t off, u_int32_t len)
  151 {
  152         struct ip6_hdr *ip6;
  153         u_int16_t *w, scope;
  154         int byte_swapped, mlen;
  155         int sum;
  156         union {
  157                 u_int16_t phs[4];
  158                 struct {
  159                         u_int32_t       ph_len;
  160                         u_int8_t        ph_zero[3];
  161                         u_int8_t        ph_nxt;
  162                 } __packed ph;
  163         } uph;
  164         union {
  165                 u_int8_t        c[2];
  166                 u_int16_t       s;
  167         } s_util;
  168         union {
  169                 u_int16_t s[2];
  170                 u_int32_t l;
  171         } l_util;
  172 
  173         /* Sanity check. */
  174         KASSERT(m->m_pkthdr.len >= off + len, ("%s: mbuf len (%d) < off(%d)+"
  175             "len(%d)", __func__, m->m_pkthdr.len, off, len));
  176 
  177         /*
  178          * First create IP6 pseudo header and calculate a summary.
  179          */
  180         uph.ph.ph_len = htonl(len);
  181         uph.ph.ph_zero[0] = uph.ph.ph_zero[1] = uph.ph.ph_zero[2] = 0;
  182         uph.ph.ph_nxt = nxt;
  183 
  184         /* Payload length and upper layer identifier. */
  185         sum = uph.phs[0];  sum += uph.phs[1];
  186         sum += uph.phs[2];  sum += uph.phs[3];
  187 
  188         ip6 = mtod(m, struct ip6_hdr *);
  189 
  190         /* IPv6 source address. */
  191         scope = in6_getscope(&ip6->ip6_src);
  192         w = (u_int16_t *)&ip6->ip6_src;
  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         if (scope != 0)
  196                 sum -= scope;
  197 
  198         /* IPv6 destination address. */
  199         scope = in6_getscope(&ip6->ip6_dst);
  200         w = (u_int16_t *)&ip6->ip6_dst;
  201         sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
  202         sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
  203         if (scope != 0)
  204                 sum -= scope;
  205 
  206         /*
  207          * Secondly calculate a summary of the first mbuf excluding offset.
  208          */
  209         while (off > 0) {
  210                 if (m->m_len <= off)
  211                         off -= m->m_len;
  212                 else
  213                         break;
  214                 m = m->m_next;
  215         }
  216         w = (u_int16_t *)(mtod(m, u_char *) + off);
  217         mlen = m->m_len - off;
  218         if (len < mlen)
  219                 mlen = len;
  220         len -= mlen;
  221         /*
  222          * Force to even boundary.
  223          */
  224         if ((1 & (long)w) && (mlen > 0)) {
  225                 REDUCE;
  226                 sum <<= 8;
  227                 s_util.c[0] = *(u_char *)w;
  228                 w = (u_int16_t *)((char *)w + 1);
  229                 mlen--;
  230                 byte_swapped = 1;
  231         } else
  232                 byte_swapped = 0;
  233         
  234         /*
  235          * Unroll the loop to make overhead from
  236          * branches &c small.
  237          */
  238         while ((mlen -= 32) >= 0) {
  239                 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
  240                 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
  241                 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
  242                 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
  243                 w += 16;
  244         }
  245         mlen += 32;
  246         while ((mlen -= 8) >= 0) {
  247                 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
  248                 w += 4;
  249         }
  250         mlen += 8;
  251         if (mlen == 0 && byte_swapped == 0)
  252                 goto next;
  253         REDUCE;
  254         while ((mlen -= 2) >= 0) {
  255                 sum += *w++;
  256         }
  257         if (byte_swapped) {
  258                 REDUCE;
  259                 sum <<= 8;
  260                 byte_swapped = 0;
  261                 if (mlen == -1) {
  262                         s_util.c[1] = *(char *)w;
  263                         sum += s_util.s;
  264                         mlen = 0;
  265                 } else
  266                         mlen = -1;
  267         } else if (mlen == -1)
  268                 s_util.c[0] = *(char *)w;
  269  next:
  270         m = m->m_next;
  271 
  272         /*
  273          * Lastly calculate a summary of the rest of mbufs.
  274          */
  275 
  276         for (;m && len; m = m->m_next) {
  277                 if (m->m_len == 0)
  278                         continue;
  279                 w = mtod(m, u_int16_t *);
  280                 if (mlen == -1) {
  281                         /*
  282                          * The first byte of this mbuf is the continuation
  283                          * of a word spanning between this mbuf and the
  284                          * last mbuf.
  285                          *
  286                          * s_util.c[0] is already saved when scanning previous
  287                          * mbuf.
  288                          */
  289                         s_util.c[1] = *(char *)w;
  290                         sum += s_util.s;
  291                         w = (u_int16_t *)((char *)w + 1);
  292                         mlen = m->m_len - 1;
  293                         len--;
  294                 } else
  295                         mlen = m->m_len;
  296                 if (len < mlen)
  297                         mlen = len;
  298                 len -= mlen;
  299                 /*
  300                  * Force to even boundary.
  301                  */
  302                 if ((1 & (long) w) && (mlen > 0)) {
  303                         REDUCE;
  304                         sum <<= 8;
  305                         s_util.c[0] = *(u_char *)w;
  306                         w = (u_int16_t *)((char *)w + 1);
  307                         mlen--;
  308                         byte_swapped = 1;
  309                 }
  310                 /*
  311                  * Unroll the loop to make overhead from
  312                  * branches &c small.
  313                  */
  314                 while ((mlen -= 32) >= 0) {
  315                         sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
  316                         sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
  317                         sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
  318                         sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
  319                         w += 16;
  320                 }
  321                 mlen += 32;
  322                 while ((mlen -= 8) >= 0) {
  323                         sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
  324                         w += 4;
  325                 }
  326                 mlen += 8;
  327                 if (mlen == 0 && byte_swapped == 0)
  328                         continue;
  329                 REDUCE;
  330                 while ((mlen -= 2) >= 0) {
  331                         sum += *w++;
  332                 }
  333                 if (byte_swapped) {
  334                         REDUCE;
  335                         sum <<= 8;
  336                         byte_swapped = 0;
  337                         if (mlen == -1) {
  338                                 s_util.c[1] = *(char *)w;
  339                                 sum += s_util.s;
  340                                 mlen = 0;
  341                         } else
  342                                 mlen = -1;
  343                 } else if (mlen == -1)
  344                         s_util.c[0] = *(char *)w;
  345         }
  346         if (len)
  347                 panic("in6_cksum: out of data");
  348         if (mlen == -1) {
  349                 /* The last mbuf has odd # of bytes. Follow the
  350                    standard (the odd byte may be shifted left by 8 bits
  351                    or not as determined by endian-ness of the machine) */
  352                 s_util.c[1] = 0;
  353                 sum += s_util.s;
  354         }
  355         REDUCE;
  356         return (~sum & 0xffff);
  357 }

Cache object: def86a89762d298cf50b459ef63d5540


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.