Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of lwip by
inet_chksum.c
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 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 /** 00071 * lwip checksum 00072 * 00073 * @param dataptr points to start of data to be summed at any boundary 00074 * @param len length of data to be summed 00075 * @return host order (!) lwip checksum (non-inverted Internet sum) 00076 * 00077 * @note accumulator size limits summable length to 64k 00078 * @note host endianess is irrelevant (p3 RFC1071) 00079 */ 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 /** 00179 * An optimized checksum routine. Basically, it uses loop-unrolling on 00180 * the checksum loop, treating the head and tail bytes specially, whereas 00181 * the inner loop acts on 8 bytes at a time. 00182 * 00183 * @arg start of buffer to be checksummed. May be an odd byte address. 00184 * @len number of bytes in the buffer to be checksummed. 00185 * @return host order (!) lwip checksum (non-inverted Internet sum) 00186 * 00187 * by Curt McDowell, Broadcom Corp. December 8th, 2005 00188 */ 00189 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 00401 /** 00402 * Calculate a checksum over a chain of pbufs (without pseudo-header, much like 00403 * inet_chksum only pbufs are used). 00404 * 00405 * @param p pbuf chain over that the checksum should be calculated 00406 * @return checksum (as u16_t) to be saved directly in the protocol header 00407 */ 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 /** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM. 00441 * For architectures with big caches, data might still be in cache when 00442 * generating the checksum after copying. 00443 */ 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 Tue Jul 12 2022 11:29:36 by
