Rtos API example

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