source: arduino-1-6-7/trunk/fuentes/arduino-ide-amd64/hardware/arduino/avr/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/SERVICES/LWIP/lwip-1.3.2/src/core/ipv4/inet_chksum.c @ 4837

Last change on this file since 4837 was 4837, checked in by daduve, 2 years ago

Adding new version

File size: 12.6 KB
Line 
1/* This source file is part of the ATMEL AVR-UC3-SoftwareFramework-1.7.0 Release */
2
3/**
4 * @file
5 * Incluse internet checksum functions.
6 *
7 */
8
9/*
10 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without modification,
14 * are permitted provided that the following conditions are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright notice,
17 *    this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 *    this list of conditions and the following disclaimer in the documentation
20 *    and/or other materials provided with the distribution.
21 * 3. The name of the author may not be used to endorse or promote products
22 *    derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
27 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
29 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33 * OF SUCH DAMAGE.
34 *
35 * This file is part of the lwIP TCP/IP stack.
36 *
37 * Author: Adam Dunkels <adam@sics.se>
38 *
39 */
40
41#include "lwip/opt.h"
42
43#include "lwip/inet_chksum.h"
44#include "lwip/inet.h"
45
46#include <stddef.h>
47
48/* These are some reference implementations of the checksum algorithm, with the
49 * aim of being simple, correct and fully portable. Checksumming is the
50 * first thing you would want to optimize for your platform. If you create
51 * your own version, link it in and in your cc.h put:
52 *
53 * #define LWIP_CHKSUM <your_checksum_routine>
54 *
55 * Or you can select from the implementations below by defining
56 * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
57 */
58
59#ifndef LWIP_CHKSUM
60# define LWIP_CHKSUM lwip_standard_chksum
61# ifndef LWIP_CHKSUM_ALGORITHM
62#  define LWIP_CHKSUM_ALGORITHM 1
63# endif
64#endif
65/* If none set: */
66#ifndef LWIP_CHKSUM_ALGORITHM
67# define LWIP_CHKSUM_ALGORITHM 0
68#endif
69
70/** Like the name says... */
71#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)
72/* little endian and PLATFORM_BYTESWAP defined */
73#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w)
74#else
75/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */
76#define SWAP_BYTES_IN_WORD(w) ((w & 0xff) << 8) | ((w & 0xff00) >> 8)
77#endif
78
79/** Split an u32_t in two u16_ts and add them up */
80#define FOLD_U32T(u)          ((u >> 16) + (u & 0x0000ffffUL))
81
82#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */
83/**
84 * lwip checksum
85 *
86 * @param dataptr points to start of data to be summed at any boundary
87 * @param len length of data to be summed
88 * @return host order (!) lwip checksum (non-inverted Internet sum)
89 *
90 * @note accumulator size limits summable length to 64k
91 * @note host endianess is irrelevant (p3 RFC1071)
92 */
93static u16_t
94lwip_standard_chksum(void *dataptr, u16_t len)
95{
96  u32_t acc;
97  u16_t src;
98  u8_t *octetptr;
99
100  acc = 0;
101  /* dataptr may be at odd or even addresses */
102  octetptr = (u8_t*)dataptr;
103  while (len > 1) {
104    /* declare first octet as most significant
105       thus assume network order, ignoring host order */
106    src = (*octetptr) << 8;
107    octetptr++;
108    /* declare second octet as least significant */
109    src |= (*octetptr);
110    octetptr++;
111    acc += src;
112    len -= 2;
113  }
114  if (len > 0) {
115    /* accumulate remaining octet */
116    src = (*octetptr) << 8;
117    acc += src;
118  }
119  /* add deferred carry bits */
120  acc = (acc >> 16) + (acc & 0x0000ffffUL);
121  if ((acc & 0xffff0000UL) != 0) {
122    acc = (acc >> 16) + (acc & 0x0000ffffUL);
123  }
124  /* This maybe a little confusing: reorder sum using htons()
125     instead of ntohs() since it has a little less call overhead.
126     The caller must invert bits for Internet sum ! */
127  return htons((u16_t)acc);
128}
129#endif
130
131#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */
132/*
133 * Curt McDowell
134 * Broadcom Corp.
135 * csm@broadcom.com
136 *
137 * IP checksum two bytes at a time with support for
138 * unaligned buffer.
139 * Works for len up to and including 0x20000.
140 * by Curt McDowell, Broadcom Corp. 12/08/2005
141 *
142 * @param dataptr points to start of data to be summed at any boundary
143 * @param len length of data to be summed
144 * @return host order (!) lwip checksum (non-inverted Internet sum)
145 */
146
147static u16_t
148lwip_standard_chksum(void *dataptr, int len)
149{
150  u8_t *pb = dataptr;
151  u16_t *ps, t = 0;
152  u32_t sum = 0;
153  int odd = ((u32_t)pb & 1);
154
155  /* Get aligned to u16_t */
156  if (odd && len > 0) {
157    ((u8_t *)&t)[1] = *pb++;
158    len--;
159  }
160
161  /* Add the bulk of the data */
162  ps = (u16_t *)pb;
163  while (len > 1) {
164    sum += *ps++;
165    len -= 2;
166  }
167
168  /* Consume left-over byte, if any */
169  if (len > 0) {
170    ((u8_t *)&t)[0] = *(u8_t *)ps;;
171  }
172
173  /* Add end bytes */
174  sum += t;
175
176  /* Fold 32-bit sum to 16 bits
177     calling this twice is propably faster than if statements... */
178  sum = FOLD_U32T(sum);
179  sum = FOLD_U32T(sum);
180
181  /* Swap if alignment was odd */
182  if (odd) {
183    sum = SWAP_BYTES_IN_WORD(sum);
184  }
185
186  return sum;
187}
188#endif
189
190#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */
191/**
192 * An optimized checksum routine. Basically, it uses loop-unrolling on
193 * the checksum loop, treating the head and tail bytes specially, whereas
194 * the inner loop acts on 8 bytes at a time.
195 *
196 * @arg start of buffer to be checksummed. May be an odd byte address.
197 * @len number of bytes in the buffer to be checksummed.
198 * @return host order (!) lwip checksum (non-inverted Internet sum)
199 *
200 * by Curt McDowell, Broadcom Corp. December 8th, 2005
201 */
202
203static u16_t
204lwip_standard_chksum(void *dataptr, int len)
205{
206  u8_t *pb = dataptr;
207  u16_t *ps, t = 0;
208  u32_t *pl;
209  u32_t sum = 0, tmp;
210  /* starts at odd byte address? */
211  int odd = ((u32_t)pb & 1);
212
213  if (odd && len > 0) {
214    ((u8_t *)&t)[1] = *pb++;
215    len--;
216  }
217
218  ps = (u16_t *)pb;
219
220  if (((u32_t)ps & 3) && len > 1) {
221    sum += *ps++;
222    len -= 2;
223  }
224
225  pl = (u32_t *)ps;
226
227  while (len > 7)  {
228    tmp = sum + *pl++;          /* ping */
229    if (tmp < sum) {
230      tmp++;                    /* add back carry */
231    }
232
233    sum = tmp + *pl++;          /* pong */
234    if (sum < tmp) {
235      sum++;                    /* add back carry */
236    }
237
238    len -= 8;
239  }
240
241  /* make room in upper bits */
242  sum = FOLD_U32T(sum);
243
244  ps = (u16_t *)pl;
245
246  /* 16-bit aligned word remaining? */
247  while (len > 1) {
248    sum += *ps++;
249    len -= 2;
250  }
251
252  /* dangling tail byte remaining? */
253  if (len > 0) {                /* include odd byte */
254    ((u8_t *)&t)[0] = *(u8_t *)ps;
255  }
256
257  sum += t;                     /* add end bytes */
258
259  /* Fold 32-bit sum to 16 bits
260     calling this twice is propably faster than if statements... */
261  sum = FOLD_U32T(sum);
262  sum = FOLD_U32T(sum);
263
264  if (odd) {
265    sum = SWAP_BYTES_IN_WORD(sum);
266  }
267
268  return sum;
269}
270#endif
271
272/* inet_chksum_pseudo:
273 *
274 * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
275 * IP addresses are expected to be in network byte order.
276 *
277 * @param p chain of pbufs over that a checksum should be calculated (ip data part)
278 * @param src source ip address (used for checksum of pseudo header)
279 * @param dst destination ip address (used for checksum of pseudo header)
280 * @param proto ip protocol (used for checksum of pseudo header)
281 * @param proto_len length of the ip data part (used for checksum of pseudo header)
282 * @return checksum (as u16_t) to be saved directly in the protocol header
283 */
284u16_t
285inet_chksum_pseudo(struct pbuf *p,
286       struct ip_addr *src, struct ip_addr *dest,
287       u8_t proto, u16_t proto_len)
288{
289  u32_t acc;
290  struct pbuf *q;
291  u8_t swapped;
292
293  acc = 0;
294  swapped = 0;
295  /* iterate through all pbuf in chain */
296  for(q = p; q != NULL; q = q->next) {
297    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
298      (void *)q, (void *)q->next));
299    acc += LWIP_CHKSUM(q->payload, q->len);
300    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
301    /* just executing this next line is probably faster that the if statement needed
302       to check whether we really need to execute it, and does no harm */
303    acc = FOLD_U32T(acc);
304    if (q->len % 2 != 0) {
305      swapped = 1 - swapped;
306      acc = SWAP_BYTES_IN_WORD(acc);
307    }
308    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
309  }
310
311  if (swapped) {
312    acc = SWAP_BYTES_IN_WORD(acc);
313  }
314  acc += (src->addr & 0xffffUL);
315  acc += ((src->addr >> 16) & 0xffffUL);
316  acc += (dest->addr & 0xffffUL);
317  acc += ((dest->addr >> 16) & 0xffffUL);
318  acc += (u32_t)htons((u16_t)proto);
319  acc += (u32_t)htons(proto_len);
320
321  /* Fold 32-bit sum to 16 bits
322     calling this twice is propably faster than if statements... */
323  acc = FOLD_U32T(acc);
324  acc = FOLD_U32T(acc);
325  LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
326  return (u16_t)~(acc & 0xffffUL);
327}
328
329/* inet_chksum_pseudo:
330 *
331 * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
332 * IP addresses are expected to be in network byte order.
333 *
334 * @param p chain of pbufs over that a checksum should be calculated (ip data part)
335 * @param src source ip address (used for checksum of pseudo header)
336 * @param dst destination ip address (used for checksum of pseudo header)
337 * @param proto ip protocol (used for checksum of pseudo header)
338 * @param proto_len length of the ip data part (used for checksum of pseudo header)
339 * @return checksum (as u16_t) to be saved directly in the protocol header
340 */
341/* Currently only used by UDPLITE, although this could change in the future. */
342#if LWIP_UDPLITE
343u16_t
344inet_chksum_pseudo_partial(struct pbuf *p,
345       struct ip_addr *src, struct ip_addr *dest,
346       u8_t proto, u16_t proto_len, u16_t chksum_len)
347{
348  u32_t acc;
349  struct pbuf *q;
350  u8_t swapped;
351  u16_t chklen;
352
353  acc = 0;
354  swapped = 0;
355  /* iterate through all pbuf in chain */
356  for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
357    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
358      (void *)q, (void *)q->next));
359    chklen = q->len;
360    if (chklen > chksum_len) {
361      chklen = chksum_len;
362    }
363    acc += LWIP_CHKSUM(q->payload, chklen);
364    chksum_len -= chklen;
365    LWIP_ASSERT("delete me", chksum_len < 0x7fff);
366    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
367    /* fold the upper bit down */
368    acc = FOLD_U32T(acc);
369    if (q->len % 2 != 0) {
370      swapped = 1 - swapped;
371      acc = SWAP_BYTES_IN_WORD(acc);
372    }
373    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
374  }
375
376  if (swapped) {
377    acc = SWAP_BYTES_IN_WORD(acc);
378  }
379  acc += (src->addr & 0xffffUL);
380  acc += ((src->addr >> 16) & 0xffffUL);
381  acc += (dest->addr & 0xffffUL);
382  acc += ((dest->addr >> 16) & 0xffffUL);
383  acc += (u32_t)htons((u16_t)proto);
384  acc += (u32_t)htons(proto_len);
385
386  /* Fold 32-bit sum to 16 bits
387     calling this twice is propably faster than if statements... */
388  acc = FOLD_U32T(acc);
389  acc = FOLD_U32T(acc);
390  LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
391  return (u16_t)~(acc & 0xffffUL);
392}
393#endif /* LWIP_UDPLITE */
394
395/* inet_chksum:
396 *
397 * Calculates the Internet checksum over a portion of memory. Used primarily for IP
398 * and ICMP.
399 *
400 * @param dataptr start of the buffer to calculate the checksum (no alignment needed)
401 * @param len length of the buffer to calculate the checksum
402 * @return checksum (as u16_t) to be saved directly in the protocol header
403 */
404
405u16_t
406inet_chksum(void *dataptr, u16_t len)
407{
408  return ~LWIP_CHKSUM(dataptr, len);
409}
410
411/**
412 * Calculate a checksum over a chain of pbufs (without pseudo-header, much like
413 * inet_chksum only pbufs are used).
414 *
415 * @param p pbuf chain over that the checksum should be calculated
416 * @return checksum (as u16_t) to be saved directly in the protocol header
417 */
418u16_t
419inet_chksum_pbuf(struct pbuf *p)
420{
421  u32_t acc;
422  struct pbuf *q;
423  u8_t swapped;
424
425  acc = 0;
426  swapped = 0;
427  for(q = p; q != NULL; q = q->next) {
428    acc += LWIP_CHKSUM(q->payload, q->len);
429    acc = FOLD_U32T(acc);
430    if (q->len % 2 != 0) {
431      swapped = 1 - swapped;
432      acc = SWAP_BYTES_IN_WORD(acc);
433    }
434  }
435
436  if (swapped) {
437    acc = SWAP_BYTES_IN_WORD(acc);
438  }
439  return (u16_t)~(acc & 0xffffUL);
440}
Note: See TracBrowser for help on using the repository browser.