]> git.sur5r.net Git - freertos/blob - Demo/Common/ethernet/lwIP/core/inet.c
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@82 1d2547de-c912-0410-9cb9...
[freertos] / Demo / Common / ethernet / lwIP / core / inet.c
1 /*\r
2  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
3  * All rights reserved.\r
4  *\r
5  * Redistribution and use in source and binary forms, with or without modification,\r
6  * are permitted provided that the following conditions are met:\r
7  *\r
8  * 1. Redistributions of source code must retain the above copyright notice,\r
9  *    this list of conditions and the following disclaimer.\r
10  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
11  *    this list of conditions and the following disclaimer in the documentation\r
12  *    and/or other materials provided with the distribution.\r
13  * 3. The name of the author may not be used to endorse or promote products\r
14  *    derived from this software without specific prior written permission.\r
15  *\r
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
19  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
21  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
25  * OF SUCH DAMAGE.\r
26  *\r
27  * This file is part of the lwIP TCP/IP stack.\r
28  *\r
29  * Author: Adam Dunkels <adam@sics.se>\r
30  *\r
31  */\r
32 \r
33 \r
34 /* inet.c\r
35  *\r
36  * Functions common to all TCP/IP modules, such as the Internet checksum and the\r
37  * byte order functions.\r
38  *\r
39  */\r
40 \r
41 \r
42 #include "lwip/opt.h"\r
43 \r
44 #include "lwip/arch.h"\r
45 \r
46 #include "lwip/def.h"\r
47 #include "lwip/inet.h"\r
48 \r
49 #include "lwip/sys.h"\r
50 \r
51 /* These are some reference implementations of the checksum algorithm, with the\r
52  * aim of being simple, correct and fully portable. Checksumming is the\r
53  * first thing you would want to optimize for your platform. If you create\r
54  * your own version, link it in and in your sys_arch.h put:\r
55  * \r
56  * #define LWIP_CHKSUM <your_checksum_routine> \r
57 */\r
58 #ifndef LWIP_CHKSUM\r
59 #define LWIP_CHKSUM lwip_standard_chksum\r
60 \r
61 #if 1 /* Version A */\r
62 /**\r
63  * lwip checksum\r
64  *\r
65  * @param dataptr points to start of data to be summed at any boundary\r
66  * @param len length of data to be summed\r
67  * @return host order (!) lwip checksum (non-inverted Internet sum) \r
68  *\r
69  * @note accumulator size limits summable length to 64k\r
70  * @note host endianess is irrelevant (p3 RFC1071)\r
71  */\r
72 static u16_t\r
73 lwip_standard_chksum(void *dataptr, u16_t len)\r
74 {\r
75   u32_t acc;\r
76   u16_t src;\r
77   u8_t *octetptr;\r
78 \r
79   acc = 0;\r
80   /* dataptr may be at odd or even addresses */\r
81   octetptr = (u8_t*)dataptr;\r
82   while (len > 1)\r
83   {\r
84     /* declare first octet as most significant\r
85        thus assume network order, ignoring host order */\r
86     src = (*octetptr) << 8;\r
87     octetptr++;\r
88     /* declare second octet as least significant */\r
89     src |= (*octetptr);\r
90     octetptr++;\r
91     acc += src;\r
92     len -= 2;\r
93   }\r
94   if (len > 0)\r
95   {\r
96     /* accumulate remaining octet */\r
97     src = (*octetptr) << 8;\r
98     acc += src;\r
99   }\r
100   /* add deferred carry bits */\r
101   acc = (acc >> 16) + (acc & 0x0000ffffUL);\r
102   if ((acc & 0xffff0000) != 0) {\r
103     acc = (acc >> 16) + (acc & 0x0000ffffUL);\r
104   }\r
105   /* This maybe a little confusing: reorder sum using htons()\r
106      instead of ntohs() since it has a little less call overhead.\r
107      The caller must invert bits for Internet sum ! */\r
108   return htons((u16_t)acc);\r
109 }\r
110 #endif\r
111 \r
112 #if 0 /* Version B */\r
113 /*\r
114  * Curt McDowell\r
115  * Broadcom Corp.\r
116  * csm@broadcom.com\r
117  *\r
118  * IP checksum two bytes at a time with support for\r
119  * unaligned buffer.\r
120  * Works for len up to and including 0x20000.\r
121  * by Curt McDowell, Broadcom Corp. 12/08/2005\r
122  */\r
123 \r
124 static u16_t\r
125 lwip_standard_chksum(void *dataptr, int len)\r
126 {\r
127   u8_t *pb = dataptr;\r
128   u16_t *ps, t = 0;\r
129   u32_t sum = 0;\r
130   int odd = ((u32_t)pb & 1);\r
131 \r
132   /* Get aligned to u16_t */\r
133   if (odd && len > 0) {\r
134     ((u8_t *)&t)[1] = *pb++;\r
135     len--;\r
136   }\r
137 \r
138   /* Add the bulk of the data */\r
139   ps = (u16_t *)pb;\r
140   while (len > 1) {\r
141     sum += *ps++;\r
142     len -= 2;\r
143   }\r
144 \r
145   /* Consume left-over byte, if any */\r
146   if (len > 0)\r
147     ((u8_t *)&t)[0] = *(u8_t *)ps;;\r
148 \r
149   /* Add end bytes */\r
150   sum += t;\r
151 \r
152   /*  Fold 32-bit sum to 16 bits */\r
153   while (sum >> 16)\r
154     sum = (sum & 0xffff) + (sum >> 16);\r
155 \r
156   /* Swap if alignment was odd */\r
157   if (odd)\r
158     sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);\r
159 \r
160   return sum;\r
161 }\r
162 #endif\r
163 \r
164 #if 0 /* Version C */\r
165 /**\r
166  * An optimized checksum routine. Basically, it uses loop-unrolling on\r
167  * the checksum loop, treating the head and tail bytes specially, whereas\r
168  * the inner loop acts on 8 bytes at a time. \r
169  *\r
170  * @arg start of buffer to be checksummed. May be an odd byte address.\r
171  * @len number of bytes in the buffer to be checksummed.\r
172  * \r
173  * by Curt McDowell, Broadcom Corp. December 8th, 2005\r
174  */\r
175 \r
176 static u16_t\r
177 lwip_standard_chksum(void *dataptr, int len)\r
178 {\r
179   u8_t *pb = dataptr;\r
180   u16_t *ps, t = 0;\r
181   u32_t *pl;\r
182   u32_t sum = 0, tmp;\r
183   /* starts at odd byte address? */\r
184   int odd = ((u32_t)pb & 1);\r
185 \r
186   if (odd && len > 0) {\r
187     ((u8_t *)&t)[1] = *pb++;\r
188     len--;\r
189   }\r
190 \r
191   ps = (u16_t *)pb;\r
192 \r
193   if (((u32_t)ps & 3) && len > 1) {\r
194     sum += *ps++;\r
195     len -= 2;\r
196   }\r
197 \r
198   pl = (u32_t *)ps;\r
199 \r
200   while (len > 7)  {\r
201     tmp = sum + *pl++;          /* ping */\r
202     if (tmp < sum)\r
203       tmp++;                    /* add back carry */\r
204 \r
205     sum = tmp + *pl++;          /* pong */\r
206     if (sum < tmp)\r
207       sum++;                    /* add back carry */\r
208 \r
209     len -= 8;\r
210   }\r
211 \r
212   /* make room in upper bits */\r
213   sum = (sum >> 16) + (sum & 0xffff);\r
214 \r
215   ps = (u16_t *)pl;\r
216 \r
217   /* 16-bit aligned word remaining? */\r
218   while (len > 1) {\r
219     sum += *ps++;\r
220     len -= 2;\r
221   }\r
222 \r
223   /* dangling tail byte remaining? */\r
224   if (len > 0)                  /* include odd byte */\r
225     ((u8_t *)&t)[0] = *(u8_t *)ps;\r
226 \r
227   sum += t;                     /* add end bytes */\r
228 \r
229   while (sum >> 16)             /* combine halves */\r
230     sum = (sum >> 16) + (sum & 0xffff);\r
231 \r
232   if (odd)\r
233     sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);\r
234 \r
235   return sum;\r
236 }\r
237 #endif\r
238 \r
239 #endif /* LWIP_CHKSUM */\r
240 \r
241 /* inet_chksum_pseudo:\r
242  *\r
243  * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.\r
244  */\r
245 \r
246 u16_t\r
247 inet_chksum_pseudo(struct pbuf *p,\r
248        struct ip_addr *src, struct ip_addr *dest,\r
249        u8_t proto, u16_t proto_len)\r
250 {\r
251   u32_t acc;\r
252   struct pbuf *q;\r
253   u8_t swapped;\r
254 \r
255   acc = 0;\r
256   swapped = 0;\r
257   /* iterate through all pbuf in chain */\r
258   for(q = p; q != NULL; q = q->next) {\r
259     LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",\r
260       (void *)q, (void *)q->next));\r
261     acc += LWIP_CHKSUM(q->payload, q->len);\r
262     /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/\r
263     while (acc >> 16) {\r
264       acc = (acc & 0xffffUL) + (acc >> 16);\r
265     }\r
266     if (q->len % 2 != 0) {\r
267       swapped = 1 - swapped;\r
268       acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);\r
269     }\r
270     /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/\r
271   }\r
272 \r
273   if (swapped) {\r
274     acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);\r
275   }\r
276   acc += (src->addr & 0xffffUL);\r
277   acc += ((src->addr >> 16) & 0xffffUL);\r
278   acc += (dest->addr & 0xffffUL);\r
279   acc += ((dest->addr >> 16) & 0xffffUL);\r
280   acc += (u32_t)htons((u16_t)proto);\r
281   acc += (u32_t)htons(proto_len);\r
282 \r
283   while (acc >> 16) {\r
284     acc = (acc & 0xffffUL) + (acc >> 16);\r
285   }\r
286   LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));\r
287   return (u16_t)~(acc & 0xffffUL);\r
288 }\r
289 \r
290 /* inet_chksum:\r
291  *\r
292  * Calculates the Internet checksum over a portion of memory. Used primarily for IP\r
293  * and ICMP.\r
294  */\r
295 \r
296 u16_t\r
297 inet_chksum(void *dataptr, u16_t len)\r
298 {\r
299   u32_t acc;\r
300 \r
301   acc = LWIP_CHKSUM(dataptr, len);\r
302   while (acc >> 16) {\r
303     acc = (acc & 0xffff) + (acc >> 16);\r
304   }\r
305   return (u16_t)~(acc & 0xffff);\r
306 }\r
307 \r
308 u16_t\r
309 inet_chksum_pbuf(struct pbuf *p)\r
310 {\r
311   u32_t acc;\r
312   struct pbuf *q;\r
313   u8_t swapped;\r
314 \r
315   acc = 0;\r
316   swapped = 0;\r
317   for(q = p; q != NULL; q = q->next) {\r
318     acc += LWIP_CHKSUM(q->payload, q->len);\r
319     while (acc >> 16) {\r
320       acc = (acc & 0xffffUL) + (acc >> 16);\r
321     }\r
322     if (q->len % 2 != 0) {\r
323       swapped = 1 - swapped;\r
324       acc = (acc & 0x00ffUL << 8) | (acc & 0xff00UL >> 8);\r
325     }\r
326   }\r
327 \r
328   if (swapped) {\r
329     acc = ((acc & 0x00ffUL) << 8) | ((acc & 0xff00UL) >> 8);\r
330   }\r
331   return (u16_t)~(acc & 0xffffUL);\r
332 }\r
333 \r
334 /* Here for now until needed in other places in lwIP */\r
335 #ifndef isprint\r
336 #define in_range(c, lo, up)  ((u8_t)c >= lo && (u8_t)c <= up)\r
337 #define isprint(c)           in_range(c, 0x20, 0x7f)\r
338 #define isdigit(c)           in_range(c, '0', '9')\r
339 #define isxdigit(c)          (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))\r
340 #define islower(c)           in_range(c, 'a', 'z')\r
341 #define isspace(c)           (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')\r
342 #endif    \r
343     \r
344 /*\r
345  * Ascii internet address interpretation routine.\r
346  * The value returned is in network order.\r
347  */\r
348 \r
349 u32_t\r
350 inet_addr(const char *cp)\r
351 {\r
352   struct in_addr val;\r
353 \r
354   if (inet_aton(cp, &val)) {\r
355     return (val.s_addr);\r
356   }\r
357   return (INADDR_NONE);\r
358 }\r
359 \r
360 /*\r
361  * Check whether "cp" is a valid ascii representation\r
362  * of an Internet address and convert to a binary address.\r
363  * Returns 1 if the address is valid, 0 if not.\r
364  * This replaces inet_addr, the return value from which\r
365  * cannot distinguish between failure and a local broadcast address.\r
366  */\r
367 int\r
368 inet_aton(const char *cp, struct in_addr *addr)\r
369 {\r
370   u32_t val;\r
371   int base, n, c;\r
372   u32_t parts[4];\r
373   u32_t *pp = parts;\r
374 \r
375   c = *cp;\r
376   for (;;) {\r
377     /*\r
378      * Collect number up to ``.''.\r
379      * Values are specified as for C:\r
380      * 0x=hex, 0=octal, 1-9=decimal.\r
381      */\r
382     if (!isdigit(c))\r
383       return (0);\r
384     val = 0;\r
385     base = 10;\r
386     if (c == '0') {\r
387       c = *++cp;\r
388       if (c == 'x' || c == 'X') {\r
389         base = 16;\r
390         c = *++cp;\r
391       } else\r
392         base = 8;\r
393     }\r
394     for (;;) {\r
395       if (isdigit(c)) {\r
396         val = (val * base) + (int)(c - '0');\r
397         c = *++cp;\r
398       } else if (base == 16 && isxdigit(c)) {\r
399         val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));\r
400         c = *++cp;\r
401       } else\r
402         break;\r
403     }\r
404     if (c == '.') {\r
405       /*\r
406        * Internet format:\r
407        *  a.b.c.d\r
408        *  a.b.c   (with c treated as 16 bits)\r
409        *  a.b (with b treated as 24 bits)\r
410        */\r
411       if (pp >= parts + 3)\r
412         return (0);\r
413       *pp++ = val;\r
414       c = *++cp;\r
415     } else\r
416       break;\r
417   }\r
418   /*\r
419    * Check for trailing characters.\r
420    */\r
421   if (c != '\0' && (!isprint(c) || !isspace(c)))\r
422     return (0);\r
423   /*\r
424    * Concoct the address according to\r
425    * the number of parts specified.\r
426    */\r
427   n = pp - parts + 1;\r
428   switch (n) {\r
429 \r
430   case 0:\r
431     return (0);       /* initial nondigit */\r
432 \r
433   case 1:             /* a -- 32 bits */\r
434     break;\r
435 \r
436   case 2:             /* a.b -- 8.24 bits */\r
437     if (val > 0xffffff)\r
438       return (0);\r
439     val |= parts[0] << 24;\r
440     break;\r
441 \r
442   case 3:             /* a.b.c -- 8.8.16 bits */\r
443     if (val > 0xffff)\r
444       return (0);\r
445     val |= (parts[0] << 24) | (parts[1] << 16);\r
446     break;\r
447 \r
448   case 4:             /* a.b.c.d -- 8.8.8.8 bits */\r
449     if (val > 0xff)\r
450       return (0);\r
451     val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);\r
452     break;\r
453   }\r
454   if (addr)\r
455     addr->s_addr = htonl(val);\r
456   return (1);\r
457 }\r
458 \r
459 /* Convert numeric IP address into decimal dotted ASCII representation.\r
460  * returns ptr to static buffer; not reentrant!\r
461  */\r
462 char *\r
463 inet_ntoa(struct in_addr addr)\r
464 {\r
465   static char str[16];\r
466   u32_t s_addr = addr.s_addr;\r
467   char inv[3];\r
468   char *rp;\r
469   u8_t *ap;\r
470   u8_t rem;\r
471   u8_t n;\r
472   u8_t i;\r
473 \r
474   rp = str;\r
475   ap = (u8_t *)&s_addr;\r
476   for(n = 0; n < 4; n++) {\r
477     i = 0;\r
478     do {\r
479       rem = *ap % (u8_t)10;\r
480       *ap /= (u8_t)10;\r
481       inv[i++] = '0' + rem;\r
482     } while(*ap);\r
483     while(i--)\r
484       *rp++ = inv[i];\r
485     *rp++ = '.';\r
486     ap++;\r
487   }\r
488   *--rp = 0;\r
489   return str;\r
490 }\r
491 \r
492 /*\r
493  * These are reference implementations of the byte swapping functions.\r
494  * Again with the aim of being simple, correct and fully portable.\r
495  * Byte swapping is the second thing you would want to optimize. You will\r
496  * need to port it to your architecture and in your cc.h:\r
497  * \r
498  * #define LWIP_PLATFORM_BYTESWAP 1\r
499  * #define LWIP_PLATFORM_HTONS(x) <your_htons>\r
500  * #define LWIP_PLATFORM_HTONL(x) <your_htonl>\r
501  *\r
502  * Note ntohs() and ntohl() are merely references to the htonx counterparts.\r
503  */\r
504 \r
505 #ifndef BYTE_ORDER\r
506 #error BYTE_ORDER is not defined\r
507 #endif\r
508 #if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)\r
509 \r
510 u16_t\r
511 htons(u16_t n)\r
512 {\r
513   return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);\r
514 }\r
515 \r
516 u16_t\r
517 ntohs(u16_t n)\r
518 {\r
519   return htons(n);\r
520 }\r
521 \r
522 u32_t\r
523 htonl(u32_t n)\r
524 {\r
525   return ((n & 0xff) << 24) |\r
526     ((n & 0xff00) << 8) |\r
527     ((n & 0xff0000) >> 8) |\r
528     ((n & 0xff000000) >> 24);\r
529 }\r
530 \r
531 u32_t\r
532 ntohl(u32_t n)\r
533 {\r
534   return htonl(n);\r
535 }\r
536 \r
537 #endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */\r