|
||||
Warning, cross-references for /kernel/lwip/core/ipv4/inet_chksum.c need to be fixed.
0001 /** 0002 * @file 0003 * Incluse internet checksum functions. 0004 * 0005 */ 0006 0007 /* 0008 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 0009 * All rights reserved. 0010 * 0011 * Redistribution and use in source and binary forms, with or without modification, 0012 * are permitted provided that the following conditions are met: 0013 * 0014 * 1. Redistributions of source code must retain the above copyright notice, 0015 * this list of conditions and the following disclaimer. 0016 * 2. Redistributions in binary form must reproduce the above copyright notice, 0017 * this list of conditions and the following disclaimer in the documentation 0018 * and/or other materials provided with the distribution. 0019 * 3. The name of the author may not be used to endorse or promote products 0020 * derived from this software without specific prior written permission. 0021 * 0022 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 0023 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 0024 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 0025 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 0026 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 0027 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 0028 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 0029 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 0030 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 0031 * OF SUCH DAMAGE. 0032 * 0033 * This file is part of the lwIP TCP/IP stack. 0034 * 0035 * Author: Adam Dunkels <adam@sics.se> 0036 * 0037 */ 0038 0039 #include "lwip/opt.h" 0040 0041 #include "lwip/inet_chksum.h" 0042 #include "lwip/inet.h" 0043 0044 #include <stddef.h> 0045 0046 /* These are some reference implementations of the checksum algorithm, with the 0047 * aim of being simple, correct and fully portable. Checksumming is the 0048 * first thing you would want to optimize for your platform. If you create 0049 * your own version, link it in and in your cc.h put: 0050 * 0051 * #define LWIP_CHKSUM <your_checksum_routine> 0052 * 0053 * Or you can select from the implementations below by defining 0054 * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3. 0055 */ 0056 0057 #ifndef LWIP_CHKSUM 0058 # define LWIP_CHKSUM lwip_standard_chksum 0059 # ifndef LWIP_CHKSUM_ALGORITHM 0060 # define LWIP_CHKSUM_ALGORITHM 1 0061 # endif 0062 #endif 0063 /* If none set: */ 0064 #ifndef LWIP_CHKSUM_ALGORITHM 0065 # define LWIP_CHKSUM_ALGORITHM 0 0066 #endif 0067 0068 /** Like the name says... */ 0069 #if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) 0070 /* little endian and PLATFORM_BYTESWAP defined */ 0071 #define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w) 0072 #else 0073 /* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */ 0074 #define SWAP_BYTES_IN_WORD(w) ((w & 0xff) << 8) | ((w & 0xff00) >> 8) 0075 #endif 0076 0077 /** Split an u32_t in two u16_ts and add them up */ 0078 #define FOLD_U32T(u) ((u >> 16) + (u & 0x0000ffffUL)) 0079 0080 #if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */ 0081 /** 0082 * lwip checksum 0083 * 0084 * @param dataptr points to start of data to be summed at any boundary 0085 * @param len length of data to be summed 0086 * @return host order (!) lwip checksum (non-inverted Internet sum) 0087 * 0088 * @note accumulator size limits summable length to 64k 0089 * @note host endianess is irrelevant (p3 RFC1071) 0090 */ 0091 static u16_t 0092 lwip_standard_chksum(void *dataptr, u16_t len) 0093 { 0094 u32_t acc; 0095 u16_t src; 0096 u8_t *octetptr; 0097 0098 acc = 0; 0099 /* dataptr may be at odd or even addresses */ 0100 octetptr = (u8_t*)dataptr; 0101 while (len > 1) { 0102 /* declare first octet as most significant 0103 thus assume network order, ignoring host order */ 0104 src = (*octetptr) << 8; 0105 octetptr++; 0106 /* declare second octet as least significant */ 0107 src |= (*octetptr); 0108 octetptr++; 0109 acc += src; 0110 len -= 2; 0111 } 0112 if (len > 0) { 0113 /* accumulate remaining octet */ 0114 src = (*octetptr) << 8; 0115 acc += src; 0116 } 0117 /* add deferred carry bits */ 0118 acc = (acc >> 16) + (acc & 0x0000ffffUL); 0119 if ((acc & 0xffff0000UL) != 0) { 0120 acc = (acc >> 16) + (acc & 0x0000ffffUL); 0121 } 0122 /* This maybe a little confusing: reorder sum using htons() 0123 instead of ntohs() since it has a little less call overhead. 0124 The caller must invert bits for Internet sum ! */ 0125 return htons((u16_t)acc); 0126 } 0127 #endif 0128 0129 #if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */ 0130 /* 0131 * Curt McDowell 0132 * Broadcom Corp. 0133 * csm@broadcom.com 0134 * 0135 * IP checksum two bytes at a time with support for 0136 * unaligned buffer. 0137 * Works for len up to and including 0x20000. 0138 * by Curt McDowell, Broadcom Corp. 12/08/2005 0139 * 0140 * @param dataptr points to start of data to be summed at any boundary 0141 * @param len length of data to be summed 0142 * @return host order (!) lwip checksum (non-inverted Internet sum) 0143 */ 0144 0145 static u16_t 0146 lwip_standard_chksum(void *dataptr, int len) 0147 { 0148 u8_t *pb = dataptr; 0149 u16_t *ps, t = 0; 0150 u32_t sum = 0; 0151 int odd = ((u32_t)pb & 1); 0152 0153 /* Get aligned to u16_t */ 0154 if (odd && len > 0) { 0155 ((u8_t *)&t)[1] = *pb++; 0156 len--; 0157 } 0158 0159 /* Add the bulk of the data */ 0160 ps = (u16_t *)pb; 0161 while (len > 1) { 0162 sum += *ps++; 0163 len -= 2; 0164 } 0165 0166 /* Consume left-over byte, if any */ 0167 if (len > 0) { 0168 ((u8_t *)&t)[0] = *(u8_t *)ps;; 0169 } 0170 0171 /* Add end bytes */ 0172 sum += t; 0173 0174 /* Fold 32-bit sum to 16 bits 0175 calling this twice is propably faster than if statements... */ 0176 sum = FOLD_U32T(sum); 0177 sum = FOLD_U32T(sum); 0178 0179 /* Swap if alignment was odd */ 0180 if (odd) { 0181 sum = SWAP_BYTES_IN_WORD(sum); 0182 } 0183 0184 return sum; 0185 } 0186 #endif 0187 0188 #if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */ 0189 /** 0190 * An optimized checksum routine. Basically, it uses loop-unrolling on 0191 * the checksum loop, treating the head and tail bytes specially, whereas 0192 * the inner loop acts on 8 bytes at a time. 0193 * 0194 * @arg start of buffer to be checksummed. May be an odd byte address. 0195 * @len number of bytes in the buffer to be checksummed. 0196 * @return host order (!) lwip checksum (non-inverted Internet sum) 0197 * 0198 * by Curt McDowell, Broadcom Corp. December 8th, 2005 0199 */ 0200 0201 static u16_t 0202 lwip_standard_chksum(void *dataptr, int len) 0203 { 0204 u8_t *pb = dataptr; 0205 u16_t *ps, t = 0; 0206 u32_t *pl; 0207 u32_t sum = 0, tmp; 0208 /* starts at odd byte address? */ 0209 int odd = ((u32_t)pb & 1); 0210 0211 if (odd && len > 0) { 0212 ((u8_t *)&t)[1] = *pb++; 0213 len--; 0214 } 0215 0216 ps = (u16_t *)pb; 0217 0218 if (((u32_t)ps & 3) && len > 1) { 0219 sum += *ps++; 0220 len -= 2; 0221 } 0222 0223 pl = (u32_t *)ps; 0224 0225 while (len > 7) { 0226 tmp = sum + *pl++; /* ping */ 0227 if (tmp < sum) { 0228 tmp++; /* add back carry */ 0229 } 0230 0231 sum = tmp + *pl++; /* pong */ 0232 if (sum < tmp) { 0233 sum++; /* add back carry */ 0234 } 0235 0236 len -= 8; 0237 } 0238 0239 /* make room in upper bits */ 0240 sum = FOLD_U32T(sum); 0241 0242 ps = (u16_t *)pl; 0243 0244 /* 16-bit aligned word remaining? */ 0245 while (len > 1) { 0246 sum += *ps++; 0247 len -= 2; 0248 } 0249 0250 /* dangling tail byte remaining? */ 0251 if (len > 0) { /* include odd byte */ 0252 ((u8_t *)&t)[0] = *(u8_t *)ps; 0253 } 0254 0255 sum += t; /* add end bytes */ 0256 0257 /* Fold 32-bit sum to 16 bits 0258 calling this twice is propably faster than if statements... */ 0259 sum = FOLD_U32T(sum); 0260 sum = FOLD_U32T(sum); 0261 0262 if (odd) { 0263 sum = SWAP_BYTES_IN_WORD(sum); 0264 } 0265 0266 return sum; 0267 } 0268 #endif 0269 0270 /* inet_chksum_pseudo: 0271 * 0272 * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. 0273 * IP addresses are expected to be in network byte order. 0274 * 0275 * @param p chain of pbufs over that a checksum should be calculated (ip data part) 0276 * @param src source ip address (used for checksum of pseudo header) 0277 * @param dst destination ip address (used for checksum of pseudo header) 0278 * @param proto ip protocol (used for checksum of pseudo header) 0279 * @param proto_len length of the ip data part (used for checksum of pseudo header) 0280 * @return checksum (as u16_t) to be saved directly in the protocol header 0281 */ 0282 u16_t 0283 inet_chksum_pseudo(struct pbuf *p, 0284 struct ip_addr *src, struct ip_addr *dest, 0285 u8_t proto, u16_t proto_len) 0286 { 0287 u32_t acc; 0288 struct pbuf *q; 0289 u8_t swapped; 0290 0291 acc = 0; 0292 swapped = 0; 0293 /* iterate through all pbuf in chain */ 0294 for(q = p; q != NULL; q = q->next) { 0295 LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", 0296 (void *)q, (void *)q->next)); 0297 acc += LWIP_CHKSUM(q->payload, q->len); 0298 /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ 0299 /* just executing this next line is probably faster that the if statement needed 0300 to check whether we really need to execute it, and does no harm */ 0301 acc = FOLD_U32T(acc); 0302 if (q->len % 2 != 0) { 0303 swapped = 1 - swapped; 0304 acc = SWAP_BYTES_IN_WORD(acc); 0305 } 0306 /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ 0307 } 0308 0309 if (swapped) { 0310 acc = SWAP_BYTES_IN_WORD(acc); 0311 } 0312 acc += (src->addr & 0xffffUL); 0313 acc += ((src->addr >> 16) & 0xffffUL); 0314 acc += (dest->addr & 0xffffUL); 0315 acc += ((dest->addr >> 16) & 0xffffUL); 0316 acc += (u32_t)htons((u16_t)proto); 0317 acc += (u32_t)htons(proto_len); 0318 0319 /* Fold 32-bit sum to 16 bits 0320 calling this twice is propably faster than if statements... */ 0321 acc = FOLD_U32T(acc); 0322 acc = FOLD_U32T(acc); 0323 LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); 0324 return (u16_t)~(acc & 0xffffUL); 0325 } 0326 0327 /* inet_chksum_pseudo: 0328 * 0329 * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. 0330 * IP addresses are expected to be in network byte order. 0331 * 0332 * @param p chain of pbufs over that a checksum should be calculated (ip data part) 0333 * @param src source ip address (used for checksum of pseudo header) 0334 * @param dst destination ip address (used for checksum of pseudo header) 0335 * @param proto ip protocol (used for checksum of pseudo header) 0336 * @param proto_len length of the ip data part (used for checksum of pseudo header) 0337 * @return checksum (as u16_t) to be saved directly in the protocol header 0338 */ 0339 /* Currently only used by UDPLITE, although this could change in the future. */ 0340 #if LWIP_UDPLITE 0341 u16_t 0342 inet_chksum_pseudo_partial(struct pbuf *p, 0343 struct ip_addr *src, struct ip_addr *dest, 0344 u8_t proto, u16_t proto_len, u16_t chksum_len) 0345 { 0346 u32_t acc; 0347 struct pbuf *q; 0348 u8_t swapped; 0349 u16_t chklen; 0350 0351 acc = 0; 0352 swapped = 0; 0353 /* iterate through all pbuf in chain */ 0354 for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) { 0355 LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", 0356 (void *)q, (void *)q->next)); 0357 chklen = q->len; 0358 if (chklen > chksum_len) { 0359 chklen = chksum_len; 0360 } 0361 acc += LWIP_CHKSUM(q->payload, chklen); 0362 chksum_len -= chklen; 0363 LWIP_ASSERT("delete me", chksum_len < 0x7fff); 0364 /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ 0365 /* fold the upper bit down */ 0366 acc = FOLD_U32T(acc); 0367 if (q->len % 2 != 0) { 0368 swapped = 1 - swapped; 0369 acc = SWAP_BYTES_IN_WORD(acc); 0370 } 0371 /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ 0372 } 0373 0374 if (swapped) { 0375 acc = SWAP_BYTES_IN_WORD(acc); 0376 } 0377 acc += (src->addr & 0xffffUL); 0378 acc += ((src->addr >> 16) & 0xffffUL); 0379 acc += (dest->addr & 0xffffUL); 0380 acc += ((dest->addr >> 16) & 0xffffUL); 0381 acc += (u32_t)htons((u16_t)proto); 0382 acc += (u32_t)htons(proto_len); 0383 0384 /* Fold 32-bit sum to 16 bits 0385 calling this twice is propably faster than if statements... */ 0386 acc = FOLD_U32T(acc); 0387 acc = FOLD_U32T(acc); 0388 LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); 0389 return (u16_t)~(acc & 0xffffUL); 0390 } 0391 #endif /* LWIP_UDPLITE */ 0392 0393 /* inet_chksum: 0394 * 0395 * Calculates the Internet checksum over a portion of memory. Used primarily for IP 0396 * and ICMP. 0397 * 0398 * @param dataptr start of the buffer to calculate the checksum (no alignment needed) 0399 * @param len length of the buffer to calculate the checksum 0400 * @return checksum (as u16_t) to be saved directly in the protocol header 0401 */ 0402 0403 u16_t 0404 inet_chksum(void *dataptr, u16_t len) 0405 { 0406 return ~LWIP_CHKSUM(dataptr, len); 0407 } 0408 0409 /** 0410 * Calculate a checksum over a chain of pbufs (without pseudo-header, much like 0411 * inet_chksum only pbufs are used). 0412 * 0413 * @param p pbuf chain over that the checksum should be calculated 0414 * @return checksum (as u16_t) to be saved directly in the protocol header 0415 */ 0416 u16_t 0417 inet_chksum_pbuf(struct pbuf *p) 0418 { 0419 u32_t acc; 0420 struct pbuf *q; 0421 u8_t swapped; 0422 0423 acc = 0; 0424 swapped = 0; 0425 for(q = p; q != NULL; q = q->next) { 0426 acc += LWIP_CHKSUM(q->payload, q->len); 0427 acc = FOLD_U32T(acc); 0428 if (q->len % 2 != 0) { 0429 swapped = 1 - swapped; 0430 acc = SWAP_BYTES_IN_WORD(acc); 0431 } 0432 } 0433 0434 if (swapped) { 0435 acc = SWAP_BYTES_IN_WORD(acc); 0436 } 0437 return (u16_t)~(acc & 0xffffUL); 0438 }
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 1.2.0 LXR engine. |