ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

inet_chksum.c
Go to the documentation of this file.
00001 
00007 /*
00008  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00009  * All rights reserved.
00010  *
00011  * Redistribution and use in source and binary forms, with or without modification,
00012  * are permitted provided that the following conditions are met:
00013  *
00014  * 1. Redistributions of source code must retain the above copyright notice,
00015  *    this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright notice,
00017  *    this list of conditions and the following disclaimer in the documentation
00018  *    and/or other materials provided with the distribution.
00019  * 3. The name of the author may not be used to endorse or promote products
00020  *    derived from this software without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00023  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00024  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00025  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00026  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00027  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00030  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00031  * OF SUCH DAMAGE.
00032  *
00033  * This file is part of the lwIP TCP/IP stack.
00034  *
00035  * Author: Adam Dunkels <adam@sics.se>
00036  *
00037  */
00038 
00039 #include "lwip/opt.h"
00040 
00041 #include "lwip/inet_chksum.h"
00042 #include "lwip/def.h"
00043 
00044 #include <stddef.h>
00045 #include <string.h>
00046 
00047 /* These are some reference implementations of the checksum algorithm, with the
00048  * aim of being simple, correct and fully portable. Checksumming is the
00049  * first thing you would want to optimize for your platform. If you create
00050  * your own version, link it in and in your cc.h put:
00051  * 
00052  * #define LWIP_CHKSUM <your_checksum_routine> 
00053  *
00054  * Or you can select from the implementations below by defining
00055  * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
00056  */
00057 
00058 #ifndef LWIP_CHKSUM
00059 # define LWIP_CHKSUM lwip_standard_chksum
00060 # ifndef LWIP_CHKSUM_ALGORITHM
00061 #  define LWIP_CHKSUM_ALGORITHM 2
00062 # endif
00063 #endif
00064 /* If none set: */
00065 #ifndef LWIP_CHKSUM_ALGORITHM
00066 # define LWIP_CHKSUM_ALGORITHM 0
00067 #endif
00068 
00069 #if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */
00070 
00080 static u16_t
00081 lwip_standard_chksum(void *dataptr, u16_t len)
00082 {
00083   u32_t acc;
00084   u16_t src;
00085   u8_t *octetptr;
00086 
00087   acc = 0;
00088   /* dataptr may be at odd or even addresses */
00089   octetptr = (u8_t*)dataptr;
00090   while (len > 1) {
00091     /* declare first octet as most significant
00092        thus assume network order, ignoring host order */
00093     src = (*octetptr) << 8;
00094     octetptr++;
00095     /* declare second octet as least significant */
00096     src |= (*octetptr);
00097     octetptr++;
00098     acc += src;
00099     len -= 2;
00100   }
00101   if (len > 0) {
00102     /* accumulate remaining octet */
00103     src = (*octetptr) << 8;
00104     acc += src;
00105   }
00106   /* add deferred carry bits */
00107   acc = (acc >> 16) + (acc & 0x0000ffffUL);
00108   if ((acc & 0xffff0000UL) != 0) {
00109     acc = (acc >> 16) + (acc & 0x0000ffffUL);
00110   }
00111   /* This maybe a little confusing: reorder sum using htons()
00112      instead of ntohs() since it has a little less call overhead.
00113      The caller must invert bits for Internet sum ! */
00114   return htons((u16_t)acc);
00115 }
00116 #endif
00117 
00118 #if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */
00119 /*
00120  * Curt McDowell
00121  * Broadcom Corp.
00122  * csm@broadcom.com
00123  *
00124  * IP checksum two bytes at a time with support for
00125  * unaligned buffer.
00126  * Works for len up to and including 0x20000.
00127  * by Curt McDowell, Broadcom Corp. 12/08/2005
00128  *
00129  * @param dataptr points to start of data to be summed at any boundary
00130  * @param len length of data to be summed
00131  * @return host order (!) lwip checksum (non-inverted Internet sum) 
00132  */
00133 
00134 static u16_t
00135 lwip_standard_chksum(void *dataptr, int len)
00136 {
00137   u8_t *pb = (u8_t *)dataptr;
00138   u16_t *ps, t = 0;
00139   u32_t sum = 0;
00140   int odd = ((mem_ptr_t)pb & 1);
00141 
00142   /* Get aligned to u16_t */
00143   if (odd && len > 0) {
00144     ((u8_t *)&t)[1] = *pb++;
00145     len--;
00146   }
00147 
00148   /* Add the bulk of the data */
00149   ps = (u16_t *)(void *)pb;
00150   while (len > 1) {
00151     sum += *ps++;
00152     len -= 2;
00153   }
00154 
00155   /* Consume left-over byte, if any */
00156   if (len > 0) {
00157     ((u8_t *)&t)[0] = *(u8_t *)ps;
00158   }
00159 
00160   /* Add end bytes */
00161   sum += t;
00162 
00163   /* Fold 32-bit sum to 16 bits
00164      calling this twice is propably faster than if statements... */
00165   sum = FOLD_U32T(sum);
00166   sum = FOLD_U32T(sum);
00167 
00168   /* Swap if alignment was odd */
00169   if (odd) {
00170     sum = SWAP_BYTES_IN_WORD(sum);
00171   }
00172 
00173   return (u16_t)sum;
00174 }
00175 #endif
00176 
00177 #if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */
00178 
00190 static u16_t
00191 lwip_standard_chksum(void *dataptr, int len)
00192 {
00193   u8_t *pb = (u8_t *)dataptr;
00194   u16_t *ps, t = 0;
00195   u32_t *pl;
00196   u32_t sum = 0, tmp;
00197   /* starts at odd byte address? */
00198   int odd = ((mem_ptr_t)pb & 1);
00199 
00200   if (odd && len > 0) {
00201     ((u8_t *)&t)[1] = *pb++;
00202     len--;
00203   }
00204 
00205   ps = (u16_t *)pb;
00206 
00207   if (((mem_ptr_t)ps & 3) && len > 1) {
00208     sum += *ps++;
00209     len -= 2;
00210   }
00211 
00212   pl = (u32_t *)ps;
00213 
00214   while (len > 7)  {
00215     tmp = sum + *pl++;          /* ping */
00216     if (tmp < sum) {
00217       tmp++;                    /* add back carry */
00218     }
00219 
00220     sum = tmp + *pl++;          /* pong */
00221     if (sum < tmp) {
00222       sum++;                    /* add back carry */
00223     }
00224 
00225     len -= 8;
00226   }
00227 
00228   /* make room in upper bits */
00229   sum = FOLD_U32T(sum);
00230 
00231   ps = (u16_t *)pl;
00232 
00233   /* 16-bit aligned word remaining? */
00234   while (len > 1) {
00235     sum += *ps++;
00236     len -= 2;
00237   }
00238 
00239   /* dangling tail byte remaining? */
00240   if (len > 0) {                /* include odd byte */
00241     ((u8_t *)&t)[0] = *(u8_t *)ps;
00242   }
00243 
00244   sum += t;                     /* add end bytes */
00245 
00246   /* Fold 32-bit sum to 16 bits
00247      calling this twice is propably faster than if statements... */
00248   sum = FOLD_U32T(sum);
00249   sum = FOLD_U32T(sum);
00250 
00251   if (odd) {
00252     sum = SWAP_BYTES_IN_WORD(sum);
00253   }
00254 
00255   return (u16_t)sum;
00256 }
00257 #endif
00258 
00259 /* inet_chksum_pseudo:
00260  *
00261  * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
00262  * IP addresses are expected to be in network byte order.
00263  *
00264  * @param p chain of pbufs over that a checksum should be calculated (ip data part)
00265  * @param src source ip address (used for checksum of pseudo header)
00266  * @param dst destination ip address (used for checksum of pseudo header)
00267  * @param proto ip protocol (used for checksum of pseudo header)
00268  * @param proto_len length of the ip data part (used for checksum of pseudo header)
00269  * @return checksum (as u16_t) to be saved directly in the protocol header
00270  */
00271 u16_t
00272 inet_chksum_pseudo(struct pbuf *p,
00273        ip_addr_t *src, ip_addr_t *dest,
00274        u8_t proto, u16_t proto_len)
00275 {
00276   u32_t acc;
00277   u32_t addr;
00278   struct pbuf *q;
00279   u8_t swapped;
00280 
00281   acc = 0;
00282   swapped = 0;
00283   /* iterate through all pbuf in chain */
00284   for(q = p; q != NULL; q = q->next) {
00285     LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
00286       (void *)q, (void *)q->next));
00287     acc += LWIP_CHKSUM(q->payload, q->len);
00288     /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
00289     /* just executing this next line is probably faster that the if statement needed
00290        to check whether we really need to execute it, and does no harm */
00291     acc = FOLD_U32T(acc);
00292     if (q->len % 2 != 0) {
00293       swapped = 1 - swapped;
00294       acc = SWAP_BYTES_IN_WORD(acc);
00295     }
00296     /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
00297   }
00298 
00299   if (swapped) {
00300     acc = SWAP_BYTES_IN_WORD(acc);
00301   }
00302   addr = ip4_addr_get_u32(src);
00303   acc += (addr & 0xffffUL);
00304   acc += ((addr >> 16) & 0xffffUL);
00305   addr = ip4_addr_get_u32(dest);
00306   acc += (addr & 0xffffUL);
00307   acc += ((addr >> 16) & 0xffffUL);
00308   acc += (u32_t)htons((u16_t)proto);
00309   acc += (u32_t)htons(proto_len);
00310 
00311   /* Fold 32-bit sum to 16 bits
00312      calling this twice is propably faster than if statements... */
00313   acc = FOLD_U32T(acc);
00314   acc = FOLD_U32T(acc);
00315   LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
00316   return (u16_t)~(acc & 0xffffUL);
00317 }
00318 
00319 /* inet_chksum_pseudo:
00320  *
00321  * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
00322  * IP addresses are expected to be in network byte order.
00323  *
00324  * @param p chain of pbufs over that a checksum should be calculated (ip data part)
00325  * @param src source ip address (used for checksum of pseudo header)
00326  * @param dst destination ip address (used for checksum of pseudo header)
00327  * @param proto ip protocol (used for checksum of pseudo header)
00328  * @param proto_len length of the ip data part (used for checksum of pseudo header)
00329  * @return checksum (as u16_t) to be saved directly in the protocol header
00330  */
00331 u16_t
00332 inet_chksum_pseudo_partial(struct pbuf *p,
00333        ip_addr_t *src, ip_addr_t *dest,
00334        u8_t proto, u16_t proto_len, u16_t chksum_len)
00335 {
00336   u32_t acc;
00337   u32_t addr;
00338   struct pbuf *q;
00339   u8_t swapped;
00340   u16_t chklen;
00341 
00342   acc = 0;
00343   swapped = 0;
00344   /* iterate through all pbuf in chain */
00345   for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
00346     LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
00347       (void *)q, (void *)q->next));
00348     chklen = q->len;
00349     if (chklen > chksum_len) {
00350       chklen = chksum_len;
00351     }
00352     acc += LWIP_CHKSUM(q->payload, chklen);
00353     chksum_len -= chklen;
00354     LWIP_ASSERT("delete me", chksum_len < 0x7fff);
00355     /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
00356     /* fold the upper bit down */
00357     acc = FOLD_U32T(acc);
00358     if (q->len % 2 != 0) {
00359       swapped = 1 - swapped;
00360       acc = SWAP_BYTES_IN_WORD(acc);
00361     }
00362     /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
00363   }
00364 
00365   if (swapped) {
00366     acc = SWAP_BYTES_IN_WORD(acc);
00367   }
00368   addr = ip4_addr_get_u32(src);
00369   acc += (addr & 0xffffUL);
00370   acc += ((addr >> 16) & 0xffffUL);
00371   addr = ip4_addr_get_u32(dest);
00372   acc += (addr & 0xffffUL);
00373   acc += ((addr >> 16) & 0xffffUL);
00374   acc += (u32_t)htons((u16_t)proto);
00375   acc += (u32_t)htons(proto_len);
00376 
00377   /* Fold 32-bit sum to 16 bits
00378      calling this twice is propably faster than if statements... */
00379   acc = FOLD_U32T(acc);
00380   acc = FOLD_U32T(acc);
00381   LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
00382   return (u16_t)~(acc & 0xffffUL);
00383 }
00384 
00385 /* inet_chksum:
00386  *
00387  * Calculates the Internet checksum over a portion of memory. Used primarily for IP
00388  * and ICMP.
00389  *
00390  * @param dataptr start of the buffer to calculate the checksum (no alignment needed)
00391  * @param len length of the buffer to calculate the checksum
00392  * @return checksum (as u16_t) to be saved directly in the protocol header
00393  */
00394 
00395 u16_t
00396 inet_chksum(void *dataptr, u16_t len)
00397 {
00398   return ~LWIP_CHKSUM(dataptr, len);
00399 }
00400 
00408 u16_t
00409 inet_chksum_pbuf(struct pbuf *p)
00410 {
00411   u32_t acc;
00412   struct pbuf *q;
00413   u8_t swapped;
00414 
00415   acc = 0;
00416   swapped = 0;
00417   for(q = p; q != NULL; q = q->next) {
00418     acc += LWIP_CHKSUM(q->payload, q->len);
00419     acc = FOLD_U32T(acc);
00420     if (q->len % 2 != 0) {
00421       swapped = 1 - swapped;
00422       acc = SWAP_BYTES_IN_WORD(acc);
00423     }
00424   }
00425 
00426   if (swapped) {
00427     acc = SWAP_BYTES_IN_WORD(acc);
00428   }
00429   return (u16_t)~(acc & 0xffffUL);
00430 }
00431 
00432 /* These are some implementations for LWIP_CHKSUM_COPY, which copies data
00433  * like MEMCPY but generates a checksum at the same time. Since this is a
00434  * performance-sensitive function, you might want to create your own version
00435  * in assembly targeted at your hardware by defining it in lwipopts.h:
00436  *   #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len)
00437  */
00438 
00439 #if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */
00440 
00444 u16_t
00445 lwip_chksum_copy(void *dst, const void *src, u16_t len)
00446 {
00447   MEMCPY(dst, src, len);
00448   return LWIP_CHKSUM(dst, len);
00449 }
00450 #endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */

Generated on Sun May 27 2012 04:36:01 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.