Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


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