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: releng/10.1/sys/netinet6/in6_cksum.c 272991 2014-10-12 17:07:15Z tuexen $");
   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  * cov is the number of bytes to be taken into account for the checksum
  149  */
  150 int
  151 in6_cksum_partial(struct mbuf *m, u_int8_t nxt, u_int32_t off,
  152     u_int32_t len, u_int32_t cov)
  153 {
  154         struct ip6_hdr *ip6;
  155         u_int16_t *w, scope;
  156         int byte_swapped, mlen;
  157         int sum;
  158         union {
  159                 u_int16_t phs[4];
  160                 struct {
  161                         u_int32_t       ph_len;
  162                         u_int8_t        ph_zero[3];
  163                         u_int8_t        ph_nxt;
  164                 } __packed ph;
  165         } uph;
  166         union {
  167                 u_int8_t        c[2];
  168                 u_int16_t       s;
  169         } s_util;
  170         union {
  171                 u_int16_t s[2];
  172                 u_int32_t l;
  173         } l_util;
  174 
  175         /* Sanity check. */
  176         KASSERT(m->m_pkthdr.len >= off + len, ("%s: mbuf len (%d) < off(%d)+"
  177             "len(%d)", __func__, m->m_pkthdr.len, off, len));
  178 
  179         /*
  180          * First create IP6 pseudo header and calculate a summary.
  181          */
  182         uph.ph.ph_len = htonl(len);
  183         uph.ph.ph_zero[0] = uph.ph.ph_zero[1] = uph.ph.ph_zero[2] = 0;
  184         uph.ph.ph_nxt = nxt;
  185 
  186         /* Payload length and upper layer identifier. */
  187         sum = uph.phs[0];  sum += uph.phs[1];
  188         sum += uph.phs[2];  sum += uph.phs[3];
  189 
  190         ip6 = mtod(m, struct ip6_hdr *);
  191 
  192         /* IPv6 source address. */
  193         scope = in6_getscope(&ip6->ip6_src);
  194         w = (u_int16_t *)&ip6->ip6_src;
  195         sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
  196         sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
  197         if (scope != 0)
  198                 sum -= scope;
  199 
  200         /* IPv6 destination address. */
  201         scope = in6_getscope(&ip6->ip6_dst);
  202         w = (u_int16_t *)&ip6->ip6_dst;
  203         sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
  204         sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
  205         if (scope != 0)
  206                 sum -= scope;
  207 
  208         /*
  209          * Secondly calculate a summary of the first mbuf excluding offset.
  210          */
  211         while (off > 0) {
  212                 if (m->m_len <= off)
  213                         off -= m->m_len;
  214                 else
  215                         break;
  216                 m = m->m_next;
  217         }
  218         w = (u_int16_t *)(mtod(m, u_char *) + off);
  219         mlen = m->m_len - off;
  220         if (cov < mlen)
  221                 mlen = cov;
  222         cov -= mlen;
  223         /*
  224          * Force to even boundary.
  225          */
  226         if ((1 & (long)w) && (mlen > 0)) {
  227                 REDUCE;
  228                 sum <<= 8;
  229                 s_util.c[0] = *(u_char *)w;
  230                 w = (u_int16_t *)((char *)w + 1);
  231                 mlen--;
  232                 byte_swapped = 1;
  233         } else
  234                 byte_swapped = 0;
  235         
  236         /*
  237          * Unroll the loop to make overhead from
  238          * branches &c small.
  239          */
  240         while ((mlen -= 32) >= 0) {
  241                 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
  242                 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
  243                 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
  244                 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
  245                 w += 16;
  246         }
  247         mlen += 32;
  248         while ((mlen -= 8) >= 0) {
  249                 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
  250                 w += 4;
  251         }
  252         mlen += 8;
  253         if (mlen == 0 && byte_swapped == 0)
  254                 goto next;
  255         REDUCE;
  256         while ((mlen -= 2) >= 0) {
  257                 sum += *w++;
  258         }
  259         if (byte_swapped) {
  260                 REDUCE;
  261                 sum <<= 8;
  262                 byte_swapped = 0;
  263                 if (mlen == -1) {
  264                         s_util.c[1] = *(char *)w;
  265                         sum += s_util.s;
  266                         mlen = 0;
  267                 } else
  268                         mlen = -1;
  269         } else if (mlen == -1)
  270                 s_util.c[0] = *(char *)w;
  271  next:
  272         m = m->m_next;
  273 
  274         /*
  275          * Lastly calculate a summary of the rest of mbufs.
  276          */
  277 
  278         for (;m && cov; m = m->m_next) {
  279                 if (m->m_len == 0)
  280                         continue;
  281                 w = mtod(m, u_int16_t *);
  282                 if (mlen == -1) {
  283                         /*
  284                          * The first byte of this mbuf is the continuation
  285                          * of a word spanning between this mbuf and the
  286                          * last mbuf.
  287                          *
  288                          * s_util.c[0] is already saved when scanning previous
  289                          * mbuf.
  290                          */
  291                         s_util.c[1] = *(char *)w;
  292                         sum += s_util.s;
  293                         w = (u_int16_t *)((char *)w + 1);
  294                         mlen = m->m_len - 1;
  295                         cov--;
  296                 } else
  297                         mlen = m->m_len;
  298                 if (cov < mlen)
  299                         mlen = cov;
  300                 cov -= mlen;
  301                 /*
  302                  * Force to even boundary.
  303                  */
  304                 if ((1 & (long) w) && (mlen > 0)) {
  305                         REDUCE;
  306                         sum <<= 8;
  307                         s_util.c[0] = *(u_char *)w;
  308                         w = (u_int16_t *)((char *)w + 1);
  309                         mlen--;
  310                         byte_swapped = 1;
  311                 }
  312                 /*
  313                  * Unroll the loop to make overhead from
  314                  * branches &c small.
  315                  */
  316                 while ((mlen -= 32) >= 0) {
  317                         sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
  318                         sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
  319                         sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
  320                         sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
  321                         w += 16;
  322                 }
  323                 mlen += 32;
  324                 while ((mlen -= 8) >= 0) {
  325                         sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
  326                         w += 4;
  327                 }
  328                 mlen += 8;
  329                 if (mlen == 0 && byte_swapped == 0)
  330                         continue;
  331                 REDUCE;
  332                 while ((mlen -= 2) >= 0) {
  333                         sum += *w++;
  334                 }
  335                 if (byte_swapped) {
  336                         REDUCE;
  337                         sum <<= 8;
  338                         byte_swapped = 0;
  339                         if (mlen == -1) {
  340                                 s_util.c[1] = *(char *)w;
  341                                 sum += s_util.s;
  342                                 mlen = 0;
  343                         } else
  344                                 mlen = -1;
  345                 } else if (mlen == -1)
  346                         s_util.c[0] = *(char *)w;
  347         }
  348         if (cov)
  349                 panic("in6_cksum: out of data");
  350         if (mlen == -1) {
  351                 /* The last mbuf has odd # of bytes. Follow the
  352                    standard (the odd byte may be shifted left by 8 bits
  353                    or not as determined by endian-ness of the machine) */
  354                 s_util.c[1] = 0;
  355                 sum += s_util.s;
  356         }
  357         REDUCE;
  358         return (~sum & 0xffff);
  359 }
  360 
  361 int
  362 in6_cksum(struct mbuf *m, u_int8_t nxt, u_int32_t off, u_int32_t len)
  363 {
  364         return (in6_cksum_partial(m, nxt, off, len, len));
  365 }

Cache object: 1d1e5e7ed65dfea3af0d478831e766b6


[ 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.