ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_inet_chksum.c Source File

lwip_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/def.h"
00043 #include "lwip/ip_addr.h"
00044 
00045 #include <stddef.h>
00046 #include <string.h>
00047 
00048 /* These are some reference implementations of the checksum algorithm, with the
00049  * aim of being simple, correct and fully portable. Checksumming is the
00050  * first thing you would want to optimize for your platform. If you create
00051  * your own version, link it in and in your cc.h put:
00052  *
00053  * #define LWIP_CHKSUM <your_checksum_routine>
00054  *
00055  * Or you can select from the implementations below by defining
00056  * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
00057  */
00058 
00059 #ifndef LWIP_CHKSUM
00060 # define LWIP_CHKSUM lwip_standard_chksum
00061 # ifndef LWIP_CHKSUM_ALGORITHM
00062 #  define LWIP_CHKSUM_ALGORITHM 2
00063 # endif
00064 u16_t lwip_standard_chksum(const void *dataptr, int len);
00065 #endif
00066 /* If none set: */
00067 #ifndef LWIP_CHKSUM_ALGORITHM
00068 # define LWIP_CHKSUM_ALGORITHM 0
00069 #endif
00070 
00071 #if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */
00072 /**
00073  * lwip checksum
00074  *
00075  * @param dataptr points to start of data to be summed at any boundary
00076  * @param len length of data to be summed
00077  * @return host order (!) lwip checksum (non-inverted Internet sum)
00078  *
00079  * @note accumulator size limits summable length to 64k
00080  * @note host endianess is irrelevant (p3 RFC1071)
00081  */
00082 u16_t
00083 lwip_standard_chksum(const void *dataptr, int len)
00084 {
00085   u32_t acc;
00086   u16_t src;
00087   const u8_t *octetptr;
00088 
00089   acc = 0;
00090   /* dataptr may be at odd or even addresses */
00091   octetptr = (const u8_t*)dataptr;
00092   while (len > 1) {
00093     /* declare first octet as most significant
00094        thus assume network order, ignoring host order */
00095     src = (*octetptr) << 8;
00096     octetptr++;
00097     /* declare second octet as least significant */
00098     src |= (*octetptr);
00099     octetptr++;
00100     acc += src;
00101     len -= 2;
00102   }
00103   if (len > 0) {
00104     /* accumulate remaining octet */
00105     src = (*octetptr) << 8;
00106     acc += src;
00107   }
00108   /* add deferred carry bits */
00109   acc = (acc >> 16) + (acc & 0x0000ffffUL);
00110   if ((acc & 0xffff0000UL) != 0) {
00111     acc = (acc >> 16) + (acc & 0x0000ffffUL);
00112   }
00113   /* This maybe a little confusing: reorder sum using htons()
00114      instead of ntohs() since it has a little less call overhead.
00115      The caller must invert bits for Internet sum ! */
00116   return htons((u16_t)acc);
00117 }
00118 #endif
00119 
00120 #if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */
00121 /*
00122  * Curt McDowell
00123  * Broadcom Corp.
00124  * csm@broadcom.com
00125  *
00126  * IP checksum two bytes at a time with support for
00127  * unaligned buffer.
00128  * Works for len up to and including 0x20000.
00129  * by Curt McDowell, Broadcom Corp. 12/08/2005
00130  *
00131  * @param dataptr points to start of data to be summed at any boundary
00132  * @param len length of data to be summed
00133  * @return host order (!) lwip checksum (non-inverted Internet sum)
00134  */
00135 u16_t
00136 lwip_standard_chksum(const void *dataptr, int len)
00137 {
00138   const u8_t *pb = (const u8_t *)dataptr;
00139   const u16_t *ps;
00140   u16_t t = 0;
00141   u32_t sum = 0;
00142   int odd = ((mem_ptr_t)pb & 1);
00143 
00144   /* Get aligned to u16_t */
00145   if (odd && len > 0) {
00146     ((u8_t *)&t)[1] = *pb++;
00147     len--;
00148   }
00149 
00150   /* Add the bulk of the data */
00151   ps = (const u16_t *)(const void *)pb;
00152   while (len > 1) {
00153     sum += *ps++;
00154     len -= 2;
00155   }
00156 
00157   /* Consume left-over byte, if any */
00158   if (len > 0) {
00159     ((u8_t *)&t)[0] = *(const u8_t *)ps;
00160   }
00161 
00162   /* Add end bytes */
00163   sum += t;
00164 
00165   /* Fold 32-bit sum to 16 bits
00166      calling this twice is probably faster than if statements... */
00167   sum = FOLD_U32T(sum);
00168   sum = FOLD_U32T(sum);
00169 
00170   /* Swap if alignment was odd */
00171   if (odd) {
00172     sum = SWAP_BYTES_IN_WORD(sum);
00173   }
00174 
00175   return (u16_t)sum;
00176 }
00177 #endif
00178 
00179 #if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */
00180 /**
00181  * An optimized checksum routine. Basically, it uses loop-unrolling on
00182  * the checksum loop, treating the head and tail bytes specially, whereas
00183  * the inner loop acts on 8 bytes at a time.
00184  *
00185  * @arg start of buffer to be checksummed. May be an odd byte address.
00186  * @len number of bytes in the buffer to be checksummed.
00187  * @return host order (!) lwip checksum (non-inverted Internet sum)
00188  *
00189  * by Curt McDowell, Broadcom Corp. December 8th, 2005
00190  */
00191 u16_t
00192 lwip_standard_chksum(const void *dataptr, int len)
00193 {
00194   const u8_t *pb = (const u8_t *)dataptr;
00195   const u16_t *ps;
00196   u16_t t = 0;
00197   const u32_t *pl;
00198   u32_t sum = 0, tmp;
00199   /* starts at odd byte address? */
00200   int odd = ((mem_ptr_t)pb & 1);
00201 
00202   if (odd && len > 0) {
00203     ((u8_t *)&t)[1] = *pb++;
00204     len--;
00205   }
00206 
00207   ps = (const u16_t *)(const void*)pb;
00208 
00209   if (((mem_ptr_t)ps & 3) && len > 1) {
00210     sum += *ps++;
00211     len -= 2;
00212   }
00213 
00214   pl = (const u32_t *)(const void*)ps;
00215 
00216   while (len > 7)  {
00217     tmp = sum + *pl++;          /* ping */
00218     if (tmp < sum) {
00219       tmp++;                    /* add back carry */
00220     }
00221 
00222     sum = tmp + *pl++;          /* pong */
00223     if (sum < tmp) {
00224       sum++;                    /* add back carry */
00225     }
00226 
00227     len -= 8;
00228   }
00229 
00230   /* make room in upper bits */
00231   sum = FOLD_U32T(sum);
00232 
00233   ps = (const u16_t *)pl;
00234 
00235   /* 16-bit aligned word remaining? */
00236   while (len > 1) {
00237     sum += *ps++;
00238     len -= 2;
00239   }
00240 
00241   /* dangling tail byte remaining? */
00242   if (len > 0) {                /* include odd byte */
00243     ((u8_t *)&t)[0] = *(const u8_t *)ps;
00244   }
00245 
00246   sum += t;                     /* add end bytes */
00247 
00248   /* Fold 32-bit sum to 16 bits
00249      calling this twice is probably faster than if statements... */
00250   sum = FOLD_U32T(sum);
00251   sum = FOLD_U32T(sum);
00252 
00253   if (odd) {
00254     sum = SWAP_BYTES_IN_WORD(sum);
00255   }
00256 
00257   return (u16_t)sum;
00258 }
00259 #endif
00260 
00261 /** Parts of the pseudo checksum which are common to IPv4 and IPv6 */
00262 static u16_t
00263 inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc)
00264 {
00265   struct pbuf *q;
00266   u8_t swapped = 0;
00267 
00268   /* iterate through all pbuf in chain */
00269   for (q = p; q != NULL; q = q->next) {
00270     LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
00271       (void *)q, (void *)q->next));
00272     acc += LWIP_CHKSUM(q->payload, q->len);
00273     /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
00274     /* just executing this next line is probably faster that the if statement needed
00275        to check whether we really need to execute it, and does no harm */
00276     acc = FOLD_U32T(acc);
00277     if (q->len % 2 != 0) {
00278       swapped = 1 - swapped;
00279       acc = SWAP_BYTES_IN_WORD(acc);
00280     }
00281     /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
00282   }
00283 
00284   if (swapped) {
00285     acc = SWAP_BYTES_IN_WORD(acc);
00286   }
00287 
00288   acc += (u32_t)htons((u16_t)proto);
00289   acc += (u32_t)htons(proto_len);
00290 
00291   /* Fold 32-bit sum to 16 bits
00292      calling this twice is probably faster than if statements... */
00293   acc = FOLD_U32T(acc);
00294   acc = FOLD_U32T(acc);
00295   LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
00296   return (u16_t)~(acc & 0xffffUL);
00297 }
00298 
00299 #if LWIP_IPV4
00300 /* inet_chksum_pseudo:
00301  *
00302  * Calculates the IPv4 pseudo Internet checksum used by TCP and UDP for a pbuf chain.
00303  * IP addresses are expected to be in network byte order.
00304  *
00305  * @param p chain of pbufs over that a checksum should be calculated (ip data part)
00306  * @param src source ip address (used for checksum of pseudo header)
00307  * @param dst destination ip address (used for checksum of pseudo header)
00308  * @param proto ip protocol (used for checksum of pseudo header)
00309  * @param proto_len length of the ip data part (used for checksum of pseudo header)
00310  * @return checksum (as u16_t) to be saved directly in the protocol header
00311  */
00312 u16_t
00313 inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
00314        const ip4_addr_t *src, const ip4_addr_t *dest)
00315 {
00316   u32_t acc;
00317   u32_t addr;
00318 
00319   addr = ip4_addr_get_u32(src);
00320   acc = (addr & 0xffffUL);
00321   acc += ((addr >> 16) & 0xffffUL);
00322   addr = ip4_addr_get_u32(dest);
00323   acc += (addr & 0xffffUL);
00324   acc += ((addr >> 16) & 0xffffUL);
00325   /* fold down to 16 bits */
00326   acc = FOLD_U32T(acc);
00327   acc = FOLD_U32T(acc);
00328 
00329   return inet_cksum_pseudo_base(p, proto, proto_len, acc);
00330 }
00331 #endif /* LWIP_IPV4 */
00332 
00333 #if LWIP_IPV6
00334 /**
00335  * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain.
00336  * IPv6 addresses are expected to be in network byte order.
00337  *
00338  * @param p chain of pbufs over that a checksum should be calculated (ip data part)
00339  * @param proto ipv6 protocol/next header (used for checksum of pseudo header)
00340  * @param proto_len length of the ipv6 payload (used for checksum of pseudo header)
00341  * @param src source ipv6 address (used for checksum of pseudo header)
00342  * @param dest destination ipv6 address (used for checksum of pseudo header)
00343  * @return checksum (as u16_t) to be saved directly in the protocol header
00344  */
00345 u16_t
00346 ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
00347        const ip6_addr_t *src, const ip6_addr_t *dest)
00348 {
00349   u32_t acc = 0;
00350   u32_t addr;
00351   u8_t addr_part;
00352 
00353   for (addr_part = 0; addr_part < 4; addr_part++) {
00354     addr = src->addr[addr_part];
00355     acc += (addr & 0xffffUL);
00356     acc += ((addr >> 16) & 0xffffUL);
00357     addr = dest->addr[addr_part];
00358     acc += (addr & 0xffffUL);
00359     acc += ((addr >> 16) & 0xffffUL);
00360   }
00361   /* fold down to 16 bits */
00362   acc = FOLD_U32T(acc);
00363   acc = FOLD_U32T(acc);
00364 
00365   return inet_cksum_pseudo_base(p, proto, proto_len, acc);
00366 }
00367 #endif /* LWIP_IPV6 */
00368 
00369 /* ip_chksum_pseudo:
00370  *
00371  * Calculates the IPv4 or IPv6 pseudo Internet checksum used by TCP and UDP for a pbuf chain.
00372  * IP addresses are expected to be in network byte order.
00373  *
00374  * @param p chain of pbufs over that a checksum should be calculated (ip data part)
00375  * @param src source ip address (used for checksum of pseudo header)
00376  * @param dst destination ip address (used for checksum of pseudo header)
00377  * @param proto ip protocol (used for checksum of pseudo header)
00378  * @param proto_len length of the ip data part (used for checksum of pseudo header)
00379  * @return checksum (as u16_t) to be saved directly in the protocol header
00380  */
00381 u16_t
00382 ip_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
00383        const ip_addr_t *src, const ip_addr_t *dest)
00384 {
00385 #if LWIP_IPV6
00386   if (IP_IS_V6(dest)) {
00387     return ip6_chksum_pseudo(p, proto, proto_len, ip_2_ip6(src), ip_2_ip6(dest));
00388   }
00389 #endif /* LWIP_IPV6 */
00390 #if LWIP_IPV4 && LWIP_IPV6
00391   else
00392 #endif /* LWIP_IPV4 && LWIP_IPV6 */
00393 #if LWIP_IPV4
00394   {
00395     return inet_chksum_pseudo(p, proto, proto_len, ip_2_ip4(src), ip_2_ip4(dest));
00396   }
00397 #endif /* LWIP_IPV4 */
00398 }
00399 
00400 /** Parts of the pseudo checksum which are common to IPv4 and IPv6 */
00401 static u16_t
00402 inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len,
00403        u16_t chksum_len, u32_t acc)
00404 {
00405   struct pbuf *q;
00406   u8_t swapped = 0;
00407   u16_t chklen;
00408 
00409   /* iterate through all pbuf in chain */
00410   for (q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
00411     LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
00412       (void *)q, (void *)q->next));
00413     chklen = q->len;
00414     if (chklen > chksum_len) {
00415       chklen = chksum_len;
00416     }
00417     acc += LWIP_CHKSUM(q->payload, chklen);
00418     chksum_len -= chklen;
00419     LWIP_ASSERT("delete me", chksum_len < 0x7fff);
00420     /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
00421     /* fold the upper bit down */
00422     acc = FOLD_U32T(acc);
00423     if (q->len % 2 != 0) {
00424       swapped = 1 - swapped;
00425       acc = SWAP_BYTES_IN_WORD(acc);
00426     }
00427     /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
00428   }
00429 
00430   if (swapped) {
00431     acc = SWAP_BYTES_IN_WORD(acc);
00432   }
00433 
00434   acc += (u32_t)htons((u16_t)proto);
00435   acc += (u32_t)htons(proto_len);
00436 
00437   /* Fold 32-bit sum to 16 bits
00438      calling this twice is probably faster than if statements... */
00439   acc = FOLD_U32T(acc);
00440   acc = FOLD_U32T(acc);
00441   LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
00442   return (u16_t)~(acc & 0xffffUL);
00443 }
00444 
00445 #if LWIP_IPV4
00446 /* inet_chksum_pseudo_partial:
00447  *
00448  * Calculates the IPv4 pseudo Internet checksum used by TCP and UDP for a pbuf chain.
00449  * IP addresses are expected to be in network byte order.
00450  *
00451  * @param p chain of pbufs over that a checksum should be calculated (ip data part)
00452  * @param src source ip address (used for checksum of pseudo header)
00453  * @param dst destination ip address (used for checksum of pseudo header)
00454  * @param proto ip protocol (used for checksum of pseudo header)
00455  * @param proto_len length of the ip data part (used for checksum of pseudo header)
00456  * @return checksum (as u16_t) to be saved directly in the protocol header
00457  */
00458 u16_t
00459 inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
00460        u16_t chksum_len, const ip4_addr_t *src, const ip4_addr_t *dest)
00461 {
00462   u32_t acc;
00463   u32_t addr;
00464 
00465   addr = ip4_addr_get_u32(src);
00466   acc = (addr & 0xffffUL);
00467   acc += ((addr >> 16) & 0xffffUL);
00468   addr = ip4_addr_get_u32(dest);
00469   acc += (addr & 0xffffUL);
00470   acc += ((addr >> 16) & 0xffffUL);
00471   /* fold down to 16 bits */
00472   acc = FOLD_U32T(acc);
00473   acc = FOLD_U32T(acc);
00474 
00475   return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc);
00476 }
00477 #endif /* LWIP_IPV4 */
00478 
00479 #if LWIP_IPV6
00480 /**
00481  * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain.
00482  * IPv6 addresses are expected to be in network byte order. Will only compute for a
00483  * portion of the payload.
00484  *
00485  * @param p chain of pbufs over that a checksum should be calculated (ip data part)
00486  * @param proto ipv6 protocol/next header (used for checksum of pseudo header)
00487  * @param proto_len length of the ipv6 payload (used for checksum of pseudo header)
00488  * @param chksum_len number of payload bytes used to compute chksum
00489  * @param src source ipv6 address (used for checksum of pseudo header)
00490  * @param dest destination ipv6 address (used for checksum of pseudo header)
00491  * @return checksum (as u16_t) to be saved directly in the protocol header
00492  */
00493 u16_t
00494 ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
00495        u16_t chksum_len, const ip6_addr_t *src, const ip6_addr_t *dest)
00496 {
00497   u32_t acc = 0;
00498   u32_t addr;
00499   u8_t addr_part;
00500 
00501   for (addr_part = 0; addr_part < 4; addr_part++) {
00502     addr = src->addr[addr_part];
00503     acc += (addr & 0xffffUL);
00504     acc += ((addr >> 16) & 0xffffUL);
00505     addr = dest->addr[addr_part];
00506     acc += (addr & 0xffffUL);
00507     acc += ((addr >> 16) & 0xffffUL);
00508   }
00509   /* fold down to 16 bits */
00510   acc = FOLD_U32T(acc);
00511   acc = FOLD_U32T(acc);
00512 
00513   return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc);
00514 }
00515 #endif /* LWIP_IPV6 */
00516 
00517 /* ip_chksum_pseudo_partial:
00518  *
00519  * Calculates the IPv4 or IPv6 pseudo Internet checksum used by TCP and UDP for a pbuf chain.
00520  *
00521  * @param p chain of pbufs over that a checksum should be calculated (ip data part)
00522  * @param src source ip address (used for checksum of pseudo header)
00523  * @param dst destination ip address (used for checksum of pseudo header)
00524  * @param proto ip protocol (used for checksum of pseudo header)
00525  * @param proto_len length of the ip data part (used for checksum of pseudo header)
00526  * @return checksum (as u16_t) to be saved directly in the protocol header
00527  */
00528 u16_t
00529 ip_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
00530        u16_t chksum_len, const ip_addr_t *src, const ip_addr_t *dest)
00531 {
00532 #if LWIP_IPV6
00533   if (IP_IS_V6(dest)) {
00534     return ip6_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ip_2_ip6(src), ip_2_ip6(dest));
00535   }
00536 #endif /* LWIP_IPV6 */
00537 #if LWIP_IPV4 && LWIP_IPV6
00538   else
00539 #endif /* LWIP_IPV4 && LWIP_IPV6 */
00540 #if LWIP_IPV4
00541   {
00542     return inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ip_2_ip4(src), ip_2_ip4(dest));
00543   }
00544 #endif /* LWIP_IPV4 */
00545 }
00546 
00547 /* inet_chksum:
00548  *
00549  * Calculates the Internet checksum over a portion of memory. Used primarily for IP
00550  * and ICMP.
00551  *
00552  * @param dataptr start of the buffer to calculate the checksum (no alignment needed)
00553  * @param len length of the buffer to calculate the checksum
00554  * @return checksum (as u16_t) to be saved directly in the protocol header
00555  */
00556 
00557 u16_t
00558 inet_chksum(const void *dataptr, u16_t len)
00559 {
00560   return (u16_t)~(unsigned int)LWIP_CHKSUM(dataptr, len);
00561 }
00562 
00563 /**
00564  * Calculate a checksum over a chain of pbufs (without pseudo-header, much like
00565  * inet_chksum only pbufs are used).
00566  *
00567  * @param p pbuf chain over that the checksum should be calculated
00568  * @return checksum (as u16_t) to be saved directly in the protocol header
00569  */
00570 u16_t
00571 inet_chksum_pbuf(struct pbuf *p)
00572 {
00573   u32_t acc;
00574   struct pbuf *q;
00575   u8_t swapped;
00576 
00577   acc = 0;
00578   swapped = 0;
00579   for (q = p; q != NULL; q = q->next) {
00580     acc += LWIP_CHKSUM(q->payload, q->len);
00581     acc = FOLD_U32T(acc);
00582     if (q->len % 2 != 0) {
00583       swapped = 1 - swapped;
00584       acc = SWAP_BYTES_IN_WORD(acc);
00585     }
00586   }
00587 
00588   if (swapped) {
00589     acc = SWAP_BYTES_IN_WORD(acc);
00590   }
00591   return (u16_t)~(acc & 0xffffUL);
00592 }
00593 
00594 /* These are some implementations for LWIP_CHKSUM_COPY, which copies data
00595  * like MEMCPY but generates a checksum at the same time. Since this is a
00596  * performance-sensitive function, you might want to create your own version
00597  * in assembly targeted at your hardware by defining it in lwipopts.h:
00598  *   #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len)
00599  */
00600 
00601 #if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */
00602 /** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM.
00603  * For architectures with big caches, data might still be in cache when
00604  * generating the checksum after copying.
00605  */
00606 u16_t
00607 lwip_chksum_copy(void *dst, const void *src, u16_t len)
00608 {
00609   MEMCPY(dst, src, len);
00610   return LWIP_CHKSUM(dst, len);
00611 }
00612 #endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */