1 //#define DEBUG_PRINTF( ... ) /*printf(__VA_ARGS__)*/
\r
10 * The uIP TCP/IP stack code.
\r
11 * \author Adam Dunkels <adam@dunkels.com>
\r
15 * Copyright (c) 2001-2003, Adam Dunkels.
\r
16 * All rights reserved.
\r
18 * Redistribution and use in source and binary forms, with or without
\r
19 * modification, are permitted provided that the following conditions
\r
21 * 1. Redistributions of source code must retain the above copyright
\r
22 * notice, this list of conditions and the following disclaimer.
\r
23 * 2. Redistributions in binary form must reproduce the above copyright
\r
24 * notice, this list of conditions and the following disclaimer in the
\r
25 * documentation and/or other materials provided with the distribution.
\r
26 * 3. The name of the author may not be used to endorse or promote
\r
27 * products derived from this software without specific prior
\r
28 * written permission.
\r
30 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
\r
31 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
\r
32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
\r
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
\r
34 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
\r
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
\r
36 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
\r
37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
\r
38 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
39 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
\r
40 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
42 * This file is part of the uIP TCP/IP stack.
\r
44 * $Id: uip.c,v 1.15 2008/10/15 08:08:32 adamdunkels Exp $
\r
49 * uIP is a small implementation of the IP, UDP and TCP protocols (as
\r
50 * well as some basic ICMP stuff). The implementation couples the IP,
\r
51 * UDP, TCP and the application layers very tightly. To keep the size
\r
52 * of the compiled code down, this code frequently uses the goto
\r
53 * statement. While it would be possible to break the uip_process()
\r
54 * function into many smaller functions, this would increase the code
\r
55 * size because of the overhead of parameter passing and the fact that
\r
56 * the optimier would not be as efficient.
\r
58 * The principle is that we have a small buffer, called the uip_buf,
\r
59 * in which the device driver puts an incoming packet. The TCP/IP
\r
60 * stack parses the headers in the packet, and calls the
\r
61 * application. If the remote host has sent data to the application,
\r
62 * this data is present in the uip_buf and the application read the
\r
63 * data from there. It is up to the application to put this data into
\r
64 * a byte stream if needed. The application will not be fed with data
\r
65 * that is out of sequence.
\r
67 * If the application whishes to send data to the peer, it should put
\r
68 * its data into the uip_buf. The uip_appdata pointer points to the
\r
69 * first available byte. The TCP/IP stack will calculate the
\r
70 * checksums, and fill in the necessary header fields and finally send
\r
71 * the packet back to the peer.
\r
73 #include "net/uip.h"
\r
74 #include "net/uipopt.h"
\r
75 #include "net/uip_arp.h"
\r
76 #include "net/uip_arch.h"
\r
78 /* If UIP_CONF_IPV6 is defined, we compile the uip6.c file instead of this one.
\r
79 Therefore this #ifndef removes the entire compilation output of the uip.c file */
\r
83 #include "net/uip-neighbor.h"
\r
84 #endif /* UIP_CONF_IPV6 */
\r
88 /*---------------------------------------------------------------------------*/
\r
90 /* Variable definitions. */
\r
92 /* The IP address of this host. If it is defined to be fixed (by setting
\r
93 UIP_FIXEDADDR to 1 in uipopt.h), the address is set here. Otherwise, the address */
\r
94 #if UIP_FIXEDADDR > 0
\r
95 const uip_ipaddr_t uip_hostaddr = { UIP_IPADDR0, UIP_IPADDR1, UIP_IPADDR2, UIP_IPADDR3 };
\r
96 const uip_ipaddr_t uip_draddr = { UIP_DRIPADDR0, UIP_DRIPADDR1, UIP_DRIPADDR2, UIP_DRIPADDR3 };
\r
97 const uip_ipaddr_t uip_netmask = { UIP_NETMASK0, UIP_NETMASK1, UIP_NETMASK2, UIP_NETMASK3 };
\r
99 uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;
\r
100 #endif /* UIP_FIXEDADDR */
\r
102 const uip_ipaddr_t uip_broadcast_addr =
\r
104 { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
\r
105 #else /* UIP_CONF_IPV6 */
\r
106 { { 0xff, 0xff, 0xff, 0xff } };
\r
107 #endif /* UIP_CONF_IPV6 */
\r
109 const uip_ipaddr_t uip_all_zeroes_addr = { { 0x0, /* rest is 0 */ } };
\r
111 #if UIP_FIXEDETHADDR
\r
112 const struct uip_eth_addr uip_ethaddr = { { UIP_ETHADDR0, UIP_ETHADDR1, UIP_ETHADDR2, UIP_ETHADDR3, UIP_ETHADDR4, UIP_ETHADDR5 } };
\r
114 struct uip_eth_addr uip_ethaddr = { { 0, 0, 0, 0, 0, 0 } };
\r
117 #ifndef UIP_CONF_EXTERNAL_BUFFER
\r
118 /* The packet buffer that contains incoming packets. */
\r
119 u8_t uip_buf[ UIP_BUFSIZE + 2 ];
\r
120 #endif /* UIP_CONF_EXTERNAL_BUFFER */
\r
122 /* The uip_appdata pointer points to application data. */
\r
125 /* The uip_appdata pointer points to the application data which is to be sent. */
\r
126 void *uip_sappdata;
\r
128 #if UIP_URGDATA > 0
\r
129 /* The uip_urgdata pointer points to urgent data (out-of-band data), if
\r
132 u16_t uip_urglen, uip_surglen;
\r
133 #endif /* UIP_URGDATA > 0 */
\r
135 /* The uip_len is either 8 or 16 bits, depending on the maximum packet size. */
\r
136 u16_t uip_len, uip_slen;
\r
138 /* The uip_flags variable is used for communication between the TCP/IP stack
\r
139 and the application program. */
\r
142 /* uip_conn always points to the current connection. */
\r
143 struct uip_conn *uip_conn;
\r
144 struct uip_conn uip_conns[ UIP_CONNS ];
\r
146 /* The uip_conns array holds all TCP connections. */
\r
147 u16_t uip_listenports[UIP_LISTENPORTS];
\r
149 /* The uip_listenports list all currently listning ports. */
\r
151 struct uip_udp_conn *uip_udp_conn;
\r
152 struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
\r
153 #endif /* UIP_UDP */
\r
155 /* Ths ipid variable is an increasing number that is used for the IP ID field. */
\r
158 void uip_setipid( u16_t id )
\r
163 /* The iss variable is used for the TCP initial sequence number. */
\r
164 static u8_t iss[ 4 ];
\r
166 #if UIP_ACTIVE_OPEN
\r
167 /* Keeps track of the last port used for a new connection. */
\r
168 static u16_t lastport;
\r
169 #endif /* UIP_ACTIVE_OPEN */
\r
171 /* Temporary variables. */
\r
172 u8_t uip_acc32[ 4 ];
\r
173 static u8_t c, opt;
\r
174 static u16_t tmp16;
\r
176 /* Structures and definitions. */
\r
177 #define TCP_FIN 0x01
\r
178 #define TCP_SYN 0x02
\r
179 #define TCP_RST 0x04
\r
180 #define TCP_PSH 0x08
\r
181 #define TCP_ACK 0x10
\r
182 #define TCP_URG 0x20
\r
183 #define TCP_CTL 0x3f
\r
185 #define TCP_OPT_END 0 /* End of TCP options list */
\r
186 #define TCP_OPT_NOOP 1 /* "No-operation" TCP option */
\r
187 #define TCP_OPT_MSS 2 /* Maximum segment size TCP option */
\r
189 #define TCP_OPT_MSS_LEN 4 /* Length of TCP MSS option. */
\r
191 #define ICMP_ECHO_REPLY 0
\r
192 #define ICMP_ECHO 8
\r
194 #define ICMP_DEST_UNREACHABLE 3
\r
195 #define ICMP_PORT_UNREACHABLE 3
\r
197 #define ICMP6_ECHO_REPLY 129
\r
198 #define ICMP6_ECHO 128
\r
199 #define ICMP6_NEIGHBOR_SOLICITATION 135
\r
200 #define ICMP6_NEIGHBOR_ADVERTISEMENT 136
\r
202 #define ICMP6_FLAG_S ( 1 << 6 )
\r
203 #define ICMP6_OPTION_SOURCE_LINK_ADDRESS 1
\r
204 #define ICMP6_OPTION_TARGET_LINK_ADDRESS 2
\r
207 #define BUF ( ( struct uip_tcpip_hdr * ) &uip_buf[UIP_LLH_LEN] )
\r
208 #define FBUF ( ( struct uip_tcpip_hdr * ) &uip_reassbuf[0] )
\r
209 #define ICMPBUF ( ( struct uip_icmpip_hdr * ) &uip_buf[UIP_LLH_LEN] )
\r
210 #define UDPBUF ( ( struct uip_udpip_hdr * ) &uip_buf[UIP_LLH_LEN] )
\r
212 #if UIP_STATISTICS == 1
\r
213 struct uip_stats uip_stat;
\r
214 #define UIP_STAT( s ) s
\r
216 #define UIP_STAT( s )
\r
217 #endif /* UIP_STATISTICS == 1 */
\r
219 #if UIP_LOGGING == 1
\r
221 void uip_log( char *msg );
\r
222 #define UIP_LOG( m ) uip_log( m )
\r
224 #define UIP_LOG( m )
\r
225 #endif /* UIP_LOGGING == 1 */
\r
227 #if !UIP_ARCH_ADD32
\r
228 void uip_add32( u8_t *op32, u16_t op16 )
\r
230 uip_acc32[3] = op32[3] + ( op16 & 0xff );
\r
231 uip_acc32[2] = op32[2] + ( op16 >> 8 );
\r
232 uip_acc32[1] = op32[1];
\r
233 uip_acc32[0] = op32[0];
\r
235 if( uip_acc32[2] < (op16 >> 8) )
\r
238 if( uip_acc32[1] == 0 )
\r
244 if( uip_acc32[3] < (op16 & 0xff) )
\r
247 if( uip_acc32[2] == 0 )
\r
250 if( uip_acc32[1] == 0 )
\r
257 /*---------------------------------------------------------------------------*/
\r
258 #endif /* UIP_ARCH_ADD32 */
\r
260 #if !UIP_ARCH_CHKSUM
\r
262 static u16_t chksum( u16_t sum, const u8_t *data, u16_t len )
\r
265 const u8_t *dataptr;
\r
266 const u8_t *last_byte;
\r
269 last_byte = data + len - 1;
\r
271 while( dataptr < last_byte )
\r
273 /* At least two more bytes */
\r
274 t = ( dataptr[ 0 ] << 8 ) + dataptr[ 1 ];
\r
284 if( dataptr == last_byte )
\r
286 t = ( dataptr[ 0 ] << 8 ) + 0;
\r
294 /* Return sum in host byte order. */
\r
297 /*---------------------------------------------------------------------------*/
\r
299 u16_t uip_chksum( u16_t *data, u16_t len )
\r
301 return htons( chksum( 0, ( u8_t * ) data, len ) );
\r
303 /*---------------------------------------------------------------------------*/
\r
305 #ifndef UIP_ARCH_IPCHKSUM
\r
306 u16_t uip_ipchksum( void )
\r
310 sum = chksum( 0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN );
\r
312 //DEBUG_PRINTF( "uip_ipchksum: sum 0x%04x\n", sum );
\r
313 return( sum == 0 ) ? 0xffff : htons( sum );
\r
316 /*---------------------------------------------------------------------------*/
\r
318 static u16_t upper_layer_chksum( u8_t proto )
\r
320 u16_t upper_layer_len;
\r
324 upper_layer_len = ( ((u16_t) (BUF->len[ 0 ]) << 8) + BUF->len[ 1 ] );
\r
325 #else /* UIP_CONF_IPV6 */
\r
326 upper_layer_len = ( ((u16_t) (BUF->len[ 0 ]) << 8) + BUF->len[ 1 ] ) - UIP_IPH_LEN;
\r
327 #endif /* UIP_CONF_IPV6 */
\r
329 /* First sum pseudoheader. */
\r
331 /* IP protocol and length fields. This addition cannot carry. */
\r
332 sum = upper_layer_len + proto;
\r
334 /* Sum IP source and destination addresses. */
\r
335 sum = chksum( sum, ( u8_t * ) &BUF->srcipaddr, 2 * sizeof(uip_ipaddr_t) );
\r
337 /* Sum TCP header and data. */
\r
338 sum = chksum( sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_len );
\r
340 return( sum == 0 ) ? 0xffff : htons( sum );
\r
342 /*---------------------------------------------------------------------------*/
\r
345 u16_t uip_icmp6chksum( void )
\r
347 return upper_layer_chksum( UIP_PROTO_ICMP6 );
\r
349 #endif /* UIP_CONF_IPV6 */
\r
350 /*---------------------------------------------------------------------------*/
\r
352 u16_t uip_tcpchksum( void )
\r
354 return upper_layer_chksum( UIP_PROTO_TCP );
\r
356 /*---------------------------------------------------------------------------*/
\r
358 #if UIP_UDP_CHECKSUMS
\r
359 u16_t uip_udpchksum( void )
\r
361 return upper_layer_chksum( UIP_PROTO_UDP );
\r
363 #endif /* UIP_UDP_CHECKSUMS */
\r
365 #endif /* UIP_ARCH_CHKSUM */
\r
366 /*---------------------------------------------------------------------------*/
\r
368 void uip_init( void )
\r
370 for( c = 0; c < UIP_LISTENPORTS; ++c )
\r
372 uip_listenports[ c ] = 0;
\r
375 for( c = 0; c < UIP_CONNS; ++c )
\r
377 uip_conns[ c ].tcpstateflags = UIP_CLOSED;
\r
380 #if UIP_ACTIVE_OPEN
\r
382 #endif /* UIP_ACTIVE_OPEN */
\r
385 for( c = 0; c < UIP_UDP_CONNS; ++c )
\r
387 uip_udp_conns[ c ].lport = 0;
\r
389 #endif /* UIP_UDP */
\r
391 /* IPv4 initialization. */
\r
392 #if UIP_FIXEDADDR == 0
\r
393 /* uip_hostaddr[ 0 ] = uip_hostaddr[ 1 ] = 0;*/
\r
394 #endif /* UIP_FIXEDADDR */
\r
396 /*---------------------------------------------------------------------------*/
\r
398 #if UIP_ACTIVE_OPEN
\r
399 struct uip_conn *uip_connect( uip_ipaddr_t *ripaddr, u16_t rport )
\r
401 register struct uip_conn *conn, *cconn;
\r
403 /* Find an unused local port. */
\r
407 if( lastport >= 32000 )
\r
412 /* Check if this port is already in use, and if so try to find
\r
414 for( c = 0; c < UIP_CONNS; ++c )
\r
416 conn = &uip_conns[ c ];
\r
417 if( conn->tcpstateflags != UIP_CLOSED && conn->lport == htons(lastport) )
\r
424 for( c = 0; c < UIP_CONNS; ++c )
\r
426 cconn = &uip_conns[ c ];
\r
427 if( cconn->tcpstateflags == UIP_CLOSED )
\r
433 if( cconn->tcpstateflags == UIP_TIME_WAIT )
\r
435 if( conn == 0 || cconn->timer > conn->timer )
\r
447 conn->tcpstateflags = UIP_SYN_SENT;
\r
449 conn->snd_nxt[ 0 ] = iss[ 0 ];
\r
450 conn->snd_nxt[ 1 ] = iss[ 1 ];
\r
451 conn->snd_nxt[ 2 ] = iss[ 2 ];
\r
452 conn->snd_nxt[ 3 ] = iss[ 3 ];
\r
454 conn->initialmss = conn->mss = UIP_TCP_MSS;
\r
456 conn->len = 1; /* TCP length of the SYN is one. */
\r
458 conn->timer = 1; /* Send the SYN next time around. */
\r
459 conn->rto = UIP_RTO;
\r
461 conn->sv = 16; /* Initial value of the RTT variance. */
\r
462 conn->lport = htons( lastport );
\r
463 conn->rport = rport;
\r
464 uip_ipaddr_copy( &conn->ripaddr, ripaddr );
\r
468 /*---------------------------------------------------------------------------*/
\r
469 #endif /* UIP_ACTIVE_OPEN */
\r
472 struct uip_udp_conn *uip_udp_new( const uip_ipaddr_t *ripaddr, u16_t rport )
\r
474 register struct uip_udp_conn *conn;
\r
476 /* Find an unused local port. */
\r
480 if( lastport >= 32000 )
\r
485 for( c = 0; c < UIP_UDP_CONNS; ++c )
\r
487 if( uip_udp_conns[ c ].lport == htons(lastport) )
\r
494 for( c = 0; c < UIP_UDP_CONNS; ++c )
\r
496 if( uip_udp_conns[ c ].lport == 0 )
\r
498 conn = &uip_udp_conns[ c ];
\r
508 conn->lport = HTONS( lastport );
\r
509 conn->rport = rport;
\r
510 if( ripaddr == NULL )
\r
512 memset( &conn->ripaddr, 0, sizeof(uip_ipaddr_t) );
\r
516 uip_ipaddr_copy( &conn->ripaddr, ripaddr );
\r
519 conn->ttl = UIP_TTL;
\r
523 /*---------------------------------------------------------------------------*/
\r
524 #endif /* UIP_UDP */
\r
526 void uip_unlisten( u16_t port )
\r
528 for( c = 0; c < UIP_LISTENPORTS; ++c )
\r
530 if( uip_listenports[ c ] == port )
\r
532 uip_listenports[ c ] = 0;
\r
537 /*---------------------------------------------------------------------------*/
\r
539 void uip_listen( u16_t port )
\r
541 for( c = 0; c < UIP_LISTENPORTS; ++c )
\r
543 if( uip_listenports[ c ] == 0 )
\r
545 uip_listenports[ c ] = port;
\r
550 /*---------------------------------------------------------------------------*/
\r
552 /* XXX: IP fragment reassembly: not well-tested. */
\r
553 #if UIP_REASSEMBLY && !UIP_CONF_IPV6
\r
554 #define UIP_REASS_BUFSIZE ( UIP_BUFSIZE - UIP_LLH_LEN )
\r
555 static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
\r
556 static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / ( 8 * 8 )];
\r
557 static const u8_t bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
\r
558 static u16_t uip_reasslen;
\r
559 static u8_t uip_reassflags;
\r
560 #define UIP_REASS_FLAG_LASTFRAG 0x01
\r
561 static u8_t uip_reasstmr;
\r
565 static u8_t uip_reass( void )
\r
570 /* If ip_reasstmr is zero, no packet is present in the buffer, so we
\r
571 write the IP header of the fragment into the reassembly
\r
572 buffer. The timer is updated with the maximum age. */
\r
573 if( uip_reasstmr == 0 )
\r
575 memcpy( uip_reassbuf, &BUF->vhl, UIP_IPH_LEN );
\r
576 uip_reasstmr = UIP_REASS_MAXAGE;
\r
577 uip_reassflags = 0;
\r
579 /* Clear the bitmap. */
\r
580 memset( uip_reassbitmap, 0, sizeof(uip_reassbitmap) );
\r
583 /* Check if the incoming fragment matches the one currently present
\r
584 in the reasembly buffer. If so, we proceed with copying the
\r
585 fragment into the buffer. */
\r
588 BUF->srcipaddr[ 0 ] == FBUF->srcipaddr[ 0 ] &&
\r
589 BUF->srcipaddr[ 1 ] == FBUF->srcipaddr[ 1 ] &&
\r
590 BUF->destipaddr[ 0 ] == FBUF->destipaddr[ 0 ] &&
\r
591 BUF->destipaddr[ 1 ] == FBUF->destipaddr[ 1 ] &&
\r
592 BUF->ipid[ 0 ] == FBUF->ipid[ 0 ] &&
\r
593 BUF->ipid[ 1 ] == FBUF->ipid[ 1 ]
\r
596 len = ( BUF->len[ 0 ] << 8 ) + BUF->len[ 1 ] - ( BUF->vhl & 0x0f ) * 4;
\r
597 offset = ( ((BUF->ipoffset[ 0 ] & 0x3f) << 8) + BUF->ipoffset[ 1 ] ) * 8;
\r
599 /* If the offset or the offset + fragment length overflows the
\r
600 reassembly buffer, we discard the entire packet. */
\r
601 if( offset > UIP_REASS_BUFSIZE || offset + len > UIP_REASS_BUFSIZE )
\r
607 /* Copy the fragment into the reassembly buffer, at the right
\r
609 memcpy( &uip_reassbuf[UIP_IPH_LEN + offset], ( char * ) BUF + ( int ) ((BUF->vhl & 0x0f) * 4), len );
\r
611 /* Update the bitmap. */
\r
612 if( offset / (8 * 8) == (offset + len) / (8 * 8) )
\r
614 /* If the two endpoints are in the same byte, we only update
\r
616 uip_reassbitmap[offset / ( 8 * 8 )] |= bitmap_bits[( offset / 8 ) & 7] &~bitmap_bits[( (offset + len) / 8 ) & 7];
\r
620 /* If the two endpoints are in different bytes, we update the
\r
621 bytes in the endpoints and fill the stuff inbetween with
\r
623 uip_reassbitmap[offset / ( 8 * 8 )] |= bitmap_bits[( offset / 8 ) & 7];
\r
624 for( i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i )
\r
626 uip_reassbitmap[i] = 0xff;
\r
629 uip_reassbitmap[( offset + len ) / ( 8 * 8 )] |= ~bitmap_bits[( (offset + len) / 8 ) & 7];
\r
632 /* If this fragment has the More Fragments flag set to zero, we
\r
633 know that this is the last fragment, so we can calculate the
\r
634 size of the entire packet. We also set the
\r
635 IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
\r
636 the final fragment. */
\r
637 if( (BUF->ipoffset[ 0 ] & IP_MF) == 0 )
\r
639 uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
\r
640 uip_reasslen = offset + len;
\r
643 /* Finally, we check if we have a full packet in the buffer. We do
\r
644 this by checking if we have the last fragment and if all bits
\r
645 in the bitmap are set. */
\r
646 if( uip_reassflags & UIP_REASS_FLAG_LASTFRAG )
\r
648 /* Check all bytes up to and including all but the last byte in
\r
650 for( i = 0; i < uip_reasslen / (8 * 8) - 1; ++i )
\r
652 if( uip_reassbitmap[i] != 0xff )
\r
658 /* Check the last byte in the bitmap. It should contain just the
\r
659 right amount of bits. */
\r
660 if( uip_reassbitmap[uip_reasslen / (8 * 8)] != (u8_t)~bitmap_bits[uip_reasslen / 8 & 7] )
\r
665 /* If we have come this far, we have a full packet in the
\r
666 buffer, so we allocate a pbuf and copy the packet into it. We
\r
667 also reset the timer. */
\r
669 memcpy( BUF, FBUF, uip_reasslen );
\r
671 /* Pretend to be a "normal" (i.e., not fragmented) IP packet
\r
673 BUF->ipoffset[ 0 ] = BUF->ipoffset[ 1 ] = 0;
\r
674 BUF->len[ 0 ] = uip_reasslen >> 8;
\r
675 BUF->len[ 1 ] = uip_reasslen & 0xff;
\r
677 BUF->ipchksum = ~( uip_ipchksum() );
\r
679 return uip_reasslen;
\r
687 /*---------------------------------------------------------------------------*/
\r
688 #endif /* UIP_REASSEMBLY */
\r
691 static void uip_add_rcv_nxt( u16_t n )
\r
693 uip_add32( uip_conn->rcv_nxt, n );
\r
694 uip_conn->rcv_nxt[ 0 ] = uip_acc32[ 0 ];
\r
695 uip_conn->rcv_nxt[ 1 ] = uip_acc32[ 1 ];
\r
696 uip_conn->rcv_nxt[ 2 ] = uip_acc32[ 2 ];
\r
697 uip_conn->rcv_nxt[ 3 ] = uip_acc32[ 3 ];
\r
699 /*---------------------------------------------------------------------------*/
\r
701 void uip_process( u8_t flag )
\r
703 register struct uip_conn *uip_connr = uip_conn;
\r
706 if( flag == UIP_UDP_SEND_CONN )
\r
710 #endif /* UIP_UDP */
\r
712 uip_sappdata = uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN];
\r
714 /* Check if we were invoked because of a poll request for a
\r
715 particular connection. */
\r
716 if( flag == UIP_POLL_REQUEST )
\r
718 if( (uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED && !uip_outstanding(uip_connr) )
\r
720 uip_flags = UIP_POLL;
\r
727 /* Check if we were invoked because of the perodic timer fireing. */
\r
729 else if( flag == UIP_TIMER )
\r
732 if( uip_reasstmr != 0 )
\r
736 #endif /* UIP_REASSEMBLY */
\r
738 /* Increase the initial sequence number. */
\r
739 if( ++iss[ 3 ] == 0 )
\r
741 if( ++iss[ 2 ] == 0 )
\r
743 if( ++iss[ 1 ] == 0 )
\r
750 /* Reset the length variables. */
\r
754 /* Check if the connection is in a state in which we simply wait
\r
755 for the connection to time out. If so, we increase the
\r
756 connection's timer and remove the connection if it times
\r
758 if( uip_connr->tcpstateflags == UIP_TIME_WAIT || uip_connr->tcpstateflags == UIP_FIN_WAIT_2 )
\r
760 ++( uip_connr->timer );
\r
761 if( uip_connr->timer == UIP_TIME_WAIT_TIMEOUT )
\r
763 uip_connr->tcpstateflags = UIP_CLOSED;
\r
766 else if( uip_connr->tcpstateflags != UIP_CLOSED )
\r
768 /* If the connection has outstanding data, we increase the
\r
769 connection's timer and see if it has reached the RTO value
\r
770 in which case we retransmit. */
\r
771 if( uip_outstanding(uip_connr) )
\r
773 if( uip_connr->timer-- == 0 )
\r
777 uip_connr->nrtx == UIP_MAXRTX ||
\r
779 (uip_connr->tcpstateflags == UIP_SYN_SENT || uip_connr->tcpstateflags == UIP_SYN_RCVD) &&
\r
780 uip_connr->nrtx == UIP_MAXSYNRTX
\r
784 uip_connr->tcpstateflags = UIP_CLOSED;
\r
786 /* We call UIP_APPCALL() with uip_flags set to
\r
787 UIP_TIMEDOUT to inform the application that the
\r
788 connection has timed out. */
\r
789 uip_flags = UIP_TIMEDOUT;
\r
792 /* We also send a reset packet to the remote host. */
\r
793 BUF->flags = TCP_RST | TCP_ACK;
\r
794 goto tcp_send_nodata;
\r
797 /* Exponential backoff. */
\r
798 uip_connr->timer = UIP_RTO << ( uip_connr->nrtx > 4 ? 4 : uip_connr->nrtx );
\r
799 ++( uip_connr->nrtx );
\r
801 /* Ok, so we need to retransmit. We do this differently
\r
802 depending on which state we are in. In ESTABLISHED, we
\r
803 call upon the application so that it may prepare the
\r
804 data for the retransmit. In SYN_RCVD, we resend the
\r
805 SYNACK that we sent earlier and in LAST_ACK we have to
\r
806 retransmit our FINACK. */
\r
807 UIP_STAT( ++uip_stat.tcp.rexmit );
\r
808 switch( uip_connr->tcpstateflags & UIP_TS_MASK )
\r
811 /* In the SYN_RCVD state, we should retransmit our
\r
813 goto tcp_send_synack;
\r
815 #if UIP_ACTIVE_OPEN
\r
817 /* In the SYN_SENT state, we retransmit out SYN. */
\r
820 #endif /* UIP_ACTIVE_OPEN */
\r
822 case UIP_ESTABLISHED:
\r
823 /* In the ESTABLISHED state, we call upon the application
\r
824 to do the actual retransmit after which we jump into
\r
825 the code for sending out the packet (the apprexmit
\r
827 uip_flags = UIP_REXMIT;
\r
831 case UIP_FIN_WAIT_1:
\r
834 /* In all these states we should retransmit a FINACK. */
\r
835 goto tcp_send_finack;
\r
839 else if( (uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED )
\r
841 /* If there was no need for a retransmission, we poll the
\r
842 application for new data. */
\r
843 uip_flags = UIP_POLL;
\r
853 if( flag == UIP_UDP_TIMER )
\r
855 if( uip_udp_conn->lport != 0 )
\r
858 uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
\r
859 uip_len = uip_slen = 0;
\r
860 uip_flags = UIP_POLL;
\r
871 /* This is where the input processing starts. */
\r
872 UIP_STAT( ++uip_stat.ip.recv );
\r
874 /* Start of IP input header processing code. */
\r
876 /* Check validity of the IP header. */
\r
877 if( (BUF->vtc & 0xf0) != 0x60 )
\r
878 { /* IP version and header length. */
\r
879 UIP_STAT( ++uip_stat.ip.drop );
\r
880 UIP_STAT( ++uip_stat.ip.vhlerr );
\r
881 UIP_LOG( "ipv6: invalid version." );
\r
885 #else /* UIP_CONF_IPV6 */
\r
886 /* Check validity of the IP header. */
\r
887 if( BUF->vhl != 0x45 )
\r
888 { /* IP version and header length. */
\r
889 UIP_STAT( ++uip_stat.ip.drop );
\r
890 UIP_STAT( ++uip_stat.ip.vhlerr );
\r
891 UIP_LOG( "ip: invalid version or header length." );
\r
895 #endif /* UIP_CONF_IPV6 */
\r
897 /* Check the size of the packet. If the size reported to us in
\r
898 uip_len is smaller the size reported in the IP header, we assume
\r
899 that the packet has been corrupted in transit. If the size of
\r
900 uip_len is larger than the size reported in the IP packet header,
\r
901 the packet has been padded and we set uip_len to the correct
\r
903 if( (BUF->len[ 0 ] << 8) + BUF->len[ 1 ] <= uip_len )
\r
905 uip_len = ( BUF->len[ 0 ] << 8 ) + BUF->len[ 1 ];
\r
907 /* The length reported in the IPv6 header is the
\r
908 length of the payload that follows the
\r
909 header. However, uIP uses the uip_len variable
\r
910 for holding the size of the entire packet,
\r
911 including the IP header. For IPv4 this is not a
\r
912 problem as the length field in the IPv4 header
\r
913 contains the length of the entire packet. But
\r
914 for IPv6 we need to add the size of the IPv6
\r
915 header (40 bytes). */
\r
917 #endif /* UIP_CONF_IPV6 */
\r
921 UIP_LOG( "ip: packet shorter than reported in IP header." );
\r
926 /* Check the fragment flag. */
\r
927 if( (BUF->ipoffset[ 0 ] & 0x3f) != 0 || BUF->ipoffset[ 1 ] != 0 )
\r
930 uip_len = uip_reass();
\r
935 #else /* UIP_REASSEMBLY */
\r
936 UIP_STAT( ++uip_stat.ip.drop );
\r
937 UIP_STAT( ++uip_stat.ip.fragerr );
\r
938 UIP_LOG( "ip: fragment dropped." );
\r
940 #endif /* UIP_REASSEMBLY */
\r
942 #endif /* UIP_CONF_IPV6 */
\r
944 if( uip_ipaddr_cmp(&uip_hostaddr, &uip_all_zeroes_addr) )
\r
946 /* If we are configured to use ping IP address configuration and
\r
947 hasn't been assigned an IP address yet, we accept all ICMP
\r
949 #if UIP_PINGADDRCONF && !UIP_CONF_IPV6
\r
950 if( BUF->proto == UIP_PROTO_ICMP )
\r
952 UIP_LOG( "ip: possible ping config packet received." );
\r
957 UIP_LOG( "ip: packet dropped since no address assigned." );
\r
960 #endif /* UIP_PINGADDRCONF */
\r
964 /* If IP broadcast support is configured, we check for a broadcast
\r
965 UDP packet, which may be destined to us. */
\r
967 //DEBUG_PRINTF( "UDP IP checksum 0x%04x\n", uip_ipchksum() );
\r
968 if( BUF->proto == UIP_PROTO_UDP && uip_ipaddr_cmp(&BUF->destipaddr, &uip_broadcast_addr) /*&& uip_ipchksum() == 0xffff*/ )
\r
972 #endif /* UIP_BROADCAST */
\r
974 /* Check if the packet is destined for our IP address. */
\r
976 if( !uip_ipaddr_cmp(&BUF->destipaddr, &uip_hostaddr) )
\r
978 UIP_STAT( ++uip_stat.ip.drop );
\r
981 #else /* UIP_CONF_IPV6 */
\r
982 /* For IPv6, packet reception is a little trickier as we need to
\r
983 make sure that we listen to certain multicast addresses (all
\r
984 hosts multicast address, and the solicited-node multicast
\r
985 address) as well. However, we will cheat here and accept all
\r
986 multicast packets that are sent to the ff02::/16 addresses. */
\r
987 if( !uip_ipaddr_cmp(&BUF->destipaddr, &uip_hostaddr) && BUF->destipaddr.u16[ 0 ] != HTONS(0xff02) )
\r
989 UIP_STAT( ++uip_stat.ip.drop );
\r
992 #endif /* UIP_CONF_IPV6 */
\r
996 if( uip_ipchksum() != 0xffff )
\r
998 /* Compute and check the IP header checksum. */
\r
999 UIP_STAT( ++uip_stat.ip.drop );
\r
1000 UIP_STAT( ++uip_stat.ip.chkerr );
\r
1001 UIP_LOG( "ip: bad checksum." );
\r
1004 #endif /* UIP_CONF_IPV6 */
\r
1006 if( BUF->proto == UIP_PROTO_TCP )
\r
1008 /* Check for TCP packet. If so, proceed with TCP input processing. */
\r
1013 if( BUF->proto == UIP_PROTO_UDP )
\r
1017 #endif /* UIP_UDP */
\r
1019 #if !UIP_CONF_IPV6
\r
1020 /* ICMPv4 processing code follows. */
\r
1021 if( BUF->proto != UIP_PROTO_ICMP )
\r
1023 /* We only allow ICMP packets from here. */
\r
1024 UIP_STAT( ++uip_stat.ip.drop );
\r
1025 UIP_STAT( ++uip_stat.ip.protoerr );
\r
1026 UIP_LOG( "ip: neither tcp nor icmp." );
\r
1030 #if UIP_PINGADDRCONF
\r
1032 #endif /* UIP_PINGADDRCONF */
\r
1034 UIP_STAT( ++uip_stat.icmp.recv );
\r
1036 /* ICMP echo (i.e., ping) processing. This is simple, we only change
\r
1037 the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
\r
1038 checksum before we return the packet. */
\r
1039 if( ICMPBUF->type != ICMP_ECHO )
\r
1041 UIP_STAT( ++uip_stat.icmp.drop );
\r
1042 UIP_STAT( ++uip_stat.icmp.typeerr );
\r
1043 UIP_LOG( "icmp: not icmp echo." );
\r
1047 /* If we are configured to use ping IP address assignment, we use
\r
1048 the destination IP address of this ping packet and assign it to
\r
1050 #if UIP_PINGADDRCONF
\r
1051 if( uip_ipaddr_cmp(&uip_hostaddr, &uip_all_zeroes_addr) )
\r
1053 uip_hostaddr = BUF->destipaddr;
\r
1055 #endif /* UIP_PINGADDRCONF */
\r
1057 ICMPBUF->type = ICMP_ECHO_REPLY;
\r
1059 if( ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8)) )
\r
1061 ICMPBUF->icmpchksum += HTONS( ICMP_ECHO << 8 ) + 1;
\r
1065 ICMPBUF->icmpchksum += HTONS( ICMP_ECHO << 8 );
\r
1068 /* Swap IP addresses. */
\r
1069 uip_ipaddr_copy( &BUF->destipaddr, &BUF->srcipaddr );
\r
1070 uip_ipaddr_copy( &BUF->srcipaddr, &uip_hostaddr );
\r
1072 UIP_STAT( ++uip_stat.icmp.sent );
\r
1073 BUF->ttl = UIP_TTL;
\r
1074 goto ip_send_nolen;
\r
1076 /* End of IPv4 input header processing code. */
\r
1078 #else /* !UIP_CONF_IPV6 */
\r
1080 /* This is IPv6 ICMPv6 processing code. */
\r
1082 //DEBUG_PRINTF( "icmp6_input: length %d\n", uip_len );
\r
1083 if( BUF->proto != UIP_PROTO_ICMP6 )
\r
1085 /* We only allow ICMPv6 packets from here. */
\r
1086 UIP_STAT( ++uip_stat.ip.drop );
\r
1087 UIP_STAT( ++uip_stat.ip.protoerr );
\r
1088 UIP_LOG( "ip: neither tcp nor icmp6." );
\r
1092 UIP_STAT( ++uip_stat.icmp.recv );
\r
1094 /* If we get a neighbor solicitation for our address we should send
\r
1095 a neighbor advertisement message back. */
\r
1096 if( ICMPBUF->type == ICMP6_NEIGHBOR_SOLICITATION )
\r
1098 if( uip_ipaddr_cmp(&ICMPBUF->icmp6data, &uip_hostaddr) )
\r
1100 if( ICMPBUF->options[ 0 ] == ICMP6_OPTION_SOURCE_LINK_ADDRESS )
\r
1102 /* Save the sender's address in our neighbor list. */
\r
1103 uip_neighbor_add( &ICMPBUF->srcipaddr, &(ICMPBUF->options[ 2 ]) );
\r
1106 /* We should now send a neighbor advertisement back to where the
\r
1107 neighbor solicication came from. */
\r
1108 ICMPBUF->type = ICMP6_NEIGHBOR_ADVERTISEMENT;
\r
1109 ICMPBUF->flags = ICMP6_FLAG_S; /* Solicited flag. */
\r
1111 ICMPBUF->reserved1 = ICMPBUF->reserved2 = ICMPBUF->reserved3 = 0;
\r
1113 uip_ipaddr_copy( &ICMPBUF->destipaddr, &ICMPBUF->srcipaddr );
\r
1114 uip_ipaddr_copy( &ICMPBUF->srcipaddr, &uip_hostaddr );
\r
1115 ICMPBUF->options[ 0 ] = ICMP6_OPTION_TARGET_LINK_ADDRESS;
\r
1116 ICMPBUF->options[ 1 ] = 1; /* Options length, 1 = 8 bytes. */
\r
1117 memcpy( &(ICMPBUF->options[ 2 ]), &uip_ethaddr, sizeof(uip_ethaddr) );
\r
1118 ICMPBUF->icmpchksum = 0;
\r
1119 ICMPBUF->icmpchksum = ~uip_icmp6chksum();
\r
1126 else if( ICMPBUF->type == ICMP6_ECHO )
\r
1128 /* ICMP echo (i.e., ping) processing. This is simple, we only
\r
1129 change the ICMP type from ECHO to ECHO_REPLY and update the
\r
1130 ICMP checksum before we return the packet. */
\r
1131 ICMPBUF->type = ICMP6_ECHO_REPLY;
\r
1133 uip_ipaddr_copy( &BUF->destipaddr, &BUF->srcipaddr );
\r
1134 uip_ipaddr_copy( &BUF->srcipaddr, &uip_hostaddr );
\r
1135 ICMPBUF->icmpchksum = 0;
\r
1136 ICMPBUF->icmpchksum = ~uip_icmp6chksum();
\r
1138 UIP_STAT( ++uip_stat.icmp.sent );
\r
1143 //DEBUG_PRINTF( "Unknown icmp6 message type %d\n", ICMPBUF->type );
\r
1144 UIP_STAT( ++uip_stat.icmp.drop );
\r
1145 UIP_STAT( ++uip_stat.icmp.typeerr );
\r
1146 UIP_LOG( "icmp: unknown ICMP message." );
\r
1150 /* End of IPv6 ICMP processing. */
\r
1151 #endif /* !UIP_CONF_IPV6 */
\r
1154 /* UDP input processing. */
\r
1156 /* UDP processing is really just a hack. We don't do anything to the
\r
1157 UDP/IP headers, but let the UDP application do all the hard
\r
1158 work. If the application sets uip_slen, it has a packet to
\r
1160 #if UIP_UDP_CHECKSUMS
\r
1161 uip_len = uip_len - UIP_IPUDPH_LEN;
\r
1162 uip_appdata = &uip_buf[ UIP_LLH_LEN + UIP_IPUDPH_LEN ];
\r
1163 if( UDPBUF->udpchksum != 0 && uip_udpchksum() != 0xffff )
\r
1165 UIP_STAT( ++uip_stat.udp.drop );
\r
1166 UIP_STAT( ++uip_stat.udp.chkerr );
\r
1167 UIP_LOG( "udp: bad checksum." );
\r
1171 #else /* UIP_UDP_CHECKSUMS */
\r
1172 uip_len = uip_len - UIP_IPUDPH_LEN;
\r
1173 #endif /* UIP_UDP_CHECKSUMS */
\r
1175 /* Demultiplex this UDP packet between the UDP "connections". */
\r
1176 for( uip_udp_conn = &uip_udp_conns[ 0 ]; uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS]; ++uip_udp_conn )
\r
1178 /* If the local UDP port is non-zero, the connection is considered
\r
1179 to be used. If so, the local port number is checked against the
\r
1180 destination port number in the received packet. If the two port
\r
1181 numbers match, the remote port number is checked if the
\r
1182 connection is bound to a remote port. Finally, if the
\r
1183 connection is bound to a remote IP address, the source IP
\r
1184 address of the packet is checked. */
\r
1187 uip_udp_conn->lport != 0 &&
\r
1188 UDPBUF->destport == uip_udp_conn->lport &&
\r
1189 (uip_udp_conn->rport == 0 || UDPBUF->srcport == uip_udp_conn->rport) &&
\r
1191 uip_ipaddr_cmp(&uip_udp_conn->ripaddr, &uip_all_zeroes_addr) ||
\r
1192 uip_ipaddr_cmp(&uip_udp_conn->ripaddr, &uip_broadcast_addr) ||
\r
1193 uip_ipaddr_cmp(&BUF->srcipaddr, &uip_udp_conn->ripaddr)
\r
1201 UIP_LOG( "udp: no matching connection found" );
\r
1203 #if UIP_CONF_ICMP_DEST_UNREACH && !UIP_CONF_IPV6
\r
1205 /* Copy fields from packet header into payload of this ICMP packet. */
\r
1206 memcpy( &(ICMPBUF->payload[ 0 ]), ICMPBUF, UIP_IPH_LEN + 8 );
\r
1208 /* Set the ICMP type and code. */
\r
1209 ICMPBUF->type = ICMP_DEST_UNREACHABLE;
\r
1210 ICMPBUF->icode = ICMP_PORT_UNREACHABLE;
\r
1212 /* Calculate the ICMP checksum. */
\r
1213 ICMPBUF->icmpchksum = 0;
\r
1214 ICMPBUF->icmpchksum = ~uip_chksum( ( u16_t * ) &(ICMPBUF->type), 36 );
\r
1216 /* Set the IP destination address to be the source address of the
\r
1217 original packet. */
\r
1218 uip_ipaddr_copy( &BUF->destipaddr, &BUF->srcipaddr );
\r
1220 /* Set our IP address as the source address. */
\r
1221 uip_ipaddr_copy( &BUF->srcipaddr, &uip_hostaddr );
\r
1223 /* The size of the ICMP destination unreachable packet is 36 + the
\r
1224 size of the IP header (20) = 56. */
\r
1225 uip_len = 36 + UIP_IPH_LEN;
\r
1226 ICMPBUF->len[ 0 ] = 0;
\r
1227 ICMPBUF->len[ 1 ] = ( u8_t ) uip_len;
\r
1228 ICMPBUF->ttl = UIP_TTL;
\r
1229 ICMPBUF->proto = UIP_PROTO_ICMP;
\r
1231 goto ip_send_nolen;
\r
1232 #else /* UIP_CONF_ICMP_DEST_UNREACH */
\r
1234 #endif /* UIP_CONF_ICMP_DEST_UNREACH */
\r
1236 udp_found : uip_conn = NULL;
\r
1237 uip_flags = UIP_NEWDATA;
\r
1238 uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
\r
1240 UIP_UDP_APPCALL();
\r
1243 if( uip_slen == 0 )
\r
1248 uip_len = uip_slen + UIP_IPUDPH_LEN;
\r
1251 /* For IPv6, the IP length field does not include the IPv6 IP header
\r
1253 BUF->len[ 0 ] = ( (uip_len - UIP_IPH_LEN) >> 8 );
\r
1254 BUF->len[ 1 ] = ( (uip_len - UIP_IPH_LEN) & 0xff );
\r
1255 #else /* UIP_CONF_IPV6 */
\r
1256 BUF->len[ 0 ] = ( uip_len >> 8 );
\r
1257 BUF->len[ 1 ] = ( uip_len & 0xff );
\r
1258 #endif /* UIP_CONF_IPV6 */
\r
1260 BUF->ttl = uip_udp_conn->ttl;
\r
1261 BUF->proto = UIP_PROTO_UDP;
\r
1263 UDPBUF->udplen = HTONS( uip_slen + UIP_UDPH_LEN );
\r
1264 UDPBUF->udpchksum = 0;
\r
1266 BUF->srcport = uip_udp_conn->lport;
\r
1267 BUF->destport = uip_udp_conn->rport;
\r
1269 uip_ipaddr_copy( &BUF->srcipaddr, &uip_hostaddr );
\r
1270 uip_ipaddr_copy( &BUF->destipaddr, &uip_udp_conn->ripaddr );
\r
1272 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
\r
1274 #if UIP_UDP_CHECKSUMS
\r
1275 /* Calculate UDP checksum. */
\r
1276 UDPBUF->udpchksum = ~( uip_udpchksum() );
\r
1277 if( UDPBUF->udpchksum == 0 )
\r
1279 UDPBUF->udpchksum = 0xffff;
\r
1281 #endif /* UIP_UDP_CHECKSUMS */
\r
1282 goto ip_send_nolen;
\r
1283 #endif /* UIP_UDP */
\r
1285 /* TCP input processing. */
\r
1286 tcp_input : UIP_STAT( ++uip_stat.tcp.recv );
\r
1288 /* Start of TCP input header processing code. */
\r
1289 if( uip_tcpchksum() != 0xffff )
\r
1291 /* Compute and check the TCP checksum. */
\r
1292 UIP_STAT( ++uip_stat.tcp.drop );
\r
1293 UIP_STAT( ++uip_stat.tcp.chkerr );
\r
1294 UIP_LOG( "tcp: bad checksum." );
\r
1298 /* Demultiplex this segment. */
\r
1300 /* First check any active connections. */
\r
1301 for( uip_connr = &uip_conns[ 0 ]; uip_connr <= &uip_conns[UIP_CONNS - 1]; ++uip_connr )
\r
1305 uip_connr->tcpstateflags != UIP_CLOSED &&
\r
1306 BUF->destport == uip_connr->lport &&
\r
1307 BUF->srcport == uip_connr->rport &&
\r
1308 uip_ipaddr_cmp(&BUF->srcipaddr, &uip_connr->ripaddr)
\r
1315 /* If we didn't find and active connection that expected the packet,
\r
1316 either this packet is an old duplicate, or this is a SYN packet
\r
1317 destined for a connection in LISTEN. If the SYN flag isn't set,
\r
1318 it is an old packet and we send a RST. */
\r
1319 if( (BUF->flags & TCP_CTL) != TCP_SYN )
\r
1324 tmp16 = BUF->destport;
\r
1326 /* Next, check listening connections. */
\r
1327 for( c = 0; c < UIP_LISTENPORTS; ++c )
\r
1329 if( tmp16 == uip_listenports[ c ] )
\r
1331 goto found_listen;
\r
1335 /* No matching connection found, so we send a RST packet. */
\r
1336 UIP_STAT( ++uip_stat.tcp.synrst );
\r
1339 /* We do not send resets in response to resets. */
\r
1340 if( BUF->flags & TCP_RST )
\r
1345 UIP_STAT( ++uip_stat.tcp.rst );
\r
1347 BUF->flags = TCP_RST | TCP_ACK;
\r
1348 uip_len = UIP_IPTCPH_LEN;
\r
1349 BUF->tcpoffset = 5 << 4;
\r
1351 /* Flip the seqno and ackno fields in the TCP header. */
\r
1352 c = BUF->seqno[ 3 ];
\r
1353 BUF->seqno[ 3 ] = BUF->ackno[ 3 ];
\r
1354 BUF->ackno[ 3 ] = c;
\r
1356 c = BUF->seqno[ 2 ];
\r
1357 BUF->seqno[ 2 ] = BUF->ackno[ 2 ];
\r
1358 BUF->ackno[ 2 ] = c;
\r
1360 c = BUF->seqno[ 1 ];
\r
1361 BUF->seqno[ 1 ] = BUF->ackno[ 1 ];
\r
1362 BUF->ackno[ 1 ] = c;
\r
1364 c = BUF->seqno[ 0 ];
\r
1365 BUF->seqno[ 0 ] = BUF->ackno[ 0 ];
\r
1366 BUF->ackno[ 0 ] = c;
\r
1368 /* We also have to increase the sequence number we are
\r
1369 acknowledging. If the least significant byte overflowed, we need
\r
1370 to propagate the carry to the other bytes as well. */
\r
1371 if( ++BUF->ackno[ 3 ] == 0 )
\r
1373 if( ++BUF->ackno[ 2 ] == 0 )
\r
1375 if( ++BUF->ackno[ 1 ] == 0 )
\r
1377 ++BUF->ackno[ 0 ];
\r
1382 /* Swap port numbers. */
\r
1383 tmp16 = BUF->srcport;
\r
1384 BUF->srcport = BUF->destport;
\r
1385 BUF->destport = tmp16;
\r
1387 /* Swap IP addresses. */
\r
1388 uip_ipaddr_copy( &BUF->destipaddr, &BUF->srcipaddr );
\r
1389 uip_ipaddr_copy( &BUF->srcipaddr, &uip_hostaddr );
\r
1391 /* And send out the RST packet! */
\r
1392 goto tcp_send_noconn;
\r
1394 /* This label will be jumped to if we matched the incoming packet
\r
1395 with a connection in LISTEN. In that case, we should create a new
\r
1396 connection and send a SYNACK in return. */
\r
1398 /* First we check if there are any connections avaliable. Unused
\r
1399 connections are kept in the same table as used connections, but
\r
1400 unused ones have the tcpstate set to CLOSED. Also, connections in
\r
1401 TIME_WAIT are kept track of and we'll use the oldest one if no
\r
1402 CLOSED connections are found. Thanks to Eddie C. Dost for a very
\r
1403 nice algorithm for the TIME_WAIT search. */
\r
1405 for( c = 0; c < UIP_CONNS; ++c )
\r
1407 if( uip_conns[ c ].tcpstateflags == UIP_CLOSED )
\r
1409 uip_connr = &uip_conns[ c ];
\r
1413 if( uip_conns[ c ].tcpstateflags == UIP_TIME_WAIT )
\r
1415 if( uip_connr == 0 || uip_conns[ c ].timer > uip_connr->timer )
\r
1417 uip_connr = &uip_conns[ c ];
\r
1422 if( uip_connr == 0 )
\r
1424 /* All connections are used already, we drop packet and hope that
\r
1425 the remote end will retransmit the packet at a time when we
\r
1426 have more spare connections. */
\r
1427 UIP_STAT( ++uip_stat.tcp.syndrop );
\r
1428 UIP_LOG( "tcp: found no unused connections." );
\r
1432 uip_conn = uip_connr;
\r
1434 /* Fill in the necessary fields for the new connection. */
\r
1435 uip_connr->rto = uip_connr->timer = UIP_RTO;
\r
1436 uip_connr->sa = 0;
\r
1437 uip_connr->sv = 4;
\r
1438 uip_connr->nrtx = 0;
\r
1439 uip_connr->lport = BUF->destport;
\r
1440 uip_connr->rport = BUF->srcport;
\r
1441 uip_ipaddr_copy( &uip_connr->ripaddr, &BUF->srcipaddr );
\r
1442 uip_connr->tcpstateflags = UIP_SYN_RCVD;
\r
1444 uip_connr->snd_nxt[ 0 ] = iss[ 0 ];
\r
1445 uip_connr->snd_nxt[ 1 ] = iss[ 1 ];
\r
1446 uip_connr->snd_nxt[ 2 ] = iss[ 2 ];
\r
1447 uip_connr->snd_nxt[ 3 ] = iss[ 3 ];
\r
1448 uip_connr->len = 1;
\r
1450 /* rcv_nxt should be the seqno from the incoming packet + 1. */
\r
1451 uip_connr->rcv_nxt[ 3 ] = BUF->seqno[ 3 ];
\r
1452 uip_connr->rcv_nxt[ 2 ] = BUF->seqno[ 2 ];
\r
1453 uip_connr->rcv_nxt[ 1 ] = BUF->seqno[ 1 ];
\r
1454 uip_connr->rcv_nxt[ 0 ] = BUF->seqno[ 0 ];
\r
1455 uip_add_rcv_nxt( 1 );
\r
1457 /* Parse the TCP MSS option, if present. */
\r
1458 if( (BUF->tcpoffset & 0xf0) > 0x50 )
\r
1460 for( c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2; )
\r
1462 opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];
\r
1463 if( opt == TCP_OPT_END )
\r
1465 /* End of options. */
\r
1468 else if( opt == TCP_OPT_NOOP )
\r
1474 else if( opt == TCP_OPT_MSS && uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN )
\r
1476 /* An MSS option with the right option length. */
\r
1477 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
1478 uip_connr->initialmss = uip_connr->mss = tmp16 > UIP_TCP_MSS ? UIP_TCP_MSS : tmp16;
\r
1480 /* And we are done processing options. */
\r
1485 /* All other options have a length field, so that we easily
\r
1486 can skip past them. */
\r
1487 if( uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0 )
\r
1489 /* If the length field is zero, the options are malformed
\r
1490 and we don't process them further. */
\r
1494 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
\r
1499 /* Our response will be a SYNACK. */
\r
1500 #if UIP_ACTIVE_OPEN
\r
1501 tcp_send_synack : BUF->flags = TCP_ACK;
\r
1503 BUF->flags |= TCP_SYN;
\r
1504 #else /* UIP_ACTIVE_OPEN */
\r
1505 tcp_send_synack : BUF->flags = TCP_SYN | TCP_ACK;
\r
1506 #endif /* UIP_ACTIVE_OPEN */
\r
1508 /* We send out the TCP Maximum Segment Size option with our
\r
1510 BUF->optdata[ 0 ] = TCP_OPT_MSS;
\r
1511 BUF->optdata[ 1 ] = TCP_OPT_MSS_LEN;
\r
1512 BUF->optdata[ 2 ] = ( UIP_TCP_MSS ) / 256;
\r
1513 BUF->optdata[ 3 ] = ( UIP_TCP_MSS ) & 255;
\r
1514 uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN;
\r
1515 BUF->tcpoffset = ( (UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4 ) << 4;
\r
1518 /* This label will be jumped to if we found an active connection. */
\r
1520 uip_conn = uip_connr;
\r
1523 /* We do a very naive form of TCP reset processing; we just accept
\r
1524 any RST and kill our connection. We should in fact check if the
\r
1525 sequence number of this reset is wihtin our advertised window
\r
1526 before we accept the reset. */
\r
1527 if( BUF->flags & TCP_RST )
\r
1529 uip_connr->tcpstateflags = UIP_CLOSED;
\r
1530 UIP_LOG( "tcp: got reset, aborting connection." );
\r
1531 uip_flags = UIP_ABORT;
\r
1536 /* Calculate the length of the data, if the application has sent
\r
1537 any data to us. */
\r
1538 c = ( BUF->tcpoffset >> 4 ) << 2;
\r
1540 /* uip_len will contain the length of the actual TCP data. This is
\r
1541 calculated by subtracing the length of the TCP header (in
\r
1542 c) and the length of the IP header (20 bytes). */
\r
1543 uip_len = uip_len - c - UIP_IPH_LEN;
\r
1545 /* First, check if the sequence number of the incoming packet is
\r
1546 what we're expecting next. If not, we send out an ACK with the
\r
1547 correct numbers in. */
\r
1548 if( !(((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) && ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK))) )
\r
1552 (uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0)) &&
\r
1554 BUF->seqno[ 0 ] != uip_connr->rcv_nxt[ 0 ] ||
\r
1555 BUF->seqno[ 1 ] != uip_connr->rcv_nxt[ 1 ] ||
\r
1556 BUF->seqno[ 2 ] != uip_connr->rcv_nxt[ 2 ] ||
\r
1557 BUF->seqno[ 3 ] != uip_connr->rcv_nxt[ 3 ]
\r
1561 goto tcp_send_ack;
\r
1565 /* Next, check if the incoming segment acknowledges any outstanding
\r
1566 data. If so, we update the sequence number, reset the length of
\r
1567 the outstanding data, calculate RTT estimations, and reset the
\r
1568 retransmission timer. */
\r
1569 if( (BUF->flags & TCP_ACK) && uip_outstanding(uip_connr) )
\r
1571 uip_add32( uip_connr->snd_nxt, uip_connr->len );
\r
1575 BUF->ackno[ 0 ] == uip_acc32[ 0 ] &&
\r
1576 BUF->ackno[ 1 ] == uip_acc32[ 1 ] &&
\r
1577 BUF->ackno[ 2 ] == uip_acc32[ 2 ] &&
\r
1578 BUF->ackno[ 3 ] == uip_acc32[ 3 ]
\r
1581 /* Update sequence number. */
\r
1582 uip_connr->snd_nxt[ 0 ] = uip_acc32[ 0 ];
\r
1583 uip_connr->snd_nxt[ 1 ] = uip_acc32[ 1 ];
\r
1584 uip_connr->snd_nxt[ 2 ] = uip_acc32[ 2 ];
\r
1585 uip_connr->snd_nxt[ 3 ] = uip_acc32[ 3 ];
\r
1587 /* Do RTT estimation, unless we have done retransmissions. */
\r
1588 if( uip_connr->nrtx == 0 )
\r
1591 m = uip_connr->rto - uip_connr->timer;
\r
1593 /* This is taken directly from VJs original code in his paper */
\r
1594 m = m - ( uip_connr->sa >> 3 );
\r
1595 uip_connr->sa += m;
\r
1601 m = m - ( uip_connr->sv >> 2 );
\r
1602 uip_connr->sv += m;
\r
1603 uip_connr->rto = ( uip_connr->sa >> 3 ) + uip_connr->sv;
\r
1606 /* Set the acknowledged flag. */
\r
1607 uip_flags = UIP_ACKDATA;
\r
1609 /* Reset the retransmission timer. */
\r
1610 uip_connr->timer = uip_connr->rto;
\r
1612 /* Reset length of outstanding data. */
\r
1613 uip_connr->len = 0;
\r
1617 /* Do different things depending on in what state the connection is. */
\r
1618 switch( uip_connr->tcpstateflags & UIP_TS_MASK )
\r
1620 /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
\r
1621 implemented, since we force the application to close when the
\r
1622 peer sends a FIN (hence the application goes directly from
\r
1623 ESTABLISHED to LAST_ACK). */
\r
1624 case UIP_SYN_RCVD:
\r
1625 /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
\r
1626 we are waiting for an ACK that acknowledges the data we sent
\r
1627 out the last time. Therefore, we want to have the UIP_ACKDATA
\r
1628 flag set. If so, we enter the ESTABLISHED state. */
\r
1629 if( uip_flags & UIP_ACKDATA )
\r
1631 uip_connr->tcpstateflags = UIP_ESTABLISHED;
\r
1632 uip_flags = UIP_CONNECTED;
\r
1633 uip_connr->len = 0;
\r
1636 uip_flags |= UIP_NEWDATA;
\r
1637 uip_add_rcv_nxt( uip_len );
\r
1647 #if UIP_ACTIVE_OPEN
\r
1648 case UIP_SYN_SENT:
\r
1649 /* In SYN_SENT, we wait for a SYNACK that is sent in response to
\r
1650 our SYN. The rcv_nxt is set to sequence number in the SYNACK
\r
1651 plus one, and we send an ACK. We move into the ESTABLISHED
\r
1653 if( (uip_flags & UIP_ACKDATA) && (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK) )
\r
1655 /* Parse the TCP MSS option, if present. */
\r
1656 if( (BUF->tcpoffset & 0xf0) > 0x50 )
\r
1658 for( c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2; )
\r
1660 opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c];
\r
1661 if( opt == TCP_OPT_END )
\r
1663 /* End of options. */
\r
1666 else if( opt == TCP_OPT_NOOP )
\r
1672 else if( opt == TCP_OPT_MSS && uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN )
\r
1674 /* An MSS option with the right option length. */
\r
1675 tmp16 = ( uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8 ) | uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
\r
1676 uip_connr->initialmss = uip_connr->mss = tmp16 > UIP_TCP_MSS ? UIP_TCP_MSS : tmp16;
\r
1678 /* And we are done processing options. */
\r
1683 /* All other options have a length field, so that we easily
\r
1684 can skip past them. */
\r
1685 if( uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0 )
\r
1687 /* If the length field is zero, the options are malformed
\r
1688 and we don't process them further. */
\r
1692 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
\r
1697 uip_connr->tcpstateflags = UIP_ESTABLISHED;
\r
1698 uip_connr->rcv_nxt[ 0 ] = BUF->seqno[ 0 ];
\r
1699 uip_connr->rcv_nxt[ 1 ] = BUF->seqno[ 1 ];
\r
1700 uip_connr->rcv_nxt[ 2 ] = BUF->seqno[ 2 ];
\r
1701 uip_connr->rcv_nxt[ 3 ] = BUF->seqno[ 3 ];
\r
1702 uip_add_rcv_nxt( 1 );
\r
1703 uip_flags = UIP_CONNECTED | UIP_NEWDATA;
\r
1704 uip_connr->len = 0;
\r
1711 /* Inform the application that the connection failed */
\r
1712 uip_flags = UIP_ABORT;
\r
1715 /* The connection is closed after we send the RST */
\r
1716 uip_conn->tcpstateflags = UIP_CLOSED;
\r
1718 #endif /* UIP_ACTIVE_OPEN */
\r
1720 case UIP_ESTABLISHED:
\r
1721 /* In the ESTABLISHED state, we call upon the application to feed
\r
1722 data into the uip_buf. If the UIP_ACKDATA flag is set, the
\r
1723 application should put new data into the buffer, otherwise we are
\r
1724 retransmitting an old segment, and the application should put that
\r
1725 data into the buffer.
\r
1727 If the incoming packet is a FIN, we should close the connection on
\r
1728 this side as well, and we send out a FIN and enter the LAST_ACK
\r
1729 state. We require that there is no outstanding data; otherwise the
\r
1730 sequence numbers will be screwed up. */
\r
1731 if( BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED) )
\r
1733 if( uip_outstanding(uip_connr) )
\r
1738 uip_add_rcv_nxt( 1 + uip_len );
\r
1739 uip_flags |= UIP_CLOSE;
\r
1742 uip_flags |= UIP_NEWDATA;
\r
1746 uip_connr->len = 1;
\r
1747 uip_connr->tcpstateflags = UIP_LAST_ACK;
\r
1748 uip_connr->nrtx = 0;
\r
1750 BUF->flags = TCP_FIN | TCP_ACK;
\r
1751 goto tcp_send_nodata;
\r
1754 /* Check the URG flag. If this is set, the segment carries urgent
\r
1755 data that we must pass to the application. */
\r
1756 if( (BUF->flags & TCP_URG) != 0 )
\r
1758 #if UIP_URGDATA > 0
\r
1759 uip_urglen = ( BUF->urgp[ 0 ] << 8 ) | BUF->urgp[ 1 ];
\r
1760 if( uip_urglen > uip_len )
\r
1762 /* There is more urgent data in the next segment to come. */
\r
1763 uip_urglen = uip_len;
\r
1766 uip_add_rcv_nxt( uip_urglen );
\r
1767 uip_len -= uip_urglen;
\r
1768 uip_urgdata = uip_appdata;
\r
1769 uip_appdata += uip_urglen;
\r
1774 #else /* UIP_URGDATA > 0 */
\r
1775 uip_appdata = ( ( char * ) uip_appdata ) + ( (BUF->urgp[ 0 ] << 8) | BUF->urgp[ 1 ] );
\r
1776 uip_len -= ( BUF->urgp[ 0 ] << 8 ) | BUF->urgp[ 1 ];
\r
1777 #endif /* UIP_URGDATA > 0 */
\r
1780 /* If uip_len > 0 we have TCP data in the packet, and we flag this
\r
1781 by setting the UIP_NEWDATA flag and update the sequence number
\r
1782 we acknowledge. If the application has stopped the dataflow
\r
1783 using uip_stop(), we must not accept any data packets from the
\r
1785 if( uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED) )
\r
1787 uip_flags |= UIP_NEWDATA;
\r
1788 uip_add_rcv_nxt( uip_len );
\r
1791 /* Check if the available buffer space advertised by the other end
\r
1792 is smaller than the initial MSS for this connection. If so, we
\r
1793 set the current MSS to the window size to ensure that the
\r
1794 application does not send more data than the other end can
\r
1797 If the remote host advertises a zero window, we set the MSS to
\r
1798 the initial MSS so that the application will send an entire MSS
\r
1799 of data. This data will not be acknowledged by the receiver,
\r
1800 and the application will retransmit it. This is called the
\r
1801 "persistent timer" and uses the retransmission mechanim.
\r
1803 tmp16 = ( (u16_t) BUF->wnd[ 0 ] << 8 ) + ( u16_t ) BUF->wnd[ 1 ];
\r
1804 if( tmp16 > uip_connr->initialmss || tmp16 == 0 )
\r
1806 tmp16 = uip_connr->initialmss;
\r
1809 uip_connr->mss = tmp16;
\r
1811 /* If this packet constitutes an ACK for outstanding data (flagged
\r
1812 by the UIP_ACKDATA flag, we should call the application since it
\r
1813 might want to send more data. If the incoming packet had data
\r
1814 from the peer (as flagged by the UIP_NEWDATA flag), the
\r
1815 application must also be notified.
\r
1817 When the application is called, the global variable uip_len
\r
1818 contains the length of the incoming data. The application can
\r
1819 access the incoming data through the global pointer
\r
1820 uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN
\r
1821 bytes into the uip_buf array.
\r
1823 If the application wishes to send any data, this data should be
\r
1824 put into the uip_appdata and the length of the data should be
\r
1825 put into uip_len. If the application don't have any data to
\r
1826 send, uip_len must be set to 0. */
\r
1827 if( uip_flags & (UIP_NEWDATA | UIP_ACKDATA) )
\r
1833 if( uip_flags & UIP_ABORT )
\r
1836 uip_connr->tcpstateflags = UIP_CLOSED;
\r
1837 BUF->flags = TCP_RST | TCP_ACK;
\r
1838 goto tcp_send_nodata;
\r
1841 if( uip_flags & UIP_CLOSE )
\r
1844 uip_connr->len = 1;
\r
1845 uip_connr->tcpstateflags = UIP_FIN_WAIT_1;
\r
1846 uip_connr->nrtx = 0;
\r
1847 BUF->flags = TCP_FIN | TCP_ACK;
\r
1848 goto tcp_send_nodata;
\r
1851 /* If uip_slen > 0, the application has data to be sent. */
\r
1852 if( uip_slen > 0 )
\r
1854 /* If the connection has acknowledged data, the contents of
\r
1855 the ->len variable should be discarded. */
\r
1856 if( (uip_flags & UIP_ACKDATA) != 0 )
\r
1858 uip_connr->len = 0;
\r
1861 /* If the ->len variable is non-zero the connection has
\r
1862 already data in transit and cannot send anymore right
\r
1864 if( uip_connr->len == 0 )
\r
1866 /* The application cannot send more than what is allowed by
\r
1867 the mss (the minumum of the MSS and the available
\r
1869 if( uip_slen > uip_connr->mss )
\r
1871 uip_slen = uip_connr->mss;
\r
1874 /* Remember how much data we send out now so that we know
\r
1875 when everything has been acknowledged. */
\r
1876 uip_connr->len = uip_slen;
\r
1880 /* If the application already had unacknowledged data, we
\r
1881 make sure that the application does not send (i.e.,
\r
1882 retransmit) out more than it previously sent out. */
\r
1883 uip_slen = uip_connr->len;
\r
1887 uip_connr->nrtx = 0;
\r
1889 uip_appdata = uip_sappdata;
\r
1891 /* If the application has data to be sent, or if the incoming
\r
1892 packet had new data in it, we must send out a packet. */
\r
1893 if( uip_slen > 0 && uip_connr->len > 0 )
\r
1895 /* Add the length of the IP and TCP headers. */
\r
1896 uip_len = uip_connr->len + UIP_TCPIP_HLEN;
\r
1898 /* We always set the ACK flag in response packets. */
\r
1899 BUF->flags = TCP_ACK | TCP_PSH;
\r
1901 /* Send the packet. */
\r
1902 goto tcp_send_noopts;
\r
1905 /* If there is no data to send, just send out a pure ACK if
\r
1906 there is newdata. */
\r
1907 if( uip_flags & UIP_NEWDATA )
\r
1909 uip_len = UIP_TCPIP_HLEN;
\r
1910 BUF->flags = TCP_ACK;
\r
1911 goto tcp_send_noopts;
\r
1917 case UIP_LAST_ACK:
\r
1918 /* We can close this connection if the peer has acknowledged our
\r
1919 FIN. This is indicated by the UIP_ACKDATA flag. */
\r
1920 if( uip_flags & UIP_ACKDATA )
\r
1922 uip_connr->tcpstateflags = UIP_CLOSED;
\r
1923 uip_flags = UIP_CLOSE;
\r
1929 case UIP_FIN_WAIT_1:
\r
1930 /* The application has closed the connection, but the remote host
\r
1931 hasn't closed its end yet. Thus we do nothing but wait for a
\r
1932 FIN from the other side. */
\r
1935 uip_add_rcv_nxt( uip_len );
\r
1938 if( BUF->flags & TCP_FIN )
\r
1940 if( uip_flags & UIP_ACKDATA )
\r
1942 uip_connr->tcpstateflags = UIP_TIME_WAIT;
\r
1943 uip_connr->timer = 0;
\r
1944 uip_connr->len = 0;
\r
1948 uip_connr->tcpstateflags = UIP_CLOSING;
\r
1951 uip_add_rcv_nxt( 1 );
\r
1952 uip_flags = UIP_CLOSE;
\r
1954 goto tcp_send_ack;
\r
1956 else if( uip_flags & UIP_ACKDATA )
\r
1958 uip_connr->tcpstateflags = UIP_FIN_WAIT_2;
\r
1959 uip_connr->len = 0;
\r
1965 goto tcp_send_ack;
\r
1970 case UIP_FIN_WAIT_2:
\r
1973 uip_add_rcv_nxt( uip_len );
\r
1976 if( BUF->flags & TCP_FIN )
\r
1978 uip_connr->tcpstateflags = UIP_TIME_WAIT;
\r
1979 uip_connr->timer = 0;
\r
1980 uip_add_rcv_nxt( 1 );
\r
1981 uip_flags = UIP_CLOSE;
\r
1983 goto tcp_send_ack;
\r
1988 goto tcp_send_ack;
\r
1993 case UIP_TIME_WAIT:
\r
1994 goto tcp_send_ack;
\r
1997 if( uip_flags & UIP_ACKDATA )
\r
1999 uip_connr->tcpstateflags = UIP_TIME_WAIT;
\r
2000 uip_connr->timer = 0;
\r
2006 /* We jump here when we are ready to send the packet, and just want
\r
2007 to set the appropriate TCP sequence numbers in the TCP header. */
\r
2009 BUF->flags = TCP_ACK;
\r
2012 uip_len = UIP_IPTCPH_LEN;
\r
2015 BUF->tcpoffset = ( UIP_TCPH_LEN / 4 ) << 4;
\r
2017 /* We're done with the input processing. We are now ready to send a
\r
2018 reply. Our job is to fill in all the fields of the TCP and IP
\r
2019 headers before calculating the checksum and finally send the
\r
2022 BUF->ackno[ 0 ] = uip_connr->rcv_nxt[ 0 ];
\r
2023 BUF->ackno[ 1 ] = uip_connr->rcv_nxt[ 1 ];
\r
2024 BUF->ackno[ 2 ] = uip_connr->rcv_nxt[ 2 ];
\r
2025 BUF->ackno[ 3 ] = uip_connr->rcv_nxt[ 3 ];
\r
2027 BUF->seqno[ 0 ] = uip_connr->snd_nxt[ 0 ];
\r
2028 BUF->seqno[ 1 ] = uip_connr->snd_nxt[ 1 ];
\r
2029 BUF->seqno[ 2 ] = uip_connr->snd_nxt[ 2 ];
\r
2030 BUF->seqno[ 3 ] = uip_connr->snd_nxt[ 3 ];
\r
2032 BUF->proto = UIP_PROTO_TCP;
\r
2034 BUF->srcport = uip_connr->lport;
\r
2035 BUF->destport = uip_connr->rport;
\r
2037 uip_ipaddr_copy( &BUF->srcipaddr, &uip_hostaddr );
\r
2038 uip_ipaddr_copy( &BUF->destipaddr, &uip_connr->ripaddr );
\r
2040 if( uip_connr->tcpstateflags & UIP_STOPPED )
\r
2042 /* If the connection has issued uip_stop(), we advertise a zero
\r
2043 window so that the remote host will stop sending data. */
\r
2044 BUF->wnd[ 0 ] = BUF->wnd[ 1 ] = 0;
\r
2048 BUF->wnd[ 0 ] = ( (UIP_RECEIVE_WINDOW) >> 8 );
\r
2049 BUF->wnd[ 1 ] = ( (UIP_RECEIVE_WINDOW) & 0xff );
\r
2054 BUF->ttl = UIP_TTL;
\r
2057 /* For IPv6, the IP length field does not include the IPv6 IP header
\r
2059 BUF->len[ 0 ] = ( (uip_len - UIP_IPH_LEN) >> 8 );
\r
2060 BUF->len[ 1 ] = ( (uip_len - UIP_IPH_LEN) & 0xff );
\r
2061 #else /* UIP_CONF_IPV6 */
\r
2062 BUF->len[ 0 ] = ( uip_len >> 8 );
\r
2063 BUF->len[ 1 ] = ( uip_len & 0xff );
\r
2064 #endif /* UIP_CONF_IPV6 */
\r
2066 BUF->urgp[ 0 ] = BUF->urgp[ 1 ] = 0;
\r
2068 /* Calculate TCP checksum. */
\r
2069 BUF->tcpchksum = 0;
\r
2070 BUF->tcpchksum = ~( uip_tcpchksum() );
\r
2075 BUF->tcflow = 0x00;
\r
2077 #else /* UIP_CONF_IPV6 */
\r
2080 BUF->ipoffset[ 0 ] = BUF->ipoffset[ 1 ] = 0;
\r
2082 BUF->ipid[ 0 ] = ipid >> 8;
\r
2083 BUF->ipid[ 1 ] = ipid & 0xff;
\r
2085 /* Calculate IP checksum. */
\r
2086 BUF->ipchksum = 0;
\r
2087 BUF->ipchksum = ~( uip_ipchksum() );
\r
2089 //DEBUG_PRINTF( "uip ip_send_nolen: chkecum 0x%04x\n", uip_ipchksum() );
\r
2090 #endif /* UIP_CONF_IPV6 */
\r
2092 UIP_STAT( ++uip_stat.tcp.sent );
\r
2096 #endif /* UIP_CONF_IPV6 */
\r
2098 //DEBUG_PRINTF( "Sending packet with length %d (%d)\n", uip_len, (BUF->len[ 0 ] << 8) | BUF->len[ 1 ] );
\r
2099 UIP_STAT( ++uip_stat.ip.sent );
\r
2101 /* Return and let the caller do the actual transmission. */
\r
2110 /*---------------------------------------------------------------------------*/
\r
2112 u16_t htons( u16_t val )
\r
2114 return HTONS( val );
\r
2117 u32_t htonl( u32_t val )
\r
2119 return HTONL( val );
\r
2121 /*---------------------------------------------------------------------------*/
\r
2123 void uip_send( const void *data, int len )
\r
2127 #define MIN( a, b ) ( (a) < (b) ? (a) : (b) )
\r
2129 copylen = MIN( len, UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN - ( int )
\r
2130 (( char * ) uip_sappdata - ( char * ) &uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN]) );
\r
2133 uip_slen = copylen;
\r
2134 if( data != uip_sappdata )
\r
2136 memcpy( uip_sappdata, (data), uip_slen );
\r
2140 /*---------------------------------------------------------------------------*/
\r
2143 #endif /* UIP_CONF_IPV6 */
\r