]> git.sur5r.net Git - freertos/blob - Demo/Common/ethernet/FreeRTOS-uIP/uip.c
Remove compiler warning.
[freertos] / Demo / Common / ethernet / FreeRTOS-uIP / uip.c
1 #define DEBUG_PRINTF( ... )             /*printf(__VA_ARGS__)*/\r
2 \r
3 /**\r
4  * \defgroup uip The uIP TCP/IP stack\r
5  * @{\r
6  *\r
7  * uIP is an implementation of the TCP/IP protocol stack intended for\r
8  * small 8-bit and 16-bit microcontrollers.\r
9  *\r
10  * uIP provides the necessary protocols for Internet communication,\r
11  * with a very small code footprint and RAM requirements - the uIP\r
12  * code size is on the order of a few kilobytes and RAM usage is on\r
13  * the order of a few hundred bytes.\r
14  */\r
15 \r
16 /**\r
17  * \file\r
18  * The uIP TCP/IP stack code.\r
19  * \author Adam Dunkels <adam@dunkels.com>\r
20  */\r
21 \r
22 /*\r
23  * Copyright (c) 2001-2003, Adam Dunkels.\r
24  * All rights reserved.\r
25  *\r
26  * Redistribution and use in source and binary forms, with or without\r
27  * modification, are permitted provided that the following conditions\r
28  * are met:\r
29  * 1. Redistributions of source code must retain the above copyright\r
30  *    notice, this list of conditions and the following disclaimer.\r
31  * 2. Redistributions in binary form must reproduce the above copyright\r
32  *    notice, this list of conditions and the following disclaimer in the\r
33  *    documentation and/or other materials provided with the distribution.\r
34  * 3. The name of the author may not be used to endorse or promote\r
35  *    products derived from this software without specific prior\r
36  *    written permission.\r
37  *\r
38  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS\r
39  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
40  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
41  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\r
42  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
43  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\r
44  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
45  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
46  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
47  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
48  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
49  *\r
50  * This file is part of the uIP TCP/IP stack.\r
51  *\r
52  * $Id: uip.c,v 1.65 2006/06/11 21:46:39 adam Exp $\r
53  *\r
54  */\r
55 \r
56 /*\r
57  * uIP is a small implementation of the IP, UDP and TCP protocols (as\r
58  * well as some basic ICMP stuff). The implementation couples the IP,\r
59  * UDP, TCP and the application layers very tightly. To keep the size\r
60  * of the compiled code down, this code frequently uses the goto\r
61  * statement. While it would be possible to break the uip_process()\r
62  * function into many smaller functions, this would increase the code\r
63  * size because of the overhead of parameter passing and the fact that\r
64  * the optimier would not be as efficient.\r
65  *\r
66  * The principle is that we have a small buffer, called the uip_buf,\r
67  * in which the device driver puts an incoming packet. The TCP/IP\r
68  * stack parses the headers in the packet, and calls the\r
69  * application. If the remote host has sent data to the application,\r
70  * this data is present in the uip_buf and the application read the\r
71  * data from there. It is up to the application to put this data into\r
72  * a byte stream if needed. The application will not be fed with data\r
73  * that is out of sequence.\r
74  *\r
75  * If the application whishes to send data to the peer, it should put\r
76  * its data into the uip_buf. The uip_appdata pointer points to the\r
77  * first available byte. The TCP/IP stack will calculate the\r
78  * checksums, and fill in the necessary header fields and finally send\r
79  * the packet back to the peer.\r
80 */\r
81 #include "uip.h"\r
82 #include "uipopt.h"\r
83 #include "uip_arch.h"\r
84 #include "uip_arp.h"\r
85 #include "FreeRTOS.h"\r
86 \r
87 #if UIP_CONF_IPV6\r
88         #include "uip-neighbor.h"\r
89 #endif /* UIP_CONF_IPV6 */\r
90 \r
91 #include <string.h>\r
92 \r
93 /*---------------------------------------------------------------------------*/\r
94 \r
95 /* Variable definitions. */\r
96 \r
97 /* The IP address of this host. If it is defined to be fixed (by\r
98    setting UIP_FIXEDADDR to 1 in uipopt.h), the address is set\r
99    here. Otherwise, the address */\r
100 #if UIP_FIXEDADDR > 0\r
101 const uip_ipaddr_t                      uip_hostaddr = { HTONS( (UIP_IPADDR0 << 8) | UIP_IPADDR1 ), HTONS( (UIP_IPADDR2 << 8) | UIP_IPADDR3 ) };\r
102 const uip_ipaddr_t                      uip_draddr = { HTONS( (UIP_DRIPADDR0 << 8) | UIP_DRIPADDR1 ), HTONS( (UIP_DRIPADDR2 << 8) | UIP_DRIPADDR3 ) };\r
103 const uip_ipaddr_t                      uip_netmask = { HTONS( (UIP_NETMASK0 << 8) | UIP_NETMASK1 ), HTONS( (UIP_NETMASK2 << 8) | UIP_NETMASK3 ) };\r
104 #else\r
105 uip_ipaddr_t                            uip_hostaddr, uip_draddr, uip_netmask;\r
106 #endif /* UIP_FIXEDADDR */\r
107 \r
108 static const uip_ipaddr_t       all_ones_addr =\r
109 #if UIP_CONF_IPV6\r
110 { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff };\r
111 #else /* UIP_CONF_IPV6 */\r
112 {\r
113         0xffff, 0xffff\r
114 };\r
115 #endif /* UIP_CONF_IPV6 */\r
116 static const uip_ipaddr_t       all_zeroes_addr =\r
117 #if UIP_CONF_IPV6\r
118 { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };\r
119 #else /* UIP_CONF_IPV6 */\r
120 {\r
121         0x0000, 0x0000\r
122 };\r
123 #endif /* UIP_CONF_IPV6 */\r
124 \r
125 #if UIP_FIXEDETHADDR\r
126 const struct uip_eth_addr       uip_ethaddr = { { UIP_ETHADDR0, UIP_ETHADDR1, UIP_ETHADDR2, UIP_ETHADDR3, UIP_ETHADDR4, UIP_ETHADDR5 } };\r
127 #else\r
128 struct uip_eth_addr                     uip_ethaddr = { { 0, 0, 0, 0, 0, 0 } };\r
129 #endif\r
130 #ifndef UIP_CONF_EXTERNAL_BUFFER\r
131         #ifdef __ICCARM__\r
132                 #pragma data_alignment = 4\r
133 u8_t uip_buf[UIP_BUFSIZE + 2];  /* The packet buffer that contains incoming packets. */\r
134         #else\r
135 u8_t                            uip_buf[UIP_BUFSIZE + 2] ALIGN_STRUCT_END;      /* The packet buffer that contains incoming packets. */\r
136         #endif\r
137 #endif /* UIP_CONF_EXTERNAL_BUFFER */\r
138 \r
139 void                            *uip_appdata;                           /* The uip_appdata pointer points to\r
140                                     application data. */\r
141 void                            *uip_sappdata;                          /* The uip_appdata pointer points to\r
142                                     the application data which is to\r
143                                     be sent. */\r
144 #if UIP_URGDATA > 0\r
145 void                            *uip_urgdata;                           /* The uip_urgdata pointer points to\r
146                                     urgent data (out-of-band data), if\r
147                                     present. */\r
148 u16_t                           uip_urglen, uip_surglen;\r
149 #endif /* UIP_URGDATA > 0 */\r
150 \r
151 u16_t                           uip_len, uip_slen;\r
152 \r
153 /* The uip_len is either 8 or 16 bits,\r
154                                 depending on the maximum packet\r
155                                 size. */\r
156 u8_t                            uip_flags;                                      /* The uip_flags variable is used for\r
157                                 communication between the TCP/IP stack\r
158                                 and the application program. */\r
159 struct uip_conn         *uip_conn;                                      /* uip_conn always points to the current\r
160                                 connection. */\r
161 \r
162 struct uip_conn         uip_conns[UIP_CONNS];\r
163 \r
164 /* The uip_conns array holds all TCP\r
165                                 connections. */\r
166 u16_t                           uip_listenports[UIP_LISTENPORTS];\r
167 \r
168 /* The uip_listenports list all currently\r
169                                 listning ports. */\r
170 #if UIP_UDP\r
171 struct uip_udp_conn *uip_udp_conn;\r
172 struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];\r
173 #endif /* UIP_UDP */\r
174 \r
175 static u16_t            ipid;                                           /* Ths ipid variable is an increasing\r
176                                 number that is used for the IP ID\r
177                                 field. */\r
178 \r
179 void uip_setipid( u16_t id )\r
180 {\r
181         ipid = id;\r
182 }\r
183 \r
184 static u8_t             iss[4];                                                 /* The iss variable is used for the TCP\r
185                                 initial sequence number. */\r
186 \r
187 #if UIP_ACTIVE_OPEN\r
188 static u16_t    lastport;                                               /* Keeps track of the last port used for\r
189                                 a new connection. */\r
190 #endif /* UIP_ACTIVE_OPEN */\r
191 \r
192 /* Temporary variables. */\r
193 u8_t                    uip_acc32[4];\r
194 static u8_t             c, opt;\r
195 static u16_t    tmp16;\r
196 \r
197 /* Structures and definitions. */\r
198 #define TCP_FIN                                                         0x01\r
199 #define TCP_SYN                                                         0x02\r
200 #define TCP_RST                                                         0x04\r
201 #define TCP_PSH                                                         0x08\r
202 #define TCP_ACK                                                         0x10\r
203 #define TCP_URG                                                         0x20\r
204 #define TCP_CTL                                                         0x3f\r
205 \r
206 #define TCP_OPT_END                                                     0       /* End of TCP options list */\r
207 #define TCP_OPT_NOOP                                            1       /* "No-operation" TCP option */\r
208 #define TCP_OPT_MSS                                                     2       /* Maximum segment size TCP option */\r
209 \r
210 #define TCP_OPT_MSS_LEN                                         4       /* Length of TCP MSS option. */\r
211 \r
212 #define ICMP_ECHO_REPLY                                         0\r
213 #define ICMP_ECHO                                                       8\r
214 \r
215 #define ICMP6_ECHO_REPLY                                        129\r
216 #define ICMP6_ECHO                                                      128\r
217 #define ICMP6_NEIGHBOR_SOLICITATION                     135\r
218 #define ICMP6_NEIGHBOR_ADVERTISEMENT            136\r
219 \r
220 #define ICMP6_FLAG_S                                            ( 1 << 6 )\r
221 #define ICMP6_OPTION_SOURCE_LINK_ADDRESS        1\r
222 #define ICMP6_OPTION_TARGET_LINK_ADDRESS        2\r
223 \r
224 /* Macros. */\r
225 #define BUF             ( ( struct uip_tcpip_hdr * ) &uip_buf[UIP_LLH_LEN] )\r
226 #define FBUF    ( ( struct uip_tcpip_hdr * ) &uip_reassbuf[0] )\r
227 #define ICMPBUF ( ( struct uip_icmpip_hdr * ) &uip_buf[UIP_LLH_LEN] )\r
228 #define UDPBUF  ( ( struct uip_udpip_hdr * ) &uip_buf[UIP_LLH_LEN] )\r
229 #if UIP_STATISTICS == 1\r
230 struct uip_stats        uip_stat;\r
231         #define UIP_STAT( s )   s\r
232 #else\r
233         #define UIP_STAT( s )\r
234 #endif /* UIP_STATISTICS == 1 */\r
235 \r
236 #if UIP_LOGGING == 1\r
237         #include <stdio.h>\r
238 void    uip_log( char *msg );\r
239         #define UIP_LOG( m )    uip_log( m )\r
240 #else\r
241         #define UIP_LOG( m )\r
242 #endif /* UIP_LOGGING == 1 */\r
243 \r
244 #if !UIP_ARCH_ADD32\r
245 void uip_add32( u8_t *op32, u16_t op16 )\r
246 {\r
247         uip_acc32[3] = op32[3] + ( op16 & 0xff );\r
248         uip_acc32[2] = op32[2] + ( op16 >> 8 );\r
249         uip_acc32[1] = op32[1];\r
250         uip_acc32[0] = op32[0];\r
251 \r
252         if( uip_acc32[2] < (op16 >> 8) )\r
253         {\r
254                 ++uip_acc32[1];\r
255                 if( uip_acc32[1] == 0 )\r
256                 {\r
257                         ++uip_acc32[0];\r
258                 }\r
259         }\r
260 \r
261         if( uip_acc32[3] < (op16 & 0xff) )\r
262         {\r
263                 ++uip_acc32[2];\r
264                 if( uip_acc32[2] == 0 )\r
265                 {\r
266                         ++uip_acc32[1];\r
267                         if( uip_acc32[1] == 0 )\r
268                         {\r
269                                 ++uip_acc32[0];\r
270                         }\r
271                 }\r
272         }\r
273 }\r
274 \r
275 #endif /* UIP_ARCH_ADD32 */\r
276 \r
277 #if !UIP_ARCH_CHKSUM\r
278 \r
279 /*---------------------------------------------------------------------------*/\r
280 static u16_t chksum( u16_t sum, const u8_t *data, u16_t len )\r
281 {\r
282         u16_t           t;\r
283         const u8_t      *dataptr;\r
284         const u8_t      *last_byte;\r
285 \r
286         dataptr = data;\r
287         last_byte = data + len - 1;\r
288 \r
289         while( dataptr < last_byte )\r
290         {                               /* At least two more bytes */\r
291                 t = ( dataptr[0] << 8 ) + dataptr[1];\r
292                 sum += t;\r
293                 if( sum < t )\r
294                 {\r
295                         sum++;  /* carry */\r
296                 }\r
297 \r
298                 dataptr += 2;\r
299         }\r
300 \r
301         if( dataptr == last_byte )\r
302         {\r
303                 t = ( dataptr[0] << 8 ) + 0;\r
304                 sum += t;\r
305                 if( sum < t )\r
306                 {\r
307                         sum++;  /* carry */\r
308                 }\r
309         }\r
310 \r
311         /* Return sum in host byte order. */\r
312         return sum;\r
313 }\r
314 \r
315 /*---------------------------------------------------------------------------*/\r
316 u16_t uip_chksum( u16_t *data, u16_t len )\r
317 {\r
318         return htons( chksum(0, ( u8_t * ) data, len) );\r
319 }\r
320 \r
321 /*---------------------------------------------------------------------------*/\r
322         #ifndef UIP_ARCH_IPCHKSUM\r
323 u16_t uip_ipchksum( void )\r
324 {\r
325         u16_t   sum;\r
326 \r
327         sum = chksum( 0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN );\r
328         DEBUG_PRINTF( "uip_ipchksum: sum 0x%04x\n", sum );\r
329         return( sum == 0 ) ? 0xffff : htons( sum );\r
330 }\r
331 \r
332         #endif\r
333 \r
334 /*---------------------------------------------------------------------------*/\r
335 static u16_t upper_layer_chksum( u8_t proto )\r
336 {\r
337         u16_t   upper_layer_len;\r
338         u16_t   sum;\r
339 \r
340                 #if UIP_CONF_IPV6\r
341         upper_layer_len = ( ((u16_t) (BUF->len[0]) << 8) + BUF->len[1] );\r
342                 #else /* UIP_CONF_IPV6 */\r
343         upper_layer_len = ( ((u16_t) (BUF->len[0]) << 8) + BUF->len[1] ) - UIP_IPH_LEN;\r
344                 #endif /* UIP_CONF_IPV6 */\r
345 \r
346         /* First sum pseudoheader. */\r
347 \r
348         /* IP protocol and length fields. This addition cannot carry. */\r
349         sum = upper_layer_len + proto;\r
350 \r
351         /* Sum IP source and destination addresses. */\r
352         sum = chksum( sum, ( u8_t * ) &BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t) );\r
353 \r
354         /* Sum TCP header and data. */\r
355         sum = chksum( sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_len );\r
356 \r
357         return( sum == 0 ) ? 0xffff : htons( sum );\r
358 }\r
359 \r
360 /*---------------------------------------------------------------------------*/\r
361         #if UIP_CONF_IPV6\r
362 u16_t uip_icmp6chksum( void )\r
363 {\r
364         return upper_layer_chksum( UIP_PROTO_ICMP6 );\r
365 }\r
366 \r
367         #endif /* UIP_CONF_IPV6 */\r
368 \r
369 /*---------------------------------------------------------------------------*/\r
370 u16_t uip_tcpchksum( void )\r
371 {\r
372         return upper_layer_chksum( UIP_PROTO_TCP );\r
373 }\r
374 \r
375 /*---------------------------------------------------------------------------*/\r
376         #if UIP_UDP_CHECKSUMS\r
377 u16_t uip_udpchksum( void )\r
378 {\r
379         return upper_layer_chksum( UIP_PROTO_UDP );\r
380 }\r
381 \r
382         #endif /* UIP_UDP_CHECKSUMS */\r
383 #endif /* UIP_ARCH_CHKSUM */\r
384 \r
385 /*---------------------------------------------------------------------------*/\r
386 void uip_init( void )\r
387 {\r
388         for( c = 0; c < UIP_LISTENPORTS; ++c )\r
389         {\r
390                 uip_listenports[c] = 0;\r
391         }\r
392 \r
393         for( c = 0; c < UIP_CONNS; ++c )\r
394         {\r
395                 uip_conns[c].tcpstateflags = UIP_CLOSED;\r
396         }\r
397 \r
398         #if UIP_ACTIVE_OPEN\r
399         lastport = 1024;\r
400         #endif /* UIP_ACTIVE_OPEN */\r
401 \r
402         #if UIP_UDP\r
403         for( c = 0; c < UIP_UDP_CONNS; ++c )\r
404         {\r
405                 uip_udp_conns[c].lport = 0;\r
406         }\r
407 \r
408         #endif /* UIP_UDP */\r
409 \r
410         /* IPv4 initialization. */\r
411         #if UIP_FIXEDADDR == 0\r
412 \r
413         /*  uip_hostaddr[0] = uip_hostaddr[1] = 0;*/\r
414         #endif /* UIP_FIXEDADDR */\r
415 }\r
416 \r
417 /*---------------------------------------------------------------------------*/\r
418 #if UIP_ACTIVE_OPEN\r
419 struct uip_conn *uip_connect( uip_ipaddr_t *ripaddr, u16_t rport )\r
420 {\r
421         register struct uip_conn        *conn, *cconn;\r
422 \r
423         /* Find an unused local port. */\r
424 again:\r
425         ++lastport;\r
426 \r
427         if( lastport >= 32000 )\r
428         {\r
429                 lastport = 4096;\r
430         }\r
431 \r
432         /* Check if this port is already in use, and if so try to find\r
433      another one. */\r
434         for( c = 0; c < UIP_CONNS; ++c )\r
435         {\r
436                 conn = &uip_conns[c];\r
437                 if( conn->tcpstateflags != UIP_CLOSED && conn->lport == htons(lastport) )\r
438                 {\r
439                         goto again;\r
440                 }\r
441         }\r
442 \r
443         conn = 0;\r
444         for( c = 0; c < UIP_CONNS; ++c )\r
445         {\r
446                 cconn = &uip_conns[c];\r
447                 if( cconn->tcpstateflags == UIP_CLOSED )\r
448                 {\r
449                         conn = cconn;\r
450                         break;\r
451                 }\r
452 \r
453                 if( cconn->tcpstateflags == UIP_TIME_WAIT )\r
454                 {\r
455                         if( conn == 0 || cconn->timer > conn->timer )\r
456                         {\r
457                                 conn = cconn;\r
458                         }\r
459                 }\r
460         }\r
461 \r
462         if( conn == 0 )\r
463         {\r
464                 return 0;\r
465         }\r
466 \r
467         conn->tcpstateflags = UIP_SYN_SENT;\r
468 \r
469         conn->snd_nxt[0] = iss[0];\r
470         conn->snd_nxt[1] = iss[1];\r
471         conn->snd_nxt[2] = iss[2];\r
472         conn->snd_nxt[3] = iss[3];\r
473 \r
474         conn->initialmss = conn->mss = UIP_TCP_MSS;\r
475 \r
476         conn->len = 1;          /* TCP length of the SYN is one. */\r
477         conn->nrtx = 0;\r
478         conn->timer = 1;        /* Send the SYN next time around. */\r
479         conn->rto = UIP_RTO;\r
480         conn->sa = 0;\r
481         conn->sv = 16;          /* Initial value of the RTT variance. */\r
482         conn->lport = htons( lastport );\r
483         conn->rport = rport;\r
484         uip_ipaddr_copy( &conn->ripaddr, ripaddr );\r
485 \r
486         return conn;\r
487 }\r
488 \r
489 #endif /* UIP_ACTIVE_OPEN */\r
490 \r
491 /*---------------------------------------------------------------------------*/\r
492 #if UIP_UDP\r
493 struct uip_udp_conn *uip_udp_new( uip_ipaddr_t *ripaddr, u16_t rport )\r
494 {\r
495         register struct uip_udp_conn    *conn;\r
496 \r
497         /* Find an unused local port. */\r
498 again:\r
499         ++lastport;\r
500 \r
501         if( lastport >= 32000 )\r
502         {\r
503                 lastport = 4096;\r
504         }\r
505 \r
506         for( c = 0; c < UIP_UDP_CONNS; ++c )\r
507         {\r
508                 if( uip_udp_conns[c].lport == htons(lastport) )\r
509                 {\r
510                         goto again;\r
511                 }\r
512         }\r
513 \r
514         conn = 0;\r
515         for( c = 0; c < UIP_UDP_CONNS; ++c )\r
516         {\r
517                 if( uip_udp_conns[c].lport == 0 )\r
518                 {\r
519                         conn = &uip_udp_conns[c];\r
520                         break;\r
521                 }\r
522         }\r
523 \r
524         if( conn == 0 )\r
525         {\r
526                 return 0;\r
527         }\r
528 \r
529         conn->lport = HTONS( lastport );\r
530         conn->rport = rport;\r
531         if( ripaddr == NULL )\r
532         {\r
533                 memset( conn->ripaddr, 0, sizeof(uip_ipaddr_t) );\r
534         }\r
535         else\r
536         {\r
537                 uip_ipaddr_copy( &conn->ripaddr, ripaddr );\r
538         }\r
539 \r
540         conn->ttl = UIP_TTL;\r
541 \r
542         return conn;\r
543 }\r
544 \r
545 #endif /* UIP_UDP */\r
546 \r
547 /*---------------------------------------------------------------------------*/\r
548 void uip_unlisten( u16_t port )\r
549 {\r
550         for( c = 0; c < UIP_LISTENPORTS; ++c )\r
551         {\r
552                 if( uip_listenports[c] == port )\r
553                 {\r
554                         uip_listenports[c] = 0;\r
555                         return;\r
556                 }\r
557         }\r
558 }\r
559 \r
560 /*---------------------------------------------------------------------------*/\r
561 void uip_listen( u16_t port )\r
562 {\r
563         for( c = 0; c < UIP_LISTENPORTS; ++c )\r
564         {\r
565                 if( uip_listenports[c] == 0 )\r
566                 {\r
567                         uip_listenports[c] = port;\r
568                         return;\r
569                 }\r
570         }\r
571 }\r
572 \r
573 /*---------------------------------------------------------------------------*/\r
574 \r
575 /* XXX: IP fragment reassembly: not well-tested. */\r
576 #if UIP_REASSEMBLY && !UIP_CONF_IPV6\r
577         #define UIP_REASS_BUFSIZE       ( UIP_BUFSIZE - UIP_LLH_LEN )\r
578 static u8_t                     uip_reassbuf[UIP_REASS_BUFSIZE];\r
579 static u8_t                     uip_reassbitmap[UIP_REASS_BUFSIZE / ( 8 * 8 )];\r
580 static const u8_t       bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };\r
581 static u16_t            uip_reasslen;\r
582 static u8_t                     uip_reassflags;\r
583         #define UIP_REASS_FLAG_LASTFRAG 0x01\r
584 static u8_t                     uip_reasstmr;\r
585 \r
586         #define IP_MF   0x20\r
587 \r
588 static u8_t uip_reass( void )\r
589 {\r
590         u16_t   offset, len;\r
591         u16_t   i;\r
592 \r
593         /* If ip_reasstmr is zero, no packet is present in the buffer, so we\r
594      write the IP header of the fragment into the reassembly\r
595      buffer. The timer is updated with the maximum age. */\r
596         if( uip_reasstmr == 0 )\r
597         {\r
598                 memcpy( uip_reassbuf, &BUF->vhl, UIP_IPH_LEN );\r
599                 uip_reasstmr = UIP_REASS_MAXAGE;\r
600                 uip_reassflags = 0;\r
601 \r
602                 /* Clear the bitmap. */\r
603                 memset( uip_reassbitmap, 0, sizeof(uip_reassbitmap) );\r
604         }\r
605 \r
606         /* Check if the incoming fragment matches the one currently present\r
607      in the reasembly buffer. If so, we proceed with copying the\r
608      fragment into the buffer. */\r
609         if\r
610         (\r
611                 BUF->srcipaddr[0] == FBUF->srcipaddr[0] &&\r
612                 BUF->srcipaddr[1] == FBUF->srcipaddr[1] &&\r
613                 BUF->destipaddr[0] == FBUF->destipaddr[0] &&\r
614                 BUF->destipaddr[1] == FBUF->destipaddr[1] &&\r
615                 BUF->ipid[0] == FBUF->ipid[0] &&\r
616                 BUF->ipid[1] == FBUF->ipid[1]\r
617         )\r
618         {\r
619                 len = ( BUF->len[0] << 8 ) + BUF->len[1] - ( BUF->vhl & 0x0f ) * 4;\r
620                 offset = ( ((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1] ) * 8;\r
621 \r
622                 /* If the offset or the offset + fragment length overflows the\r
623        reassembly buffer, we discard the entire packet. */\r
624                 if( offset > UIP_REASS_BUFSIZE || offset + len > UIP_REASS_BUFSIZE )\r
625                 {\r
626                         uip_reasstmr = 0;\r
627                         goto nullreturn;\r
628                 }\r
629 \r
630                 /* Copy the fragment into the reassembly buffer, at the right\r
631        offset. */\r
632                 memcpy( &uip_reassbuf[UIP_IPH_LEN + offset], ( char * ) BUF + ( int ) ((BUF->vhl & 0x0f) * 4), len );\r
633 \r
634                 /* Update the bitmap. */\r
635                 if( offset / (8 * 8) == (offset + len) / (8 * 8) )\r
636                 {\r
637                         /* If the two endpoints are in the same byte, we only update\r
638          that byte. */\r
639                         uip_reassbitmap[offset / ( 8 * 8 )] |= bitmap_bits[( offset / 8 ) & 7] &~bitmap_bits[( (offset + len) / 8 ) & 7];\r
640                 }\r
641                 else\r
642                 {\r
643                         /* If the two endpoints are in different bytes, we update the\r
644          bytes in the endpoints and fill the stuff inbetween with\r
645          0xff. */\r
646                         uip_reassbitmap[offset / ( 8 * 8 )] |= bitmap_bits[( offset / 8 ) & 7];\r
647                         for( i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i )\r
648                         {\r
649                                 uip_reassbitmap[i] = 0xff;\r
650                         }\r
651 \r
652                         uip_reassbitmap[( offset + len ) / ( 8 * 8 )] |= ~bitmap_bits[( (offset + len) / 8 ) & 7];\r
653                 }\r
654 \r
655                 /* If this fragment has the More Fragments flag set to zero, we\r
656        know that this is the last fragment, so we can calculate the\r
657        size of the entire packet. We also set the\r
658        IP_REASS_FLAG_LASTFRAG flag to indicate that we have received\r
659        the final fragment. */\r
660                 if( (BUF->ipoffset[0] & IP_MF) == 0 )\r
661                 {\r
662                         uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;\r
663                         uip_reasslen = offset + len;\r
664                 }\r
665 \r
666                 /* Finally, we check if we have a full packet in the buffer. We do\r
667        this by checking if we have the last fragment and if all bits\r
668        in the bitmap are set. */\r
669                 if( uip_reassflags & UIP_REASS_FLAG_LASTFRAG )\r
670                 {\r
671                         /* Check all bytes up to and including all but the last byte in\r
672          the bitmap. */\r
673                         for( i = 0; i < uip_reasslen / (8 * 8) - 1; ++i )\r
674                         {\r
675                                 if( uip_reassbitmap[i] != 0xff )\r
676                                 {\r
677                                         goto nullreturn;\r
678                                 }\r
679                         }\r
680 \r
681                         /* Check the last byte in the bitmap. It should contain just the\r
682          right amount of bits. */\r
683                         if( uip_reassbitmap[uip_reasslen / (8 * 8)] != (u8_t)~bitmap_bits[uip_reasslen / 8 & 7] )\r
684                         {\r
685                                 goto nullreturn;\r
686                         }\r
687 \r
688                         /* If we have come this far, we have a full packet in the\r
689          buffer, so we allocate a pbuf and copy the packet into it. We\r
690          also reset the timer. */\r
691                         uip_reasstmr = 0;\r
692                         memcpy( BUF, FBUF, uip_reasslen );\r
693 \r
694                         /* Pretend to be a "normal" (i.e., not fragmented) IP packet\r
695          from now on. */\r
696                         BUF->ipoffset[0] = BUF->ipoffset[1] = 0;\r
697                         BUF->len[0] = uip_reasslen >> 8;\r
698                         BUF->len[1] = uip_reasslen & 0xff;\r
699                         BUF->ipchksum = 0;\r
700                         BUF->ipchksum = ~( uip_ipchksum() );\r
701 \r
702                         return uip_reasslen;\r
703                 }\r
704         }\r
705 \r
706 nullreturn:\r
707         return 0;\r
708 }\r
709 \r
710 #endif /* UIP_REASSEMBLY */\r
711 \r
712 /*---------------------------------------------------------------------------*/\r
713 static void uip_add_rcv_nxt( u16_t n )\r
714 {\r
715         uip_add32( uip_conn->rcv_nxt, n );\r
716         uip_conn->rcv_nxt[0] = uip_acc32[0];\r
717         uip_conn->rcv_nxt[1] = uip_acc32[1];\r
718         uip_conn->rcv_nxt[2] = uip_acc32[2];\r
719         uip_conn->rcv_nxt[3] = uip_acc32[3];\r
720 }\r
721 \r
722 /*---------------------------------------------------------------------------*/\r
723 void uip_process( u8_t flag )\r
724 {\r
725         register struct uip_conn        *uip_connr = uip_conn;\r
726 \r
727         #if UIP_UDP\r
728         if( flag == UIP_UDP_SEND_CONN )\r
729         {\r
730                 goto udp_send;\r
731         }\r
732 \r
733         #endif /* UIP_UDP */\r
734 \r
735         uip_sappdata = uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN];\r
736 \r
737         /* Check if we were invoked because of a poll request for a\r
738      particular connection. */\r
739         if( flag == UIP_POLL_REQUEST )\r
740         {\r
741                 if( (uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED && !uip_outstanding(uip_connr) )\r
742                 {\r
743                         uip_flags = UIP_POLL;\r
744                         UIP_APPCALL();\r
745                         goto appsend;\r
746                 }\r
747 \r
748                 goto drop;\r
749 \r
750                 /* Check if we were invoked because of the perodic timer fireing. */\r
751         }\r
752         else if( flag == UIP_TIMER )\r
753         {\r
754                 #if UIP_REASSEMBLY\r
755                 if( uip_reasstmr != 0 )\r
756                 {\r
757                         --uip_reasstmr;\r
758                 }\r
759 \r
760                 #endif /* UIP_REASSEMBLY */\r
761 \r
762                 /* Increase the initial sequence number. */\r
763                 if( ++iss[3] == 0 )\r
764                 {\r
765                         if( ++iss[2] == 0 )\r
766                         {\r
767                                 if( ++iss[1] == 0 )\r
768                                 {\r
769                                         ++iss[0];\r
770                                 }\r
771                         }\r
772                 }\r
773 \r
774                 /* Reset the length variables. */\r
775                 uip_len = 0;\r
776                 uip_slen = 0;\r
777 \r
778                 /* Check if the connection is in a state in which we simply wait\r
779        for the connection to time out. If so, we increase the\r
780        connection's timer and remove the connection if it times\r
781        out. */\r
782                 if( uip_connr->tcpstateflags == UIP_TIME_WAIT || uip_connr->tcpstateflags == UIP_FIN_WAIT_2 )\r
783                 {\r
784                         ++( uip_connr->timer );\r
785                         if( uip_connr->timer == UIP_TIME_WAIT_TIMEOUT )\r
786                         {\r
787                                 uip_connr->tcpstateflags = UIP_CLOSED;\r
788                         }\r
789                 }\r
790                 else if( uip_connr->tcpstateflags != UIP_CLOSED )\r
791                 {\r
792                         /* If the connection has outstanding data, we increase the\r
793          connection's timer and see if it has reached the RTO value\r
794          in which case we retransmit. */\r
795                         if( uip_outstanding(uip_connr) )\r
796                         {\r
797                                 uip_connr->timer = uip_connr->timer - 1;\r
798                                 if( uip_connr->timer == 0 )\r
799                                 {\r
800                                         if\r
801                                         (\r
802                                                 uip_connr->nrtx == UIP_MAXRTX ||\r
803                                                 (\r
804                                                         (uip_connr->tcpstateflags == UIP_SYN_SENT || uip_connr->tcpstateflags == UIP_SYN_RCVD) &&\r
805                                                         uip_connr->nrtx == UIP_MAXSYNRTX\r
806                                                 )\r
807                                         )\r
808                                         {\r
809                                                 uip_connr->tcpstateflags = UIP_CLOSED;\r
810 \r
811                                                 /* We call UIP_APPCALL() with uip_flags set to\r
812                UIP_TIMEDOUT to inform the application that the\r
813                connection has timed out. */\r
814                                                 uip_flags = UIP_TIMEDOUT;\r
815                                                 UIP_APPCALL();\r
816 \r
817                                                 /* We also send a reset packet to the remote host. */\r
818                                                 BUF->flags = TCP_RST | TCP_ACK;\r
819                                                 goto tcp_send_nodata;\r
820                                         }\r
821 \r
822                                         /* Exponential backoff. */\r
823                                         uip_connr->timer = UIP_RTO << ( uip_connr->nrtx > 4 ? 4 : uip_connr->nrtx );\r
824                                         ++( uip_connr->nrtx );\r
825 \r
826                                         /* Ok, so we need to retransmit. We do this differently\r
827              depending on which state we are in. In ESTABLISHED, we\r
828              call upon the application so that it may prepare the\r
829              data for the retransmit. In SYN_RCVD, we resend the\r
830              SYNACK that we sent earlier and in LAST_ACK we have to\r
831              retransmit our FINACK. */\r
832                                         UIP_STAT( ++uip_stat.tcp.rexmit );\r
833                                         switch( uip_connr->tcpstateflags & UIP_TS_MASK )\r
834                                         {\r
835                                                 case UIP_SYN_RCVD:\r
836                                                         /* In the SYN_RCVD state, we should retransmit our\r
837                SYNACK. */\r
838                                                         goto tcp_send_synack;\r
839 \r
840                                                         #if UIP_ACTIVE_OPEN\r
841 \r
842                                                 case UIP_SYN_SENT:\r
843                                                         /* In the SYN_SENT state, we retransmit out SYN. */\r
844                                                         BUF->flags = 0;\r
845                                                         goto tcp_send_syn;\r
846                                                         #endif /* UIP_ACTIVE_OPEN */\r
847 \r
848                                                 case UIP_ESTABLISHED:\r
849                                                         /* In the ESTABLISHED state, we call upon the application\r
850                to do the actual retransmit after which we jump into\r
851                the code for sending out the packet (the apprexmit\r
852                label). */\r
853                                                         uip_flags = UIP_REXMIT;\r
854                                                         UIP_APPCALL();\r
855                                                         goto apprexmit;\r
856 \r
857                                                 case UIP_FIN_WAIT_1:\r
858                                                 case UIP_CLOSING:\r
859                                                 case UIP_LAST_ACK:\r
860                                                         /* In all these states we should retransmit a FINACK. */\r
861                                                         goto tcp_send_finack;\r
862                                         }\r
863                                 }\r
864                         }\r
865                         else if( (uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED )\r
866                         {\r
867                                 /* If there was no need for a retransmission, we poll the\r
868            application for new data. */\r
869                                 uip_flags = UIP_POLL;\r
870                                 UIP_APPCALL();\r
871                                 goto appsend;\r
872                         }\r
873                 }\r
874 \r
875                 goto drop;\r
876         }\r
877 \r
878         #if UIP_UDP\r
879         if( flag == UIP_UDP_TIMER )\r
880         {\r
881                 if( uip_udp_conn->lport != 0 )\r
882                 {\r
883                         uip_conn = NULL;\r
884                         uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];\r
885                         uip_len = uip_slen = 0;\r
886                         uip_flags = UIP_POLL;\r
887                         UIP_UDP_APPCALL();\r
888                         goto udp_send;\r
889                 }\r
890                 else\r
891                 {\r
892                         goto drop;\r
893                 }\r
894         }\r
895 \r
896         #endif\r
897 \r
898         /* This is where the input processing starts. */\r
899         UIP_STAT( ++uip_stat.ip.recv );\r
900 \r
901         /* Start of IP input header processing code. */\r
902         #if UIP_CONF_IPV6\r
903 \r
904         /* Check validity of the IP header. */\r
905         if( (BUF->vtc & 0xf0) != 0x60 )\r
906         {                                       /* IP version and header length. */\r
907                 UIP_STAT( ++uip_stat.ip.drop );\r
908                 UIP_STAT( ++uip_stat.ip.vhlerr );\r
909                 UIP_LOG( "ipv6: invalid version." );\r
910                 goto drop;\r
911         }\r
912 \r
913         #else /* UIP_CONF_IPV6 */\r
914 \r
915         /* Check validity of the IP header. */\r
916         if( BUF->vhl != 0x45 )\r
917         {                                       /* IP version and header length. */\r
918                 UIP_STAT( ++uip_stat.ip.drop );\r
919                 UIP_STAT( ++uip_stat.ip.vhlerr );\r
920                 UIP_LOG( "ip: invalid version or header length." );\r
921                 goto drop;\r
922         }\r
923 \r
924         #endif /* UIP_CONF_IPV6 */\r
925 \r
926         /* Check the size of the packet. If the size reported to us in\r
927      uip_len is smaller the size reported in the IP header, we assume\r
928      that the packet has been corrupted in transit. If the size of\r
929      uip_len is larger than the size reported in the IP packet header,\r
930      the packet has been padded and we set uip_len to the correct\r
931      value.. */\r
932         if( (BUF->len[0] << 8) + BUF->len[1] <= uip_len )\r
933         {\r
934                 uip_len = ( BUF->len[0] << 8 ) + BUF->len[1];\r
935                 #if UIP_CONF_IPV6\r
936                 uip_len += 40;  /* The length reported in the IPv6 header is the\r
937                       length of the payload that follows the\r
938                       header. However, uIP uses the uip_len variable\r
939                       for holding the size of the entire packet,\r
940                       including the IP header. For IPv4 this is not a\r
941                       problem as the length field in the IPv4 header\r
942                       contains the length of the entire packet. But\r
943                       for IPv6 we need to add the size of the IPv6\r
944                       header (40 bytes). */\r
945                 #endif /* UIP_CONF_IPV6 */\r
946         }\r
947         else\r
948         {\r
949                 UIP_LOG( "ip: packet shorter than reported in IP header." );\r
950                 goto drop;\r
951         }\r
952 \r
953         #if !UIP_CONF_IPV6\r
954 \r
955         /* Check the fragment flag. */\r
956         if( (BUF->ipoffset[0] & 0x3f) != 0 || BUF->ipoffset[1] != 0 )\r
957         {\r
958                         #if UIP_REASSEMBLY\r
959                 uip_len = uip_reass();\r
960                 if( uip_len == 0 )\r
961                 {\r
962                         goto drop;\r
963                 }\r
964 \r
965                         #else /* UIP_REASSEMBLY */\r
966                 UIP_STAT( ++uip_stat.ip.drop );\r
967                 UIP_STAT( ++uip_stat.ip.fragerr );\r
968                 UIP_LOG( "ip: fragment dropped." );\r
969                 goto drop;\r
970                         #endif /* UIP_REASSEMBLY */\r
971         }\r
972 \r
973         #endif /* UIP_CONF_IPV6 */\r
974 \r
975         if( uip_ipaddr_cmp(uip_hostaddr, all_zeroes_addr) )\r
976         {\r
977                 /* If we are configured to use ping IP address configuration and\r
978        hasn't been assigned an IP address yet, we accept all ICMP\r
979        packets. */\r
980                 #if UIP_PINGADDRCONF && !UIP_CONF_IPV6\r
981                 if( BUF->proto == UIP_PROTO_ICMP )\r
982                 {\r
983                         UIP_LOG( "ip: possible ping config packet received." );\r
984                         goto icmp_input;\r
985                 }\r
986                 else\r
987                 {\r
988                         UIP_LOG( "ip: packet dropped since no address assigned." );\r
989                         goto drop;\r
990                 }\r
991 \r
992                 #endif /* UIP_PINGADDRCONF */\r
993         }\r
994         else\r
995         {\r
996                 /* If IP broadcast support is configured, we check for a broadcast\r
997        UDP packet, which may be destined to us. */\r
998                 #if UIP_BROADCAST\r
999                 DEBUG_PRINTF( "UDP IP checksum 0x%04x\n", uip_ipchksum() );\r
1000                 if( BUF->proto == UIP_PROTO_UDP && uip_ipaddr_cmp(BUF->destipaddr, all_ones_addr) /*&&\r
1001          uip_ipchksum() == 0xffff*/ )\r
1002                 {\r
1003                         goto udp_input;\r
1004                 }\r
1005 \r
1006                 #endif /* UIP_BROADCAST */\r
1007 \r
1008                 /* Check if the packet is destined for our IP address. */\r
1009                 #if !UIP_CONF_IPV6\r
1010                 if( !uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr) )\r
1011                 {\r
1012                         UIP_STAT( ++uip_stat.ip.drop );\r
1013                         goto drop;\r
1014                 }\r
1015 \r
1016                 #else /* UIP_CONF_IPV6 */\r
1017 \r
1018                 /* For IPv6, packet reception is a little trickier as we need to\r
1019        make sure that we listen to certain multicast addresses (all\r
1020        hosts multicast address, and the solicited-node multicast\r
1021        address) as well. However, we will cheat here and accept all\r
1022        multicast packets that are sent to the ff02::/16 addresses. */\r
1023                 if( !uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr) && BUF->destipaddr[0] != HTONS(0xff02) )\r
1024                 {\r
1025                         UIP_STAT( ++uip_stat.ip.drop );\r
1026                         goto drop;\r
1027                 }\r
1028 \r
1029                 #endif /* UIP_CONF_IPV6 */\r
1030         }\r
1031 \r
1032         #if !UIP_CONF_IPV6\r
1033         if( uip_ipchksum() != 0xffff )\r
1034         {                                       /* Compute and check the IP header\r
1035                                     checksum. */\r
1036                 UIP_STAT( ++uip_stat.ip.drop );\r
1037                 UIP_STAT( ++uip_stat.ip.chkerr );\r
1038                 UIP_LOG( "ip: bad checksum." );\r
1039                 goto drop;\r
1040         }\r
1041 \r
1042         #endif /* UIP_CONF_IPV6 */\r
1043 \r
1044         if( BUF->proto == UIP_PROTO_TCP )\r
1045         {                                       /* Check for TCP packet. If so,\r
1046                                        proceed with TCP input\r
1047                                        processing. */\r
1048                 goto tcp_input;\r
1049         }\r
1050 \r
1051         #if UIP_UDP\r
1052         if( BUF->proto == UIP_PROTO_UDP )\r
1053         {\r
1054                 goto udp_input;\r
1055         }\r
1056 \r
1057         #endif /* UIP_UDP */\r
1058 \r
1059         #if !UIP_CONF_IPV6\r
1060 \r
1061         /* ICMPv4 processing code follows. */\r
1062         if( BUF->proto != UIP_PROTO_ICMP )\r
1063         {                                       /* We only allow ICMP packets from\r
1064                                         here. */\r
1065                 UIP_STAT( ++uip_stat.ip.drop );\r
1066                 UIP_STAT( ++uip_stat.ip.protoerr );\r
1067                 UIP_LOG( "ip: neither tcp nor icmp." );\r
1068                 goto drop;\r
1069         }\r
1070 \r
1071                 #if UIP_PINGADDRCONF\r
1072         icmp_input :\r
1073                 #endif /* UIP_PINGADDRCONF */\r
1074         UIP_STAT( ++uip_stat.icmp.recv );\r
1075 \r
1076         /* ICMP echo (i.e., ping) processing. This is simple, we only change\r
1077      the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP\r
1078      checksum before we return the packet. */\r
1079         if( ICMPBUF->type != ICMP_ECHO )\r
1080         {\r
1081                 UIP_STAT( ++uip_stat.icmp.drop );\r
1082                 UIP_STAT( ++uip_stat.icmp.typeerr );\r
1083                 UIP_LOG( "icmp: not icmp echo." );\r
1084                 goto drop;\r
1085         }\r
1086 \r
1087         /* If we are configured to use ping IP address assignment, we use\r
1088      the destination IP address of this ping packet and assign it to\r
1089      ourself. */\r
1090                 #if UIP_PINGADDRCONF\r
1091         if( (uip_hostaddr[0] | uip_hostaddr[1]) == 0 )\r
1092         {\r
1093                 uip_hostaddr[0] = BUF->destipaddr[0];\r
1094                 uip_hostaddr[1] = BUF->destipaddr[1];\r
1095         }\r
1096 \r
1097                 #endif /* UIP_PINGADDRCONF */\r
1098 \r
1099         ICMPBUF->type = ICMP_ECHO_REPLY;\r
1100 \r
1101         if( ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8)) )\r
1102         {\r
1103                 ICMPBUF->icmpchksum += HTONS( ICMP_ECHO << 8 ) + 1;\r
1104         }\r
1105         else\r
1106         {\r
1107                 ICMPBUF->icmpchksum += HTONS( ICMP_ECHO << 8 );\r
1108         }\r
1109 \r
1110         /* Swap IP addresses. */\r
1111         uip_ipaddr_copy( BUF->destipaddr, BUF->srcipaddr );\r
1112         uip_ipaddr_copy( BUF->srcipaddr, uip_hostaddr );\r
1113 \r
1114         UIP_STAT( ++uip_stat.icmp.sent );\r
1115         goto send;\r
1116 \r
1117         /* End of IPv4 input header processing code. */\r
1118         #else /* !UIP_CONF_IPV6 */\r
1119 \r
1120         /* This is IPv6 ICMPv6 processing code. */\r
1121         DEBUG_PRINTF( "icmp6_input: length %d\n", uip_len );\r
1122 \r
1123         if( BUF->proto != UIP_PROTO_ICMP6 )\r
1124         {                                       /* We only allow ICMPv6 packets from\r
1125                                          here. */\r
1126                 UIP_STAT( ++uip_stat.ip.drop );\r
1127                 UIP_STAT( ++uip_stat.ip.protoerr );\r
1128                 UIP_LOG( "ip: neither tcp nor icmp6." );\r
1129                 goto drop;\r
1130         }\r
1131 \r
1132         UIP_STAT( ++uip_stat.icmp.recv );\r
1133 \r
1134         /* If we get a neighbor solicitation for our address we should send\r
1135      a neighbor advertisement message back. */\r
1136         if( ICMPBUF->type == ICMP6_NEIGHBOR_SOLICITATION )\r
1137         {\r
1138                 if( uip_ipaddr_cmp(ICMPBUF->icmp6data, uip_hostaddr) )\r
1139                 {\r
1140                         if( ICMPBUF->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS )\r
1141                         {\r
1142                                 /* Save the sender's address in our neighbor list. */\r
1143                                 uip_neighbor_add( ICMPBUF->srcipaddr, &(ICMPBUF->options[2]) );\r
1144                         }\r
1145 \r
1146                         /* We should now send a neighbor advertisement back to where the\r
1147          neighbor solicication came from. */\r
1148                         ICMPBUF->type = ICMP6_NEIGHBOR_ADVERTISEMENT;\r
1149                         ICMPBUF->flags = ICMP6_FLAG_S;  /* Solicited flag. */\r
1150 \r
1151                         ICMPBUF->reserved1 = ICMPBUF->reserved2 = ICMPBUF->reserved3 = 0;\r
1152 \r
1153                         uip_ipaddr_copy( ICMPBUF->destipaddr, ICMPBUF->srcipaddr );\r
1154                         uip_ipaddr_copy( ICMPBUF->srcipaddr, uip_hostaddr );\r
1155                         ICMPBUF->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS;\r
1156                         ICMPBUF->options[1] = 1;                /* Options length, 1 = 8 bytes. */\r
1157                         memcpy( &(ICMPBUF->options[2]), &uip_ethaddr, sizeof(uip_ethaddr) );\r
1158                         ICMPBUF->icmpchksum = 0;\r
1159                         ICMPBUF->icmpchksum = ~uip_icmp6chksum();\r
1160                         goto send;\r
1161                 }\r
1162 \r
1163                 goto drop;\r
1164         }\r
1165         else if( ICMPBUF->type == ICMP6_ECHO )\r
1166         {\r
1167                 /* ICMP echo (i.e., ping) processing. This is simple, we only\r
1168        change the ICMP type from ECHO to ECHO_REPLY and update the\r
1169        ICMP checksum before we return the packet. */\r
1170                 ICMPBUF->type = ICMP6_ECHO_REPLY;\r
1171 \r
1172                 uip_ipaddr_copy( BUF->destipaddr, BUF->srcipaddr );\r
1173                 uip_ipaddr_copy( BUF->srcipaddr, uip_hostaddr );\r
1174                 ICMPBUF->icmpchksum = 0;\r
1175                 ICMPBUF->icmpchksum = ~uip_icmp6chksum();\r
1176 \r
1177                 UIP_STAT( ++uip_stat.icmp.sent );\r
1178                 goto send;\r
1179         }\r
1180         else\r
1181         {\r
1182                 DEBUG_PRINTF( "Unknown icmp6 message type %d\n", ICMPBUF->type );\r
1183                 UIP_STAT( ++uip_stat.icmp.drop );\r
1184                 UIP_STAT( ++uip_stat.icmp.typeerr );\r
1185                 UIP_LOG( "icmp: unknown ICMP message." );\r
1186                 goto drop;\r
1187         }\r
1188 \r
1189         /* End of IPv6 ICMP processing. */\r
1190         #endif /* !UIP_CONF_IPV6 */\r
1191 \r
1192         #if UIP_UDP\r
1193 \r
1194         /* UDP input processing. */\r
1195         udp_input :\r
1196         /* UDP processing is really just a hack. We don't do anything to the\r
1197      UDP/IP headers, but let the UDP application do all the hard\r
1198      work. If the application sets uip_slen, it has a packet to\r
1199      send. */\r
1200                 #if UIP_UDP_CHECKSUMS\r
1201         uip_len = uip_len - UIP_IPUDPH_LEN;\r
1202         uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];\r
1203         if( UDPBUF->udpchksum != 0 && uip_udpchksum() != 0xffff )\r
1204         {\r
1205                 UIP_STAT( ++uip_stat.udp.drop );\r
1206                 UIP_STAT( ++uip_stat.udp.chkerr );\r
1207                 UIP_LOG( "udp: bad checksum." );\r
1208                 goto drop;\r
1209         }\r
1210 \r
1211                 #else /* UIP_UDP_CHECKSUMS */\r
1212         uip_len = uip_len - UIP_IPUDPH_LEN;\r
1213                 #endif /* UIP_UDP_CHECKSUMS */\r
1214 \r
1215         /* Demultiplex this UDP packet between the UDP "connections". */\r
1216         for( uip_udp_conn = &uip_udp_conns[0]; uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS]; ++uip_udp_conn )\r
1217         {\r
1218                 /* If the local UDP port is non-zero, the connection is considered\r
1219        to be used. If so, the local port number is checked against the\r
1220        destination port number in the received packet. If the two port\r
1221        numbers match, the remote port number is checked if the\r
1222        connection is bound to a remote port. Finally, if the\r
1223        connection is bound to a remote IP address, the source IP\r
1224        address of the packet is checked. */\r
1225                 if\r
1226                 (\r
1227                         uip_udp_conn->lport != 0 &&\r
1228                         UDPBUF->destport == uip_udp_conn->lport &&\r
1229                         (uip_udp_conn->rport == 0 || UDPBUF->srcport == uip_udp_conn->rport) &&\r
1230                         (\r
1231                                 uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_zeroes_addr) ||\r
1232                                 uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_ones_addr) ||\r
1233                                 uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr)\r
1234                         )\r
1235                 )\r
1236                 {\r
1237                         goto udp_found;\r
1238                 }\r
1239         }\r
1240 \r
1241         UIP_LOG( "udp: no matching connection found" );\r
1242         goto drop;\r
1243 \r
1244 udp_found:\r
1245         UIP_STAT( ++uip_stat.udp.recv );\r
1246         uip_conn = NULL;\r
1247         uip_flags = UIP_NEWDATA;\r
1248         uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];\r
1249         uip_slen = 0;\r
1250         UIP_UDP_APPCALL();\r
1251 udp_send:\r
1252         if( uip_slen == 0 )\r
1253         {\r
1254                 goto drop;\r
1255         }\r
1256 \r
1257         uip_len = uip_slen + UIP_IPUDPH_LEN;\r
1258 \r
1259                 #if UIP_CONF_IPV6\r
1260 \r
1261         /* For IPv6, the IP length field does not include the IPv6 IP header\r
1262      length. */\r
1263         BUF->len[0] = ( (uip_len - UIP_IPH_LEN) >> 8 );\r
1264         BUF->len[1] = ( (uip_len - UIP_IPH_LEN) & 0xff );\r
1265                 #else /* UIP_CONF_IPV6 */\r
1266         BUF->len[0] = ( uip_len >> 8 );\r
1267         BUF->len[1] = ( uip_len & 0xff );\r
1268                 #endif /* UIP_CONF_IPV6 */\r
1269 \r
1270         BUF->ttl = uip_udp_conn->ttl;\r
1271         BUF->proto = UIP_PROTO_UDP;\r
1272 \r
1273         UDPBUF->udplen = HTONS( uip_slen + UIP_UDPH_LEN );\r
1274         UDPBUF->udpchksum = 0;\r
1275 \r
1276         BUF->srcport = uip_udp_conn->lport;\r
1277         BUF->destport = uip_udp_conn->rport;\r
1278 \r
1279         uip_ipaddr_copy( BUF->srcipaddr, uip_hostaddr );\r
1280         uip_ipaddr_copy( BUF->destipaddr, uip_udp_conn->ripaddr );\r
1281 \r
1282         uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];\r
1283 \r
1284                 #if UIP_UDP_CHECKSUMS\r
1285 \r
1286         /* Calculate UDP checksum. */\r
1287         UDPBUF->udpchksum = ~( uip_udpchksum() );\r
1288         if( UDPBUF->udpchksum == 0 )\r
1289         {\r
1290                 UDPBUF->udpchksum = 0xffff;\r
1291         }\r
1292 \r
1293                 #endif /* UIP_UDP_CHECKSUMS */\r
1294         UIP_STAT( ++uip_stat.udp.sent );\r
1295         goto ip_send_nolen;\r
1296         #endif /* UIP_UDP */\r
1297 \r
1298         /* TCP input processing. */\r
1299         tcp_input : UIP_STAT( ++uip_stat.tcp.recv );\r
1300 \r
1301         /* Start of TCP input header processing code. */\r
1302         if( uip_tcpchksum() != 0xffff )\r
1303         {       /* Compute and check the TCP\r
1304                                        checksum. */\r
1305                 UIP_STAT( ++uip_stat.tcp.drop );\r
1306                 UIP_STAT( ++uip_stat.tcp.chkerr );\r
1307                 UIP_LOG( "tcp: bad checksum." );\r
1308                 goto drop;\r
1309         }\r
1310 \r
1311         /* Demultiplex this segment. */\r
1312 \r
1313         /* First check any active connections. */\r
1314         for( uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1]; ++uip_connr )\r
1315         {\r
1316                 if\r
1317                 (\r
1318                         uip_connr->tcpstateflags != UIP_CLOSED &&\r
1319                         BUF->destport == uip_connr->lport &&\r
1320                         BUF->srcport == uip_connr->rport &&\r
1321                         uip_ipaddr_cmp(BUF->srcipaddr, uip_connr->ripaddr)\r
1322                 )\r
1323                 {\r
1324                         goto found;\r
1325                 }\r
1326         }\r
1327 \r
1328         /* If we didn't find and active connection that expected the packet,\r
1329      either this packet is an old duplicate, or this is a SYN packet\r
1330      destined for a connection in LISTEN. If the SYN flag isn't set,\r
1331      it is an old packet and we send a RST. */\r
1332         if( (BUF->flags & TCP_CTL) != TCP_SYN )\r
1333         {\r
1334                 goto reset;\r
1335         }\r
1336 \r
1337         tmp16 = BUF->destport;\r
1338 \r
1339         /* Next, check listening connections. */\r
1340         for( c = 0; c < UIP_LISTENPORTS; ++c )\r
1341         {\r
1342                 if( tmp16 == uip_listenports[c] )\r
1343                 {\r
1344                         goto found_listen;\r
1345                 }\r
1346         }\r
1347 \r
1348         /* No matching connection found, so we send a RST packet. */\r
1349         UIP_STAT( ++uip_stat.tcp.synrst );\r
1350 reset:\r
1351         /* We do not send resets in response to resets. */\r
1352         if( BUF->flags & TCP_RST )\r
1353         {\r
1354                 goto drop;\r
1355         }\r
1356 \r
1357         UIP_STAT( ++uip_stat.tcp.rst );\r
1358 \r
1359         BUF->flags = TCP_RST | TCP_ACK;\r
1360         uip_len = UIP_IPTCPH_LEN;\r
1361         BUF->tcpoffset = 5 << 4;\r
1362 \r
1363         /* Flip the seqno and ackno fields in the TCP header. */\r
1364         c = BUF->seqno[3];\r
1365         BUF->seqno[3] = BUF->ackno[3];\r
1366         BUF->ackno[3] = c;\r
1367 \r
1368         c = BUF->seqno[2];\r
1369         BUF->seqno[2] = BUF->ackno[2];\r
1370         BUF->ackno[2] = c;\r
1371 \r
1372         c = BUF->seqno[1];\r
1373         BUF->seqno[1] = BUF->ackno[1];\r
1374         BUF->ackno[1] = c;\r
1375 \r
1376         c = BUF->seqno[0];\r
1377         BUF->seqno[0] = BUF->ackno[0];\r
1378         BUF->ackno[0] = c;\r
1379 \r
1380         /* We also have to increase the sequence number we are\r
1381      acknowledging. If the least significant byte overflowed, we need\r
1382      to propagate the carry to the other bytes as well. */\r
1383         if( ++BUF->ackno[3] == 0 )\r
1384         {\r
1385                 if( ++BUF->ackno[2] == 0 )\r
1386                 {\r
1387                         if( ++BUF->ackno[1] == 0 )\r
1388                         {\r
1389                                 ++BUF->ackno[0];\r
1390                         }\r
1391                 }\r
1392         }\r
1393 \r
1394         /* Swap port numbers. */\r
1395         tmp16 = BUF->srcport;\r
1396         BUF->srcport = BUF->destport;\r
1397         BUF->destport = tmp16;\r
1398 \r
1399         /* Swap IP addresses. */\r
1400         uip_ipaddr_copy( BUF->destipaddr, BUF->srcipaddr );\r
1401         uip_ipaddr_copy( BUF->srcipaddr, uip_hostaddr );\r
1402 \r
1403         /* And send out the RST packet! */\r
1404         goto tcp_send_noconn;\r
1405 \r
1406         /* This label will be jumped to if we matched the incoming packet\r
1407      with a connection in LISTEN. In that case, we should create a new\r
1408      connection and send a SYNACK in return. */\r
1409 found_listen:\r
1410         /* First we check if there are any connections avaliable. Unused\r
1411      connections are kept in the same table as used connections, but\r
1412      unused ones have the tcpstate set to CLOSED. Also, connections in\r
1413      TIME_WAIT are kept track of and we'll use the oldest one if no\r
1414      CLOSED connections are found. Thanks to Eddie C. Dost for a very\r
1415      nice algorithm for the TIME_WAIT search. */\r
1416         uip_connr = 0;\r
1417         for( c = 0; c < UIP_CONNS; ++c )\r
1418         {\r
1419                 if( uip_conns[c].tcpstateflags == UIP_CLOSED )\r
1420                 {\r
1421                         uip_connr = &uip_conns[c];\r
1422                         break;\r
1423                 }\r
1424 \r
1425                 if( uip_conns[c].tcpstateflags == UIP_TIME_WAIT )\r
1426                 {\r
1427                         if( uip_connr == 0 || uip_conns[c].timer > uip_connr->timer )\r
1428                         {\r
1429                                 uip_connr = &uip_conns[c];\r
1430                         }\r
1431                 }\r
1432         }\r
1433 \r
1434         if( uip_connr == 0 )\r
1435         {\r
1436                 /* All connections are used already, we drop packet and hope that\r
1437        the remote end will retransmit the packet at a time when we\r
1438        have more spare connections. */\r
1439                 UIP_STAT( ++uip_stat.tcp.syndrop );\r
1440                 UIP_LOG( "tcp: found no unused connections." );\r
1441                 goto drop;\r
1442         }\r
1443 \r
1444         uip_conn = uip_connr;\r
1445 \r
1446         /* Fill in the necessary fields for the new connection. */\r
1447         uip_connr->rto = uip_connr->timer = UIP_RTO;\r
1448         uip_connr->sa = 0;\r
1449         uip_connr->sv = 4;\r
1450         uip_connr->nrtx = 0;\r
1451         uip_connr->lport = BUF->destport;\r
1452         uip_connr->rport = BUF->srcport;\r
1453         uip_ipaddr_copy( uip_connr->ripaddr, BUF->srcipaddr );\r
1454         uip_connr->tcpstateflags = UIP_SYN_RCVD;\r
1455 \r
1456         uip_connr->snd_nxt[0] = iss[0];\r
1457         uip_connr->snd_nxt[1] = iss[1];\r
1458         uip_connr->snd_nxt[2] = iss[2];\r
1459         uip_connr->snd_nxt[3] = iss[3];\r
1460         uip_connr->len = 1;\r
1461 \r
1462         /* rcv_nxt should be the seqno from the incoming packet + 1. */\r
1463         uip_connr->rcv_nxt[3] = BUF->seqno[3];\r
1464         uip_connr->rcv_nxt[2] = BUF->seqno[2];\r
1465         uip_connr->rcv_nxt[1] = BUF->seqno[1];\r
1466         uip_connr->rcv_nxt[0] = BUF->seqno[0];\r
1467         uip_add_rcv_nxt( 1 );\r
1468 \r
1469         /* Parse the TCP MSS option, if present. */\r
1470         if( (BUF->tcpoffset & 0xf0) > 0x50 )\r
1471         {\r
1472                 for( c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2; )\r
1473                 {\r
1474                         opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];\r
1475                         if( opt == TCP_OPT_END )\r
1476                         {\r
1477                                 /* End of options. */\r
1478                                 break;\r
1479                         }\r
1480                         else if( opt == TCP_OPT_NOOP )\r
1481                         {\r
1482                                 ++c;\r
1483 \r
1484                                 /* NOP option. */\r
1485                         }\r
1486                         else if( opt == TCP_OPT_MSS && uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN )\r
1487                         {\r
1488                                 /* An MSS option with the right option length. */\r
1489                                 tmp16 = ( (u16_t) uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8 ) | ( u16_t ) uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c];\r
1490                                 uip_connr->initialmss = uip_connr->mss = tmp16 > UIP_TCP_MSS ? UIP_TCP_MSS : tmp16;\r
1491 \r
1492                                 /* And we are done processing options. */\r
1493                                 break;\r
1494                         }\r
1495                         else\r
1496                         {\r
1497                                 /* All other options have a length field, so that we easily\r
1498            can skip past them. */\r
1499                                 if( uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0 )\r
1500                                 {\r
1501                                         /* If the length field is zero, the options are malformed\r
1502              and we don't process them further. */\r
1503                                         break;\r
1504                                 }\r
1505 \r
1506                                 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];\r
1507                         }\r
1508                 }\r
1509         }\r
1510 \r
1511         /* Our response will be a SYNACK. */\r
1512         #if UIP_ACTIVE_OPEN\r
1513         tcp_send_synack : BUF->flags = TCP_ACK;\r
1514 \r
1515 tcp_send_syn:\r
1516         BUF->flags |= TCP_SYN;\r
1517         #else /* UIP_ACTIVE_OPEN */\r
1518         tcp_send_synack : BUF->flags = TCP_SYN | TCP_ACK;\r
1519         #endif /* UIP_ACTIVE_OPEN */\r
1520 \r
1521         /* We send out the TCP Maximum Segment Size option with our\r
1522      SYNACK. */\r
1523         BUF->optdata[0] = TCP_OPT_MSS;\r
1524         BUF->optdata[1] = TCP_OPT_MSS_LEN;\r
1525         BUF->optdata[2] = ( UIP_TCP_MSS ) / 256;\r
1526         BUF->optdata[3] = ( UIP_TCP_MSS ) & 255;\r
1527         uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN;\r
1528         BUF->tcpoffset = ( (UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4 ) << 4;\r
1529         goto tcp_send;\r
1530 \r
1531         /* This label will be jumped to if we found an active connection. */\r
1532 found:\r
1533         uip_conn = uip_connr;\r
1534         uip_flags = 0;\r
1535 \r
1536         /* We do a very naive form of TCP reset processing; we just accept\r
1537      any RST and kill our connection. We should in fact check if the\r
1538      sequence number of this reset is wihtin our advertised window\r
1539      before we accept the reset. */\r
1540         if( BUF->flags & TCP_RST )\r
1541         {\r
1542                 uip_connr->tcpstateflags = UIP_CLOSED;\r
1543                 UIP_LOG( "tcp: got reset, aborting connection." );\r
1544                 uip_flags = UIP_ABORT;\r
1545                 UIP_APPCALL();\r
1546                 goto drop;\r
1547         }\r
1548 \r
1549         /* Calculated the length of the data, if the application has sent\r
1550      any data to us. */\r
1551         c = ( BUF->tcpoffset >> 4 ) << 2;\r
1552 \r
1553         /* uip_len will contain the length of the actual TCP data. This is\r
1554      calculated by subtracing the length of the TCP header (in\r
1555      c) and the length of the IP header (20 bytes). */\r
1556         uip_len = uip_len - c - UIP_IPH_LEN;\r
1557 \r
1558         /* First, check if the sequence number of the incoming packet is\r
1559      what we're expecting next. If not, we send out an ACK with the\r
1560      correct numbers in. */\r
1561         if( !(((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) && ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK))) )\r
1562         {\r
1563                 if\r
1564                 (\r
1565                         (uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0)) &&\r
1566                         (\r
1567                                 BUF->seqno[0] != uip_connr->rcv_nxt[0] ||\r
1568                                 BUF->seqno[1] != uip_connr->rcv_nxt[1] ||\r
1569                                 BUF->seqno[2] != uip_connr->rcv_nxt[2] ||\r
1570                                 BUF->seqno[3] != uip_connr->rcv_nxt[3]\r
1571                         )\r
1572                 )\r
1573                 {\r
1574                         goto tcp_send_ack;\r
1575                 }\r
1576         }\r
1577 \r
1578         /* Next, check if the incoming segment acknowledges any outstanding\r
1579      data. If so, we update the sequence number, reset the length of\r
1580      the outstanding data, calculate RTT estimations, and reset the\r
1581      retransmission timer. */\r
1582         if( (BUF->flags & TCP_ACK) && uip_outstanding(uip_connr) )\r
1583         {\r
1584                 uip_add32( uip_connr->snd_nxt, uip_connr->len );\r
1585 \r
1586                 if\r
1587                 (\r
1588                         BUF->ackno[0] == uip_acc32[0] &&\r
1589                         BUF->ackno[1] == uip_acc32[1] &&\r
1590                         BUF->ackno[2] == uip_acc32[2] &&\r
1591                         BUF->ackno[3] == uip_acc32[3]\r
1592                 )\r
1593                 {\r
1594                         /* Update sequence number. */\r
1595                         uip_connr->snd_nxt[0] = uip_acc32[0];\r
1596                         uip_connr->snd_nxt[1] = uip_acc32[1];\r
1597                         uip_connr->snd_nxt[2] = uip_acc32[2];\r
1598                         uip_connr->snd_nxt[3] = uip_acc32[3];\r
1599 \r
1600                         /* Do RTT estimation, unless we have done retransmissions. */\r
1601                         if( uip_connr->nrtx == 0 )\r
1602                         {\r
1603                                 signed char m;\r
1604                                 m = uip_connr->rto - uip_connr->timer;\r
1605 \r
1606                                 /* This is taken directly from VJs original code in his paper */\r
1607                                 m = m - ( uip_connr->sa >> 3 );\r
1608                                 uip_connr->sa += m;\r
1609                                 if( m < 0 )\r
1610                                 {\r
1611                                         m = -m;\r
1612                                 }\r
1613 \r
1614                                 m = m - ( uip_connr->sv >> 2 );\r
1615                                 uip_connr->sv += m;\r
1616                                 uip_connr->rto = ( uip_connr->sa >> 3 ) + uip_connr->sv;\r
1617                         }\r
1618 \r
1619                         /* Set the acknowledged flag. */\r
1620                         uip_flags = UIP_ACKDATA;\r
1621 \r
1622                         /* Reset the retransmission timer. */\r
1623                         uip_connr->timer = uip_connr->rto;\r
1624 \r
1625                         /* Reset length of outstanding data. */\r
1626                         uip_connr->len = 0;\r
1627                 }\r
1628         }\r
1629 \r
1630         /* Do different things depending on in what state the connection is. */\r
1631         switch( uip_connr->tcpstateflags & UIP_TS_MASK )\r
1632         {\r
1633                 /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not\r
1634         implemented, since we force the application to close when the\r
1635         peer sends a FIN (hence the application goes directly from\r
1636         ESTABLISHED to LAST_ACK). */\r
1637                 case UIP_SYN_RCVD:\r
1638                         /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and\r
1639        we are waiting for an ACK that acknowledges the data we sent\r
1640        out the last time. Therefore, we want to have the UIP_ACKDATA\r
1641        flag set. If so, we enter the ESTABLISHED state. */\r
1642                         if( uip_flags & UIP_ACKDATA )\r
1643                         {\r
1644                                 uip_connr->tcpstateflags = UIP_ESTABLISHED;\r
1645                                 uip_flags = UIP_CONNECTED;\r
1646                                 uip_connr->len = 0;\r
1647                                 if( uip_len > 0 )\r
1648                                 {\r
1649                                         uip_flags |= UIP_NEWDATA;\r
1650                                         uip_add_rcv_nxt( uip_len );\r
1651                                 }\r
1652 \r
1653                                 uip_slen = 0;\r
1654                                 UIP_APPCALL();\r
1655                                 goto appsend;\r
1656                         }\r
1657 \r
1658                         goto drop;\r
1659                         #if UIP_ACTIVE_OPEN\r
1660 \r
1661                 case UIP_SYN_SENT:\r
1662                         /* In SYN_SENT, we wait for a SYNACK that is sent in response to\r
1663        our SYN. The rcv_nxt is set to sequence number in the SYNACK\r
1664        plus one, and we send an ACK. We move into the ESTABLISHED\r
1665        state. */\r
1666                         if( (uip_flags & UIP_ACKDATA) && (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK) )\r
1667                         {\r
1668                                 /* Parse the TCP MSS option, if present. */\r
1669                                 if( (BUF->tcpoffset & 0xf0) > 0x50 )\r
1670                                 {\r
1671                                         for( c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2; )\r
1672                                         {\r
1673                                                 opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c];\r
1674                                                 if( opt == TCP_OPT_END )\r
1675                                                 {\r
1676                                                         /* End of options. */\r
1677                                                         break;\r
1678                                                 }\r
1679                                                 else if( opt == TCP_OPT_NOOP )\r
1680                                                 {\r
1681                                                         ++c;\r
1682 \r
1683                                                         /* NOP option. */\r
1684                                                 }\r
1685                                                 else if( opt == TCP_OPT_MSS && uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN )\r
1686                                                 {\r
1687                                                         /* An MSS option with the right option length. */\r
1688                                                         tmp16 = ( uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8 ) | uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];\r
1689                                                         uip_connr->initialmss = uip_connr->mss = tmp16 > UIP_TCP_MSS ? UIP_TCP_MSS : tmp16;\r
1690 \r
1691                                                         /* And we are done processing options. */\r
1692                                                         break;\r
1693                                                 }\r
1694                                                 else\r
1695                                                 {\r
1696                                                         /* All other options have a length field, so that we easily\r
1697                can skip past them. */\r
1698                                                         if( uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0 )\r
1699                                                         {\r
1700                                                                 /* If the length field is zero, the options are malformed\r
1701                  and we don't process them further. */\r
1702                                                                 break;\r
1703                                                         }\r
1704 \r
1705                                                         c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];\r
1706                                                 }\r
1707                                         }\r
1708                                 }\r
1709 \r
1710                                 uip_connr->tcpstateflags = UIP_ESTABLISHED;\r
1711                                 uip_connr->rcv_nxt[0] = BUF->seqno[0];\r
1712                                 uip_connr->rcv_nxt[1] = BUF->seqno[1];\r
1713                                 uip_connr->rcv_nxt[2] = BUF->seqno[2];\r
1714                                 uip_connr->rcv_nxt[3] = BUF->seqno[3];\r
1715                                 uip_add_rcv_nxt( 1 );\r
1716                                 uip_flags = UIP_CONNECTED | UIP_NEWDATA;\r
1717                                 uip_connr->len = 0;\r
1718                                 uip_len = 0;\r
1719                                 uip_slen = 0;\r
1720                                 UIP_APPCALL();\r
1721                                 goto appsend;\r
1722                         }\r
1723 \r
1724                         /* Inform the application that the connection failed */\r
1725                         uip_flags = UIP_ABORT;\r
1726                         UIP_APPCALL();\r
1727 \r
1728                         /* The connection is closed after we send the RST */\r
1729                         uip_conn->tcpstateflags = UIP_CLOSED;\r
1730                         goto reset;\r
1731                         #endif /* UIP_ACTIVE_OPEN */\r
1732 \r
1733                 case UIP_ESTABLISHED:\r
1734                         /* In the ESTABLISHED state, we call upon the application to feed\r
1735     data into the uip_buf. If the UIP_ACKDATA flag is set, the\r
1736     application should put new data into the buffer, otherwise we are\r
1737     retransmitting an old segment, and the application should put that\r
1738     data into the buffer.\r
1739 \r
1740     If the incoming packet is a FIN, we should close the connection on\r
1741     this side as well, and we send out a FIN and enter the LAST_ACK\r
1742     state. We require that there is no outstanding data; otherwise the\r
1743     sequence numbers will be screwed up. */\r
1744                         if( BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED) )\r
1745                         {\r
1746                                 if( uip_outstanding(uip_connr) )\r
1747                                 {\r
1748                                         goto drop;\r
1749                                 }\r
1750 \r
1751                                 uip_add_rcv_nxt( 1 + uip_len );\r
1752                                 uip_flags |= UIP_CLOSE;\r
1753                                 if( uip_len > 0 )\r
1754                                 {\r
1755                                         uip_flags |= UIP_NEWDATA;\r
1756                                 }\r
1757 \r
1758                                 UIP_APPCALL();\r
1759                                 uip_connr->len = 1;\r
1760                                 uip_connr->tcpstateflags = UIP_LAST_ACK;\r
1761                                 uip_connr->nrtx = 0;\r
1762         tcp_send_finack:\r
1763                                 BUF->flags = TCP_FIN | TCP_ACK;\r
1764                                 goto tcp_send_nodata;\r
1765                         }\r
1766 \r
1767                         /* Check the URG flag. If this is set, the segment carries urgent\r
1768        data that we must pass to the application. */\r
1769                         if( (BUF->flags & TCP_URG) != 0 )\r
1770                         {\r
1771                                 #if UIP_URGDATA > 0\r
1772                                 uip_urglen = ( BUF->urgp[0] << 8 ) | BUF->urgp[1];\r
1773                                 if( uip_urglen > uip_len )\r
1774                                 {\r
1775                                         /* There is more urgent data in the next segment to come. */\r
1776                                         uip_urglen = uip_len;\r
1777                                 }\r
1778 \r
1779                                 uip_add_rcv_nxt( uip_urglen );\r
1780                                 uip_len -= uip_urglen;\r
1781                                 uip_urgdata = uip_appdata;\r
1782                                 uip_appdata += uip_urglen;\r
1783                         }\r
1784                         else\r
1785                         {\r
1786                                 uip_urglen = 0;\r
1787                                 #else /* UIP_URGDATA > 0 */\r
1788                                 uip_appdata = ( ( char * ) uip_appdata ) + ( (BUF->urgp[0] << 8) | BUF->urgp[1] );\r
1789                                 uip_len -= ( BUF->urgp[0] << 8 ) | BUF->urgp[1];\r
1790                                 #endif /* UIP_URGDATA > 0 */\r
1791                         }\r
1792 \r
1793                         /* If uip_len > 0 we have TCP data in the packet, and we flag this\r
1794        by setting the UIP_NEWDATA flag and update the sequence number\r
1795        we acknowledge. If the application has stopped the dataflow\r
1796        using uip_stop(), we must not accept any data packets from the\r
1797        remote host. */\r
1798                         if( uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED) )\r
1799                         {\r
1800                                 uip_flags |= UIP_NEWDATA;\r
1801                                 uip_add_rcv_nxt( uip_len );\r
1802                         }\r
1803 \r
1804                         /* Check if the available buffer space advertised by the other end\r
1805        is smaller than the initial MSS for this connection. If so, we\r
1806        set the current MSS to the window size to ensure that the\r
1807        application does not send more data than the other end can\r
1808        handle.\r
1809 \r
1810        If the remote host advertises a zero window, we set the MSS to\r
1811        the initial MSS so that the application will send an entire MSS\r
1812        of data. This data will not be acknowledged by the receiver,\r
1813        and the application will retransmit it. This is called the\r
1814        "persistent timer" and uses the retransmission mechanim.\r
1815     */\r
1816                         tmp16 = ( (u16_t) BUF->wnd[0] << 8 ) + ( u16_t ) BUF->wnd[1];\r
1817                         if( tmp16 > (uip_connr->initialmss * FRAME_MULTIPLE) || tmp16 == 0 )\r
1818                         {\r
1819                                 tmp16 = uip_connr->initialmss * FRAME_MULTIPLE;\r
1820                         }\r
1821 \r
1822                         uip_connr->mss = tmp16;\r
1823 \r
1824                         /* If this packet constitutes an ACK for outstanding data (flagged\r
1825        by the UIP_ACKDATA flag, we should call the application since it\r
1826        might want to send more data. If the incoming packet had data\r
1827        from the peer (as flagged by the UIP_NEWDATA flag), the\r
1828        application must also be notified.\r
1829 \r
1830        When the application is called, the global variable uip_len\r
1831        contains the length of the incoming data. The application can\r
1832        access the incoming data through the global pointer\r
1833        uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN\r
1834        bytes into the uip_buf array.\r
1835 \r
1836        If the application wishes to send any data, this data should be\r
1837        put into the uip_appdata and the length of the data should be\r
1838        put into uip_len. If the application don't have any data to\r
1839        send, uip_len must be set to 0. */\r
1840                         if( uip_flags & (UIP_NEWDATA | UIP_ACKDATA) )\r
1841                         {\r
1842                                 uip_slen = 0;\r
1843                                 UIP_APPCALL();\r
1844 \r
1845         appsend:\r
1846                                 if( uip_flags & UIP_ABORT )\r
1847                                 {\r
1848                                         uip_slen = 0;\r
1849                                         uip_connr->tcpstateflags = UIP_CLOSED;\r
1850                                         BUF->flags = TCP_RST | TCP_ACK;\r
1851                                         goto tcp_send_nodata;\r
1852                                 }\r
1853 \r
1854                                 if( uip_flags & UIP_CLOSE )\r
1855                                 {\r
1856                                         uip_slen = 0;\r
1857                                         uip_connr->len = 1;\r
1858                                         uip_connr->tcpstateflags = UIP_FIN_WAIT_1;\r
1859                                         uip_connr->nrtx = 0;\r
1860                                         BUF->flags = TCP_FIN | TCP_ACK;\r
1861                                         goto tcp_send_nodata;\r
1862                                 }\r
1863 \r
1864                                 /* If uip_slen > 0, the application has data to be sent. */\r
1865                                 if( uip_slen > 0 )\r
1866                                 {\r
1867                                         /* If the connection has acknowledged data, the contents of\r
1868            the ->len variable should be discarded. */\r
1869                                         if( (uip_flags & UIP_ACKDATA) != 0 )\r
1870                                         {\r
1871                                                 uip_connr->len = 0;\r
1872                                         }\r
1873 \r
1874                                         /* If the ->len variable is non-zero the connection has\r
1875            already data in transit and cannot send anymore right\r
1876            now. */\r
1877                                         if( uip_connr->len == 0 )\r
1878                                         {\r
1879                                                 /* The application cannot send more than what is allowed by\r
1880              the mss (the minumum of the MSS and the available\r
1881              window). */\r
1882                                                 if( uip_slen > uip_connr->mss )\r
1883                                                 {\r
1884                                                         uip_slen = uip_connr->mss;\r
1885                                                 }\r
1886 \r
1887                                                 /* Remember how much data we send out now so that we know\r
1888              when everything has been acknowledged. */\r
1889                                                 uip_connr->len = uip_slen;\r
1890                                         }\r
1891                                         else\r
1892                                         {\r
1893                                                 /* If the application already had unacknowledged data, we\r
1894              make sure that the application does not send (i.e.,\r
1895              retransmit) out more than it previously sent out. */\r
1896                                                 uip_slen = uip_connr->len;\r
1897                                         }\r
1898                                 }\r
1899 \r
1900                                 uip_connr->nrtx = 0;\r
1901         apprexmit:\r
1902                                 uip_appdata = uip_sappdata;\r
1903 \r
1904                                 /* If the application has data to be sent, or if the incoming\r
1905          packet had new data in it, we must send out a packet. */\r
1906                                 if( uip_slen > 0 && uip_connr->len > 0 )\r
1907                                 {\r
1908                                         /* Add the length of the IP and TCP headers. */\r
1909                                         uip_len = uip_connr->len + UIP_TCPIP_HLEN;\r
1910 \r
1911                                         /* We always set the ACK flag in response packets. */\r
1912                                         BUF->flags = TCP_ACK | TCP_PSH;\r
1913 \r
1914                                         /* Send the packet. */\r
1915                                         goto tcp_send_noopts;\r
1916                                 }\r
1917 \r
1918                                 /* If there is no data to send, just send out a pure ACK if\r
1919          there is newdata. */\r
1920                                 if( uip_flags & UIP_NEWDATA )\r
1921                                 {\r
1922                                         uip_len = UIP_TCPIP_HLEN;\r
1923                                         BUF->flags = TCP_ACK;\r
1924                                         goto tcp_send_noopts;\r
1925                                 }\r
1926                         }\r
1927 \r
1928                         goto drop;\r
1929 \r
1930                 case UIP_LAST_ACK:\r
1931                         /* We can close this connection if the peer has acknowledged our\r
1932        FIN. This is indicated by the UIP_ACKDATA flag. */\r
1933                         if( uip_flags & UIP_ACKDATA )\r
1934                         {\r
1935                                 uip_connr->tcpstateflags = UIP_CLOSED;\r
1936                                 uip_flags = UIP_CLOSE;\r
1937                                 UIP_APPCALL();\r
1938                         }\r
1939 \r
1940                         break;\r
1941 \r
1942                 case UIP_FIN_WAIT_1:\r
1943                         /* The application has closed the connection, but the remote host\r
1944        hasn't closed its end yet. Thus we do nothing but wait for a\r
1945        FIN from the other side. */\r
1946                         if( uip_len > 0 )\r
1947                         {\r
1948                                 uip_add_rcv_nxt( uip_len );\r
1949                         }\r
1950 \r
1951                         if( BUF->flags & TCP_FIN )\r
1952                         {\r
1953                                 if( uip_flags & UIP_ACKDATA )\r
1954                                 {\r
1955                                         uip_connr->tcpstateflags = UIP_TIME_WAIT;\r
1956                                         uip_connr->timer = 0;\r
1957                                         uip_connr->len = 0;\r
1958                                 }\r
1959                                 else\r
1960                                 {\r
1961                                         uip_connr->tcpstateflags = UIP_CLOSING;\r
1962                                 }\r
1963 \r
1964                                 uip_add_rcv_nxt( 1 );\r
1965                                 uip_flags = UIP_CLOSE;\r
1966                                 UIP_APPCALL();\r
1967                                 goto tcp_send_ack;\r
1968                         }\r
1969                         else if( uip_flags & UIP_ACKDATA )\r
1970                         {\r
1971                                 uip_connr->tcpstateflags = UIP_FIN_WAIT_2;\r
1972                                 uip_connr->len = 0;\r
1973                                 goto drop;\r
1974                         }\r
1975 \r
1976                         if( uip_len > 0 )\r
1977                         {\r
1978                                 goto tcp_send_ack;\r
1979                         }\r
1980 \r
1981                         goto drop;\r
1982 \r
1983                 case UIP_FIN_WAIT_2:\r
1984                         if( uip_len > 0 )\r
1985                         {\r
1986                                 uip_add_rcv_nxt( uip_len );\r
1987                         }\r
1988 \r
1989                         if( BUF->flags & TCP_FIN )\r
1990                         {\r
1991                                 uip_connr->tcpstateflags = UIP_TIME_WAIT;\r
1992                                 uip_connr->timer = 0;\r
1993                                 uip_add_rcv_nxt( 1 );\r
1994                                 uip_flags = UIP_CLOSE;\r
1995                                 UIP_APPCALL();\r
1996                                 goto tcp_send_ack;\r
1997                         }\r
1998 \r
1999                         if( uip_len > 0 )\r
2000                         {\r
2001                                 goto tcp_send_ack;\r
2002                         }\r
2003 \r
2004                         goto drop;\r
2005 \r
2006                 case UIP_TIME_WAIT:\r
2007                         goto tcp_send_ack;\r
2008 \r
2009                 case UIP_CLOSING:\r
2010                         if( uip_flags & UIP_ACKDATA )\r
2011                         {\r
2012                                 uip_connr->tcpstateflags = UIP_TIME_WAIT;\r
2013                                 uip_connr->timer = 0;\r
2014                         }\r
2015         }\r
2016 \r
2017         goto drop;\r
2018 \r
2019         /* We jump here when we are ready to send the packet, and just want\r
2020      to set the appropriate TCP sequence numbers in the TCP header. */\r
2021 tcp_send_ack:\r
2022         BUF->flags = TCP_ACK;\r
2023 tcp_send_nodata:\r
2024         uip_len = UIP_IPTCPH_LEN;\r
2025 tcp_send_noopts:\r
2026         BUF->tcpoffset = ( UIP_TCPH_LEN / 4 ) << 4;\r
2027 tcp_send:\r
2028         /* We're done with the input processing. We are now ready to send a\r
2029      reply. Our job is to fill in all the fields of the TCP and IP\r
2030      headers before calculating the checksum and finally send the\r
2031      packet. */\r
2032         BUF->ackno[0] = uip_connr->rcv_nxt[0];\r
2033         BUF->ackno[1] = uip_connr->rcv_nxt[1];\r
2034         BUF->ackno[2] = uip_connr->rcv_nxt[2];\r
2035         BUF->ackno[3] = uip_connr->rcv_nxt[3];\r
2036 \r
2037         BUF->seqno[0] = uip_connr->snd_nxt[0];\r
2038         BUF->seqno[1] = uip_connr->snd_nxt[1];\r
2039         BUF->seqno[2] = uip_connr->snd_nxt[2];\r
2040         BUF->seqno[3] = uip_connr->snd_nxt[3];\r
2041 \r
2042         BUF->proto = UIP_PROTO_TCP;\r
2043 \r
2044         BUF->srcport = uip_connr->lport;\r
2045         BUF->destport = uip_connr->rport;\r
2046 \r
2047         uip_ipaddr_copy( BUF->srcipaddr, uip_hostaddr );\r
2048         uip_ipaddr_copy( BUF->destipaddr, uip_connr->ripaddr );\r
2049 \r
2050         if( uip_connr->tcpstateflags & UIP_STOPPED )\r
2051         {\r
2052                 /* If the connection has issued uip_stop(), we advertise a zero\r
2053        window so that the remote host will stop sending data. */\r
2054                 BUF->wnd[0] = BUF->wnd[1] = 0;\r
2055         }\r
2056         else\r
2057         {\r
2058                 BUF->wnd[0] = ( (UIP_RECEIVE_WINDOW) >> 8 );\r
2059                 BUF->wnd[1] = ( (UIP_RECEIVE_WINDOW) & 0xff );\r
2060         }\r
2061 \r
2062 tcp_send_noconn:\r
2063         BUF->ttl = UIP_TTL;\r
2064         #if UIP_CONF_IPV6\r
2065 \r
2066         /* For IPv6, the IP length field does not include the IPv6 IP header\r
2067      length. */\r
2068         BUF->len[0] = ( (uip_len - UIP_IPH_LEN) >> 8 );\r
2069         BUF->len[1] = ( (uip_len - UIP_IPH_LEN) & 0xff );\r
2070         #else /* UIP_CONF_IPV6 */\r
2071         BUF->len[0] = ( uip_len >> 8 );\r
2072         BUF->len[1] = ( uip_len & 0xff );\r
2073         #endif /* UIP_CONF_IPV6 */\r
2074 \r
2075         BUF->urgp[0] = BUF->urgp[1] = 0;\r
2076 \r
2077         /* Calculate TCP checksum. */\r
2078         BUF->tcpchksum = 0;\r
2079         BUF->tcpchksum = ~( uip_tcpchksum() );\r
2080 \r
2081         #if UIP_UDP\r
2082         ip_send_nolen :\r
2083         #endif\r
2084         #if UIP_CONF_IPV6\r
2085         BUF->vtc = 0x60;\r
2086         BUF->tcflow = 0x00;\r
2087         BUF->flow = 0x00;\r
2088         #else /* UIP_CONF_IPV6 */\r
2089         BUF->vhl = 0x45;\r
2090         BUF->tos = 0;\r
2091         BUF->ipoffset[0] = BUF->ipoffset[1] = 0;\r
2092         ++ipid;\r
2093         BUF->ipid[0] = ipid >> 8;\r
2094         BUF->ipid[1] = ipid & 0xff;\r
2095 \r
2096         /* Calculate IP checksum. */\r
2097         BUF->ipchksum = 0;\r
2098         BUF->ipchksum = ~( uip_ipchksum() );\r
2099         DEBUG_PRINTF( "uip ip_send_nolen: chkecum 0x%04x\n", uip_ipchksum() );\r
2100         #endif /* UIP_CONF_IPV6 */\r
2101 \r
2102         UIP_STAT( ++uip_stat.tcp.sent );\r
2103 send:\r
2104         DEBUG_PRINTF( "Sending packet with length %d (%d)\n", uip_len, (BUF->len[0] << 8) | BUF->len[1] );\r
2105 \r
2106         UIP_STAT( ++uip_stat.ip.sent );\r
2107 \r
2108         /* Return and let the caller do the actual transmission. */\r
2109         uip_flags = 0;\r
2110         return;\r
2111 drop:\r
2112         uip_len = 0;\r
2113         uip_flags = 0;\r
2114         return;\r
2115 }\r
2116 \r
2117 /*---------------------------------------------------------------------------*/\r
2118 u16_t htons( u16_t val )\r
2119 {\r
2120         return HTONS( val );\r
2121 }\r
2122 \r
2123 /*---------------------------------------------------------------------------*/\r
2124 void uip_send( const void *data, int len )\r
2125 {\r
2126         if( len > 0 )\r
2127         {\r
2128                 uip_slen = len;\r
2129                 if( data != uip_sappdata )\r
2130                 {\r
2131                         memcpy( uip_sappdata, (data), uip_slen );\r
2132                 }\r
2133         }\r
2134 }\r
2135 \r
2136 /*---------------------------------------------------------------------------*/\r
2137 int uip_fast_send( int xARP )\r
2138 {\r
2139         ( void ) xARP;\r
2140         #if NOT_YET_COMPLETE\r
2141 \r
2142         u16_t           tcplen, len1 = 0, uiAccumulatedLen = 0, len_previous = 0, split_len;\r
2143         int                     iSplitNo = 0;\r
2144         extern int      uip_low_level_output( unsigned char *pcBuf, int ilen );\r
2145 \r
2146         if( xARP == pdTRUE )\r
2147         {\r
2148                 if( BUF->proto == UIP_PROTO_TCP && uip_slen > 1 )\r
2149                 {\r
2150                         tcplen = uip_len - UIP_TCPIP_HLEN;\r
2151 \r
2152                         if( tcplen > UIP_TCP_MSS )\r
2153                         {\r
2154                                 split_len = UIP_TCP_MSS;\r
2155                         }\r
2156                         else\r
2157                         {\r
2158                                 split_len = tcplen / 2;\r
2159                         }\r
2160 \r
2161                         while( tcplen > 0 )\r
2162                         {\r
2163                                 uiAccumulatedLen += len1;\r
2164 \r
2165                                 if( tcplen > split_len )\r
2166                                 {\r
2167                                         len1 = split_len;\r
2168                                         tcplen -= split_len;\r
2169                                 }\r
2170                                 else\r
2171                                 {\r
2172                                         len1 = tcplen;\r
2173                                         tcplen = 0;\r
2174                                 }\r
2175 \r
2176                                 uip_len = len1 + UIP_TCPIP_HLEN;\r
2177                                 BUF->len[0] = uip_len >> 8;\r
2178                                 BUF->len[1] = uip_len & 0xff;\r
2179                                 if( iSplitNo == 0 )\r
2180                                 {\r
2181                                         iSplitNo++;\r
2182 \r
2183                                         /* Create the first packet. This is done by altering the length\r
2184                                         field of the IP header and updating the checksums. */\r
2185                                 }\r
2186                                 else\r
2187                                 {\r
2188                                         /* Now, create the second packet. To do this, it is not enough to\r
2189                                         just alter the length field, but we must also update the TCP\r
2190                                         sequence number and point the uip_appdata to a new place in\r
2191                                         memory. This place is determined by the length of the first\r
2192                                         packet (len1). */\r
2193 \r
2194                                         /*    uip_appdata += len1;*/\r
2195                                         memcpy( uip_appdata, ( u8_t * ) uip_appdata + uiAccumulatedLen, len1 );\r
2196                                         uip_add32( BUF->seqno, len_previous );\r
2197                                         BUF->seqno[0] = uip_acc32[0];\r
2198                                         BUF->seqno[1] = uip_acc32[1];\r
2199                                         BUF->seqno[2] = uip_acc32[2];\r
2200                                         BUF->seqno[3] = uip_acc32[3];\r
2201                                 }\r
2202 \r
2203                                 /* Recalculate the TCP checksum. */\r
2204                                 BUF->tcpchksum = 0;\r
2205                                 BUF->tcpchksum = ~( uip_tcpchksum() );\r
2206 \r
2207                                 /* Recalculate the IP checksum. */\r
2208                                 BUF->ipchksum = 0;\r
2209                                 BUF->ipchksum = ~( uip_ipchksum() );\r
2210 \r
2211                                 /* Transmit the packet. */\r
2212                                 uip_arp_out();\r
2213                                 uip_low_level_output( uip_buf, uip_len );\r
2214 \r
2215                                 len_previous = len1;\r
2216                         }\r
2217                 }\r
2218                 else\r
2219                 {\r
2220                         uip_arp_out();\r
2221                         uip_low_level_output( uip_buf, uip_len );\r
2222                 }\r
2223         }\r
2224         else\r
2225         {\r
2226                 uip_low_level_output( uip_buf, uip_len );\r
2227         }\r
2228 \r
2229         #endif\r
2230         return 1;\r
2231 }\r
2232 \r
2233 /** @} */\r