Port of LwIP performed by Ralf in 2010. Not recommended for use with recent mbed libraries, but good demos of raw LwIP possible

Dependents:   LwIP_raw_API_serverExample tiny-dtls

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers inet_chksum.c Source File

inet_chksum.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Incluse internet checksum functions.
00004  *
00005  */
00006 
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/inet.h"
00043 
00044 #include <stddef.h>
00045 
00046 /* These are some reference implementations of the checksum algorithm, with the
00047  * aim of being simple, correct and fully portable. Checksumming is the
00048  * first thing you would want to optimize for your platform. If you create
00049  * your own version, link it in and in your cc.h put:
00050  * 
00051  * #define LWIP_CHKSUM <your_checksum_routine> 
00052  *
00053  * Or you can select from the implementations below by defining
00054  * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
00055  */
00056 
00057 #ifndef LWIP_CHKSUM
00058 # define LWIP_CHKSUM lwip_standard_chksum
00059 # ifndef LWIP_CHKSUM_ALGORITHM
00060 #  define LWIP_CHKSUM_ALGORITHM 1
00061 # endif
00062 #endif
00063 /* If none set: */
00064 #ifndef LWIP_CHKSUM_ALGORITHM
00065 # define LWIP_CHKSUM_ALGORITHM 0
00066 #endif
00067 
00068 /** Like the name says... */
00069 #if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)
00070 /* little endian and PLATFORM_BYTESWAP defined */
00071 #define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w)
00072 #else
00073 /* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */
00074 #define SWAP_BYTES_IN_WORD(w) ((w & 0xff) << 8) | ((w & 0xff00) >> 8)
00075 #endif
00076 
00077 /** Split an u32_t in two u16_ts and add them up */
00078 #define FOLD_U32T(u)          ((u >> 16) + (u & 0x0000ffffUL))
00079 
00080 #if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */
00081 /**
00082  * lwip checksum
00083  *
00084  * @param dataptr points to start of data to be summed at any boundary
00085  * @param len length of data to be summed
00086  * @return host order (!) lwip checksum (non-inverted Internet sum) 
00087  *
00088  * @note accumulator size limits summable length to 64k
00089  * @note host endianess is irrelevant (p3 RFC1071)
00090  */
00091 static u16_t
00092 lwip_standard_chksum(void *dataptr, u16_t len)
00093 {
00094   u32_t acc;
00095   u16_t src;
00096   u8_t *octetptr;
00097 
00098   acc = 0;
00099   /* dataptr may be at odd or even addresses */
00100   octetptr = (u8_t*)dataptr;
00101   while (len > 1) {
00102     /* declare first octet as most significant
00103        thus assume network order, ignoring host order */
00104     src = (*octetptr) << 8;
00105     octetptr++;
00106     /* declare second octet as least significant */
00107     src |= (*octetptr);
00108     octetptr++;
00109     acc += src;
00110     len -= 2;
00111   }
00112   if (len > 0) {
00113     /* accumulate remaining octet */
00114     src = (*octetptr) << 8;
00115     acc += src;
00116   }
00117   /* add deferred carry bits */
00118   acc = (acc >> 16) + (acc & 0x0000ffffUL);
00119   if ((acc & 0xffff0000UL) != 0) {
00120     acc = (acc >> 16) + (acc & 0x0000ffffUL);
00121   }
00122   /* This maybe a little confusing: reorder sum using htons()
00123      instead of ntohs() since it has a little less call overhead.
00124      The caller must invert bits for Internet sum ! */
00125   return htons((u16_t)acc);
00126 }
00127 #endif
00128 
00129 #if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */
00130 /*
00131  * Curt McDowell
00132  * Broadcom Corp.
00133  * csm@broadcom.com
00134  *
00135  * IP checksum two bytes at a time with support for
00136  * unaligned buffer.
00137  * Works for len up to and including 0x20000.
00138  * by Curt McDowell, Broadcom Corp. 12/08/2005
00139  *
00140  * @param dataptr points to start of data to be summed at any boundary
00141  * @param len length of data to be summed
00142  * @return host order (!) lwip checksum (non-inverted Internet sum) 
00143  */
00144 
00145 static u16_t
00146 lwip_standard_chksum(void *dataptr, int len)
00147 {
00148   u8_t *pb = dataptr;
00149   u16_t *ps, t = 0;
00150   u32_t sum = 0;
00151   int odd = ((u32_t)pb & 1);
00152 
00153   /* Get aligned to u16_t */
00154   if (odd && len > 0) {
00155     ((u8_t *)&t)[1] = *pb++;
00156     len--;
00157   }
00158 
00159   /* Add the bulk of the data */
00160   ps = (u16_t *)pb;
00161   while (len > 1) {
00162     sum += *ps++;
00163     len -= 2;
00164   }
00165 
00166   /* Consume left-over byte, if any */
00167   if (len > 0) {
00168     ((u8_t *)&t)[0] = *(u8_t *)ps;;
00169   }
00170 
00171   /* Add end bytes */
00172   sum += t;
00173 
00174   /* Fold 32-bit sum to 16 bits
00175      calling this twice is propably faster than if statements... */
00176   sum = FOLD_U32T(sum);
00177   sum = FOLD_U32T(sum);
00178 
00179   /* Swap if alignment was odd */
00180   if (odd) {
00181     sum = SWAP_BYTES_IN_WORD(sum);
00182   }
00183 
00184   return sum;
00185 }
00186 #endif
00187 
00188 #if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */
00189 /**
00190  * An optimized checksum routine. Basically, it uses loop-unrolling on
00191  * the checksum loop, treating the head and tail bytes specially, whereas
00192  * the inner loop acts on 8 bytes at a time. 
00193  *
00194  * @arg start of buffer to be checksummed. May be an odd byte address.
00195  * @len number of bytes in the buffer to be checksummed.
00196  * @return host order (!) lwip checksum (non-inverted Internet sum) 
00197  * 
00198  * by Curt McDowell, Broadcom Corp. December 8th, 2005
00199  */
00200 
00201 static u16_t
00202 lwip_standard_chksum(void *dataptr, int len)
00203 {
00204   u8_t *pb = dataptr;
00205   u16_t *ps, t = 0;
00206   u32_t *pl;
00207   u32_t sum = 0, tmp;
00208   /* starts at odd byte address? */
00209   int odd = ((u32_t)pb & 1);
00210 
00211   if (odd && len > 0) {
00212     ((u8_t *)&t)[1] = *pb++;
00213     len--;
00214   }
00215 
00216   ps = (u16_t *)pb;
00217 
00218   if (((u32_t)ps & 3) && len > 1) {
00219     sum += *ps++;
00220     len -= 2;
00221   }
00222 
00223   pl = (u32_t *)ps;
00224 
00225   while (len > 7)  {
00226     tmp = sum + *pl++;          /* ping */
00227     if (tmp < sum) {
00228       tmp++;                    /* add back carry */
00229     }
00230 
00231     sum = tmp + *pl++;          /* pong */
00232     if (sum < tmp) {
00233       sum++;                    /* add back carry */
00234     }
00235 
00236     len -= 8;
00237   }
00238 
00239   /* make room in upper bits */
00240   sum = FOLD_U32T(sum);
00241 
00242   ps = (u16_t *)pl;
00243 
00244   /* 16-bit aligned word remaining? */
00245   while (len > 1) {
00246     sum += *ps++;
00247     len -= 2;
00248   }
00249 
00250   /* dangling tail byte remaining? */
00251   if (len > 0) {                /* include odd byte */
00252     ((u8_t *)&t)[0] = *(u8_t *)ps;
00253   }
00254 
00255   sum += t;                     /* add end bytes */
00256 
00257   /* Fold 32-bit sum to 16 bits
00258      calling this twice is propably faster than if statements... */
00259   sum = FOLD_U32T(sum);
00260   sum = FOLD_U32T(sum);
00261 
00262   if (odd) {
00263     sum = SWAP_BYTES_IN_WORD(sum);
00264   }
00265 
00266   return sum;
00267 }
00268 #endif
00269 
00270 /* inet_chksum_pseudo:
00271  *
00272  * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
00273  * IP addresses are expected to be in network byte order.
00274  *
00275  * @param p chain of pbufs over that a checksum should be calculated (ip data part)
00276  * @param src source ip address (used for checksum of pseudo header)
00277  * @param dst destination ip address (used for checksum of pseudo header)
00278  * @param proto ip protocol (used for checksum of pseudo header)
00279  * @param proto_len length of the ip data part (used for checksum of pseudo header)
00280  * @return checksum (as u16_t) to be saved directly in the protocol header
00281  */
00282 u16_t
00283 inet_chksum_pseudo(struct pbuf *p,
00284        struct ip_addr *src, struct ip_addr *dest,
00285        u8_t proto, u16_t proto_len)
00286 {
00287   u32_t acc;
00288   struct pbuf *q;
00289   u8_t swapped;
00290 
00291   acc = 0;
00292   swapped = 0;
00293   /* iterate through all pbuf in chain */
00294   for(q = p; q != NULL; q = q->next) {
00295     LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
00296       (void *)q, (void *)q->next));
00297     acc += LWIP_CHKSUM(q->payload, q->len);
00298     /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
00299     /* just executing this next line is probably faster that the if statement needed
00300        to check whether we really need to execute it, and does no harm */
00301     acc = FOLD_U32T(acc);
00302     if (q->len % 2 != 0) {
00303       swapped = 1 - swapped;
00304       acc = SWAP_BYTES_IN_WORD(acc);
00305     }
00306     /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
00307   }
00308 
00309   if (swapped) {
00310     acc = SWAP_BYTES_IN_WORD(acc);
00311   }
00312   acc += (src->addr & 0xffffUL);
00313   acc += ((src->addr >> 16) & 0xffffUL);
00314   acc += (dest->addr & 0xffffUL);
00315   acc += ((dest->addr >> 16) & 0xffffUL);
00316   acc += (u32_t)htons((u16_t)proto);
00317   acc += (u32_t)htons(proto_len);
00318 
00319   /* Fold 32-bit sum to 16 bits
00320      calling this twice is propably faster than if statements... */
00321   acc = FOLD_U32T(acc);
00322   acc = FOLD_U32T(acc);
00323   LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
00324   return (u16_t)~(acc & 0xffffUL);
00325 }
00326 
00327 /* inet_chksum_pseudo:
00328  *
00329  * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
00330  * IP addresses are expected to be in network byte order.
00331  *
00332  * @param p chain of pbufs over that a checksum should be calculated (ip data part)
00333  * @param src source ip address (used for checksum of pseudo header)
00334  * @param dst destination ip address (used for checksum of pseudo header)
00335  * @param proto ip protocol (used for checksum of pseudo header)
00336  * @param proto_len length of the ip data part (used for checksum of pseudo header)
00337  * @return checksum (as u16_t) to be saved directly in the protocol header
00338  */
00339 /* Currently only used by UDPLITE, although this could change in the future. */
00340 #if LWIP_UDPLITE
00341 u16_t
00342 inet_chksum_pseudo_partial(struct pbuf *p,
00343        struct ip_addr *src, struct ip_addr *dest,
00344        u8_t proto, u16_t proto_len, u16_t chksum_len)
00345 {
00346   u32_t acc;
00347   struct pbuf *q;
00348   u8_t swapped;
00349   u16_t chklen;
00350 
00351   acc = 0;
00352   swapped = 0;
00353   /* iterate through all pbuf in chain */
00354   for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
00355     LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
00356       (void *)q, (void *)q->next));
00357     chklen = q->len;
00358     if (chklen > chksum_len) {
00359       chklen = chksum_len;
00360     }
00361     acc += LWIP_CHKSUM(q->payload, chklen);
00362     chksum_len -= chklen;
00363     LWIP_ASSERT("delete me", chksum_len < 0x7fff);
00364     /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
00365     /* fold the upper bit down */
00366     acc = FOLD_U32T(acc);
00367     if (q->len % 2 != 0) {
00368       swapped = 1 - swapped;
00369       acc = SWAP_BYTES_IN_WORD(acc);
00370     }
00371     /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
00372   }
00373 
00374   if (swapped) {
00375     acc = SWAP_BYTES_IN_WORD(acc);
00376   }
00377   acc += (src->addr & 0xffffUL);
00378   acc += ((src->addr >> 16) & 0xffffUL);
00379   acc += (dest->addr & 0xffffUL);
00380   acc += ((dest->addr >> 16) & 0xffffUL);
00381   acc += (u32_t)htons((u16_t)proto);
00382   acc += (u32_t)htons(proto_len);
00383 
00384   /* Fold 32-bit sum to 16 bits
00385      calling this twice is propably faster than if statements... */
00386   acc = FOLD_U32T(acc);
00387   acc = FOLD_U32T(acc);
00388   LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
00389   return (u16_t)~(acc & 0xffffUL);
00390 }
00391 #endif /* LWIP_UDPLITE */
00392 
00393 /* inet_chksum:
00394  *
00395  * Calculates the Internet checksum over a portion of memory. Used primarily for IP
00396  * and ICMP.
00397  *
00398  * @param dataptr start of the buffer to calculate the checksum (no alignment needed)
00399  * @param len length of the buffer to calculate the checksum
00400  * @return checksum (as u16_t) to be saved directly in the protocol header
00401  */
00402 
00403 u16_t
00404 inet_chksum(void *dataptr, u16_t len)
00405 {
00406   return ~LWIP_CHKSUM(dataptr, len);
00407 }
00408 
00409 /**
00410  * Calculate a checksum over a chain of pbufs (without pseudo-header, much like
00411  * inet_chksum only pbufs are used).
00412  *
00413  * @param p pbuf chain over that the checksum should be calculated
00414  * @return checksum (as u16_t) to be saved directly in the protocol header
00415  */
00416 u16_t
00417 inet_chksum_pbuf(struct pbuf *p)
00418 {
00419   u32_t acc;
00420   struct pbuf *q;
00421   u8_t swapped;
00422 
00423   acc = 0;
00424   swapped = 0;
00425   for(q = p; q != NULL; q = q->next) {
00426     acc += LWIP_CHKSUM(q->payload, q->len);
00427     acc = FOLD_U32T(acc);
00428     if (q->len % 2 != 0) {
00429       swapped = 1 - swapped;
00430       acc = SWAP_BYTES_IN_WORD(acc);
00431     }
00432   }
00433 
00434   if (swapped) {
00435     acc = SWAP_BYTES_IN_WORD(acc);
00436   }
00437   return (u16_t)~(acc & 0xffffUL);
00438 }