1c80132e0d04bdb0042970128203f4f7e7d8b66d
[gpxe.git] / src / net / tcp.c
1 #include <string.h>
2 #include <stdlib.h>
3 #include <assert.h>
4 #include <byteswap.h>
5 #include <latch.h>
6 #include <errno.h>
7 #include <gpxe/process.h>
8 #include <gpxe/init.h>
9 #include <gpxe/netdevice.h>
10 #include <gpxe/pkbuff.h>
11 #include <gpxe/ip.h>
12 #include <gpxe/tcp.h>
13 #include <gpxe/tcpip.h>
14 #include "uip/uip.h"
15
16 /** @file
17  *
18  * TCP protocol
19  *
20  * The gPXE TCP stack is currently implemented on top of the uIP
21  * protocol stack.  This file provides wrappers around uIP so that
22  * higher-level protocol implementations do not need to talk directly
23  * to uIP (which has a somewhat baroque API).
24  *
25  * Basic operation is to create a #tcp_connection structure, call
26  * tcp_connect() and then call run_tcpip() in a loop until the
27  * operation has completed.  The TCP stack will call the various
28  * methods defined in the #tcp_operations structure in order to send
29  * and receive data.
30  *
31  * See hello.c for a trivial example of a TCP protocol using this
32  * API.
33  *
34  */
35
36 #if USE_UIP
37
38 /**
39  * TCP transmit buffer
40  *
41  * When a tcp_operations::senddata() method is called, it is
42  * guaranteed to be able to use this buffer as temporary space for
43  * constructing the data to be sent.  For example, code such as
44  *
45  * @code
46  *
47  *     static void my_senddata ( struct tcp_connection *conn, void *buf,
48  *                               size_t len ) {
49  *         len = snprintf ( buf, len, "FETCH %s\r\n", filename );
50  *         tcp_send ( conn, buf + already_sent, len - already_sent );
51  *     }
52  *
53  * @endcode
54  *
55  * is allowed, and is probably the best way to deal with
56  * variably-sized data.
57  *
58  * Note that you cannot use this simple mechanism if you want to be
59  * able to construct single data blocks of more than #len bytes.
60  */
61 static void *tcp_buffer = uip_buf + ( 40 + UIP_LLH_LEN );
62
63 /** Size of #tcp_buffer */
64 static size_t tcp_buflen = UIP_BUFSIZE - ( 40 + UIP_LLH_LEN );
65
66 /**
67  * Open a TCP connection
68  *
69  * @v conn      TCP connection
70  * 
71  * This sets up a new TCP connection to the remote host specified in
72  * tcp_connection::sin.
73  */
74 void tcp_connect ( struct tcp_connection *conn ) {
75         struct uip_conn *uip_conn;
76         u16_t ipaddr[2];
77
78         assert ( conn->sin.sin_addr.s_addr != 0 );
79         assert ( conn->sin.sin_port != 0 );
80         assert ( conn->tcp_op != NULL );
81         assert ( sizeof ( uip_conn->appstate ) == sizeof ( conn ) );
82
83         * ( ( uint32_t * ) ipaddr ) = conn->sin.sin_addr.s_addr;
84         uip_conn = uip_connect ( ipaddr, conn->sin.sin_port );
85 #warning "Use linked lists so that uip_connect() cannot fail"
86         assert ( uip_conn != NULL );
87         *( ( void ** ) uip_conn->appstate ) = conn;
88 }
89
90 /**
91  * Send data via a TCP connection
92  *
93  * @v conn      TCP connection
94  * @v data      Data to send
95  * @v len       Length of data
96  *
97  * Data will be automatically limited to the current TCP window size.
98  *
99  * If retransmission is required, the connection's
100  * tcp_operations::senddata() method will be called again in order to
101  * regenerate the data.
102  */
103 void tcp_send ( struct tcp_connection *conn __unused,
104                 const void *data, size_t len ) {
105
106         assert ( conn = *( ( void ** ) uip_conn->appstate ) );
107
108         if ( len > tcp_buflen )
109                 len = tcp_buflen;
110         memmove ( tcp_buffer, data, len );
111
112         uip_send ( tcp_buffer, len );
113 }
114
115 /**
116  * Close a TCP connection
117  *
118  * @v conn      TCP connection
119  */
120 void tcp_close ( struct tcp_connection *conn __unused ) {
121         assert ( conn = *( ( void ** ) uip_conn->appstate ) );
122         uip_close();
123 }
124
125 /**
126  * uIP TCP application call interface
127  *
128  * This is the entry point of gPXE from the point of view of the uIP
129  * protocol stack.  This function calls the appropriate methods from
130  * the connection's @tcp_operations table in order to process received
131  * data, transmit new data etc.
132  */
133 void uip_tcp_appcall ( void ) {
134         struct tcp_connection *conn = *( ( void ** ) uip_conn->appstate );
135         struct tcp_operations *op = conn->tcp_op;
136
137         if ( op->closed ) {
138                 if ( uip_aborted() )
139                         op->closed ( conn, -ECONNABORTED );
140                 if ( uip_timedout() )
141                         op->closed ( conn, -ETIMEDOUT );
142                 if ( uip_closed() )
143                         op->closed ( conn, 0 );
144         }
145         if ( uip_connected() && op->connected )
146                 op->connected ( conn );
147         if ( uip_acked() && op->acked )
148                 op->acked ( conn, uip_conn->len );
149         if ( uip_newdata() && op->newdata )
150                 op->newdata ( conn, ( void * ) uip_appdata, uip_len );
151         if ( ( uip_rexmit() || uip_newdata() || uip_acked() ||
152                uip_connected() || uip_poll() ) && op->senddata )
153                 op->senddata ( conn, tcp_buffer, tcp_buflen );
154 }
155
156 /* Present here to allow everything to link.  Will go into separate
157  * udp.c file
158  */
159 void uip_udp_appcall ( void ) {
160 }
161
162 /**
163  * Perform periodic processing of all TCP connections
164  *
165  * This allows TCP connections to retransmit data if necessary.
166  */
167 static void tcp_periodic ( void ) {
168         struct pk_buff *pkb;
169         int i;
170
171         for ( i = 0 ; i < UIP_CONNS ; i++ ) {
172                 uip_periodic ( i );
173                 if ( uip_len > 0 ) {
174                         pkb = alloc_pkb ( uip_len + MAX_LL_HEADER_LEN);
175                         if ( ! pkb )
176                                 continue;
177                                 
178                         pkb_reserve ( pkb, MAX_LL_HEADER_LEN );
179                         pkb_put ( pkb, uip_len );
180                         memcpy ( pkb->data, uip_buf, uip_len );
181
182                         ipv4_uip_tx ( pkb );
183                 }
184         }
185 }
186
187 /**
188  * Kick a connection into life
189  *
190  * @v conn      TCP connection
191  *
192  * Call this function when you have new data to send and are not
193  * already being called as part of TCP processing.
194  */
195 void tcp_kick ( struct tcp_connection *conn __unused ) {
196         /* Just kick all the connections; this will work for now */
197         tcp_periodic();
198 }
199
200 /**
201  * Single-step the TCP stack
202  *
203  * @v process   TCP process
204  *
205  * This calls tcp_periodic() at regular intervals.
206  */
207 static void tcp_step ( struct process *process ) {
208         static unsigned long timeout = 0;
209
210         if ( currticks() > timeout ) {
211                 timeout = currticks() + ( TICKS_PER_SEC / 10 );
212                 tcp_periodic ();
213         }
214
215         schedule ( process );
216 }
217
218 /** TCP stack process */
219 static struct process tcp_process = {
220         .step = tcp_step,
221 };
222
223 /** Initialise the TCP stack */
224 static void init_tcp ( void ) {
225         schedule ( &tcp_process );
226 }
227
228 INIT_FN ( INIT_PROCESS, init_tcp, NULL, NULL );
229
230 #else
231
232 /**
233  * List of registered TCP connections
234  */
235 static LIST_HEAD ( tcp_conns );
236
237 /**
238  * List of TCP states
239  */
240 static const char *tcp_states[] = {
241         "CLOSED",
242         "LISTEN",
243         "SYN_SENT",
244         "SYN_RCVD",
245         "ESTABLISHED",
246         "FIN_WAIT_1",
247         "FIN_WAIT_2",
248         "CLOSING",
249         "TIME_WAIT",
250         "CLOSE_WAIT",
251         "LAST_ACK",
252         "INVALID" };
253
254 /**
255  * TCP state transition function
256  *
257  * @v conn      TCP connection
258  * @v nxt_state Next TCP state
259  */
260 void tcp_trans ( struct tcp_connection *conn, int nxt_state ) {
261         /* Remember the last state */
262         conn->tcp_lstate = conn->tcp_state;
263         conn->tcp_state = nxt_state;
264
265         /* TODO: Check if this check is required */
266         if ( conn->tcp_lstate == conn->tcp_state || 
267              conn->tcp_state == TCP_INVALID ) {
268                 conn->tcp_flags = 0;
269                 return;
270         }
271
272         /* Set the TCP flags */
273         switch ( conn->tcp_state ) {
274         case TCP_CLOSED:
275                 if ( conn->tcp_lstate == TCP_SYN_RCVD ) {
276                         conn->tcp_flags |= TCP_RST;
277                 }
278                 break;
279         case TCP_LISTEN:
280                 break;
281         case TCP_SYN_SENT:
282                 if ( conn->tcp_lstate == TCP_LISTEN ||
283                      conn->tcp_lstate == TCP_CLOSED ) {
284                         conn->tcp_flags |= TCP_SYN;
285                 }
286                 break;
287         case TCP_SYN_RCVD:
288                 if ( conn->tcp_lstate == TCP_LISTEN ||
289                      conn->tcp_lstate == TCP_SYN_SENT ) {
290                         conn->tcp_flags |= ( TCP_SYN | TCP_ACK );
291                 }
292                 break;
293         case TCP_ESTABLISHED:
294                 if ( conn->tcp_lstate == TCP_SYN_SENT ) {
295                         conn->tcp_flags |= TCP_ACK;
296                 }
297                 break;
298         case TCP_FIN_WAIT_1:
299                 if ( conn->tcp_lstate == TCP_SYN_RCVD ||
300                      conn->tcp_lstate == TCP_ESTABLISHED ) {
301                         conn->tcp_flags |= TCP_FIN;
302                 }
303                 break;
304         case TCP_FIN_WAIT_2:
305                 break;
306         case TCP_CLOSING:
307                 if ( conn->tcp_lstate == TCP_FIN_WAIT_1 ) {
308                         conn->tcp_flags |= TCP_ACK;
309                 }
310                 break;
311         case TCP_TIME_WAIT:
312                 if ( conn->tcp_lstate == TCP_FIN_WAIT_1 ||
313                      conn->tcp_lstate == TCP_FIN_WAIT_2 ) {
314                         conn->tcp_flags |= TCP_ACK;
315                 }
316                 break;
317         case TCP_CLOSE_WAIT:
318                 if ( conn->tcp_lstate == TCP_ESTABLISHED ) {
319                         conn->tcp_flags |= TCP_ACK;
320                 }
321                 break;
322         case TCP_LAST_ACK:
323                 if ( conn->tcp_lstate == TCP_CLOSE_WAIT ) {
324                         conn->tcp_flags |= TCP_FIN;
325                 }
326                 break;
327         default:
328                 DBG ( "TCP_INVALID state %d\n", conn->tcp_state );
329                 return;
330         }
331 }
332
333 /**
334  * Dump TCP header
335  *
336  * @v tcphdr    TCP header
337  */
338 void tcp_dump ( struct tcp_header *tcphdr ) {
339         DBG ( "TCP header at %p+%d\n", tcphdr, sizeof ( *tcphdr ) );
340         DBG ( "\tSource port = %d, Destination port = %d\n",
341                 ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ) );
342         DBG ( "\tSequence Number = %ld, Acknowledgement Number = %ld\n",
343                 ntohl ( tcphdr->seq ), ntohl ( tcphdr->ack ) );
344         DBG ( "\tHeader length (/4) = %hd, Flags [..RAPUSF]= %#x\n",
345                 ( ( tcphdr->hlen & TCP_MASK_HLEN ) / 16 ),
346                 ( tcphdr->flags & TCP_MASK_FLAGS ) );
347         DBG ( "\tAdvertised window = %ld, Checksum = %x, Urgent Pointer = %d\n",
348                 ntohs ( tcphdr->win ), tcphdr->csum, ntohs ( tcphdr->urg ) );
349 }
350
351 /**
352  * Initialize a TCP connection
353  *
354  * @v conn      TCP connection
355  *
356  * This function assigns initial values to some fields in the connection
357  * structure. The application should call tcp_init_conn after creating a new
358  * connection before calling any other "tcp_*" function.
359  *
360  * struct tcp_connection my_conn;
361  * tcp_init_conn ( &my_conn );
362  * ... 
363  */
364 void tcp_init_conn ( struct tcp_connection *conn ) {
365         conn->local_port = 0;
366         conn->tcp_state = TCP_CLOSED;
367         conn->tcp_lstate = TCP_INVALID;
368         conn->tx_pkb = NULL;
369         conn->tcp_op = NULL;
370 }
371
372 /**
373  * Connect to a remote server
374  *
375  * @v conn      TCP connection
376  * @v peer      Remote socket address
377  *
378  * This function initiates a TCP connection to the socket address specified in
379  * peer. It sends a SYN packet to peer. When the connection is established, the
380  * TCP stack calls the connected() callback function.
381  */
382 int tcp_connectto ( struct tcp_connection *conn, struct sockaddr *peer ) {
383         int rc;
384
385         /* A connection can only be established from the CLOSED state */
386         if ( conn->tcp_state != TCP_CLOSED ) {
387                 DBG ( "Error opening connection: Invalid state %s\n",
388                                 tcp_states[conn->tcp_state] );
389                 return -EISCONN;
390         }
391
392         /* Add the connection to the set of listening connections */
393         if ( ( rc = tcp_listen ( conn, conn->local_port ) ) != 0 ) {
394                 return rc;
395         }
396         memcpy ( &conn->sa, peer, sizeof ( *peer ) );
397
398         /* Send a SYN packet and transition to TCP_SYN_SENT */
399         conn->snd_una = ( ( ( uint32_t ) random() ) << 16 ) & random();
400         tcp_trans ( conn, TCP_SYN_SENT );
401         /* Allocate space for the packet */
402         free_pkb ( conn->tx_pkb );
403         conn->tx_pkb = alloc_pkb ( MIN_PKB_LEN );
404         pkb_reserve ( conn->tx_pkb, MAX_HDR_LEN );
405         conn->rcv_win = MAX_PKB_LEN - MAX_HDR_LEN; /* TODO: Is this OK? */
406         return tcp_send ( conn, TCP_NOMSG, TCP_NOMSG_LEN );
407 }
408
409 int tcp_connect ( struct tcp_connection *conn ) {
410         return tcp_connectto ( conn, &conn->sa );
411 }
412
413 /**
414  * Close the connection
415  *
416  * @v conn
417  *
418  * This function sends a FIN packet to the remote end of the connection. When
419  * the remote end of the connection ACKs the FIN (FIN consumes one byte on the
420  * snd stream), the stack invokes the closed() callback function.
421  */
422 int tcp_close ( struct tcp_connection *conn ) {
423         /* A connection can only be closed if it is a connected state */
424         switch ( conn->tcp_state ) {
425         case TCP_SYN_RCVD:
426         case TCP_ESTABLISHED:
427                 tcp_trans ( conn, TCP_FIN_WAIT_1 );
428                 conn->tcp_op->closed ( conn, CONN_SNDCLOSE ); /* TODO: Check! */
429                 /* FIN consumes one byte on the snd stream */
430 //              conn->snd_una++;
431                 goto send_tcp_nomsg;
432         case TCP_SYN_SENT:
433         case TCP_LISTEN:
434                 /**
435                  * Since the connection does not expect any packets from the
436                  * remote end, it can be removed from the set of listening
437                  * connections.
438                  */
439                 list_del ( &conn->list );
440                 tcp_trans ( conn, TCP_CLOSED );
441                 conn->tcp_op->closed ( conn, CONN_SNDCLOSE );
442                 return 0;
443         case TCP_CLOSE_WAIT:
444                 tcp_trans ( conn, TCP_LAST_ACK );
445                 conn->tcp_op->closed ( conn, CONN_SNDCLOSE ); /* TODO: Check! */
446                 /* FIN consumes one byte on the snd stream */
447 //              conn->snd_una++;
448                 goto send_tcp_nomsg;
449         default:
450                 DBG ( "tcp_close(): Invalid state %s\n",
451                                         tcp_states[conn->tcp_state] );
452                 return -EPROTO;
453         }
454
455   send_tcp_nomsg:
456         free_pkb ( conn->tx_pkb );
457         conn->tx_pkb = alloc_pkb ( MIN_PKB_LEN );
458         conn->tcp_flags = TCP_FIN;
459         pkb_reserve ( conn->tx_pkb, MAX_HDR_LEN );
460         return tcp_send ( conn, TCP_NOMSG, TCP_NOMSG_LEN );
461 }
462
463
464 /**
465  * Listen for a packet
466  *
467  * @v conn      TCP connection
468  * @v port      Local port, in network byte order
469  *
470  * This function adds the connection to a list of registered tcp connections. If
471  * the local port is 0, the connection is assigned the lowest available port
472  * between MIN_TCP_PORT and 65535.
473  */
474 int tcp_listen ( struct tcp_connection *conn, uint16_t port ) {
475         struct tcp_connection *cconn;
476         if ( port != 0 ) {
477                 list_for_each_entry ( cconn, &tcp_conns, list ) {
478                         if ( cconn->local_port == port ) {
479                                 DBG ( "Error listening to %d\n", 
480                                                         ntohs ( port ) );
481                                 return -EISCONN;
482                         }
483                 }
484                 /* Add the connection to the list of registered connections */
485                 conn->local_port = port;
486                 list_add ( &conn->list, &tcp_conns );
487                 return 0;
488         }
489         /* Assigning lowest port not supported */
490         DBG ( "Assigning lowest port not implemented\n");
491         return -ENOSYS;
492 }
493
494 /**
495  * Send data
496  *
497  * @v conn      TCP connection
498  * 
499  * This function allocates space to the transmit buffer and invokes the
500  * senddata() callback function. It passes the allocated buffer to senddata().
501  * The applicaion may use this space to write it's data.
502  */
503 int tcp_senddata ( struct tcp_connection *conn ) {
504         /* The connection must be in a state in which the user can send data */
505         switch ( conn->tcp_state ) {
506         case TCP_LISTEN:
507                 tcp_trans ( conn, TCP_SYN_SENT );
508                 conn->snd_una = ( ( ( uint32_t ) random() ) << 16 ) & random();
509                 break;
510         case TCP_ESTABLISHED:
511         case TCP_CLOSE_WAIT:
512                 break;
513         default:
514                 DBG ( "tcp_senddata: Invalid state %s\n",
515                                 tcp_states[conn->tcp_state] );
516                 return -EPROTO;
517         }
518
519         /* Allocate space to the TX buffer */
520         free_pkb ( conn->tx_pkb );
521         conn->tx_pkb = alloc_pkb ( MAX_PKB_LEN );
522         if ( !conn->tx_pkb ) {
523                 DBG ( "Insufficient memory\n" );
524                 return -ENOMEM;
525         }
526         pkb_reserve ( conn->tx_pkb, MAX_HDR_LEN );
527         /* Set the advertised window */
528         conn->rcv_win = pkb_available ( conn->tx_pkb );
529         /* Call the senddata() call back function */
530         conn->tcp_op->senddata ( conn, conn->tx_pkb->data, 
531                                         pkb_available ( conn->tx_pkb ) );
532         return 0;
533 }
534
535 /**
536  * Transmit data
537  *
538  * @v conn      TCP connection
539  * @v data      Data to be sent
540  * @v len       Length of the data
541  *
542  * This function sends data to the peer socket address
543  */
544 int tcp_send ( struct tcp_connection *conn, const void *data, size_t len ) {
545         struct sockaddr *peer = &conn->sa;
546         struct pk_buff *pkb = conn->tx_pkb;
547         int slen;
548
549         /* Determine the amount of data to be sent */
550         slen = len < conn->snd_win ? len : conn->snd_win;
551         /* Copy payload */
552         memmove ( pkb_put ( pkb, slen ), data, slen );
553
554         /* Fill up the TCP header */
555         struct tcp_header *tcphdr = pkb_push ( pkb, sizeof ( *tcphdr ) );
556
557         /* Source port, assumed to be in network byte order in conn */
558         tcphdr->src = conn->local_port;
559         /* Destination port, assumed to be in network byte order in peer */
560         switch ( peer->sa_family ) {
561         case AF_INET:
562                 tcphdr->dest = peer->sin.sin_port;
563                 break;
564         case AF_INET6:
565                 tcphdr->dest = peer->sin6.sin6_port;
566                 break;
567         default:
568                 DBG ( "Family type %d not supported\n", 
569                                         peer->sa_family );
570                 return -EAFNOSUPPORT;
571         }
572         tcphdr->seq = htonl ( conn->snd_una );
573         tcphdr->ack = htonl ( conn->rcv_nxt );
574         /* Header length, = 0x50 (without TCP options) */
575         tcphdr->hlen = ( uint8_t ) ( ( sizeof ( *tcphdr ) / 4 ) << 4 );
576         /* Copy TCP flags, and then reset the variable */
577         tcphdr->flags = conn->tcp_flags;
578         conn->tcp_flags = 0;
579         /* Advertised window, in network byte order */
580         tcphdr->win = htons ( conn->rcv_win );
581         /* Set urgent pointer to 0 */
582         tcphdr->urg = 0;
583         /* Calculate and store partial checksum, in network byte order */
584         tcphdr->csum = 0;
585         tcphdr->csum = tcpip_chksum ( pkb->data, pkb_len ( pkb ) );
586         
587         /* Dump the TCP header */
588         tcp_dump ( tcphdr );
589
590         /* Transmit packet */
591         return tcpip_tx ( pkb, &tcp_protocol, peer );
592 }
593
594 /**
595  * Process received packet
596  *
597  * @v pkb       Packet buffer
598  * @v partial   Partial checksum
599  */
600 void tcp_rx ( struct pk_buff *pkb, uint16_t partial ) {
601         struct tcp_connection *conn;
602         struct tcp_header *tcphdr;
603         uint32_t acked, toack;
604         int hlen;
605
606         /* Sanity check */
607         if ( pkb_len ( pkb ) < sizeof ( *tcphdr ) ) {
608                 DBG ( "Packet too short (%d bytes)\n", pkb_len ( pkb ) );
609                 return;
610         }
611
612         /* Process TCP header */
613         tcphdr = pkb->data;
614
615         /* Verify header length */
616         hlen = ( ( tcphdr->hlen & TCP_MASK_HLEN ) / 16 ) * 4;
617         if ( hlen != sizeof ( *tcphdr ) ) {
618                 DBG ( "Bad header length (%d bytes)\n", hlen );
619                 return;
620         }
621         
622         /* TODO: Verify checksum */
623         
624         /* Demux TCP connection */
625         list_for_each_entry ( conn, &tcp_conns, list ) {
626                 if ( tcphdr->dest == conn->local_port ) {
627                         goto found_conn;
628                 }
629         }
630         
631         DBG ( "No connection found on port %d\n", ntohs ( tcphdr->dest ) );
632         return;
633
634   found_conn:
635         /* Set the advertised window */
636         conn->snd_win = tcphdr->win;
637
638         /* TCP State Machine */
639         uint8_t out_flags = 0;
640         conn->tcp_lstate = conn->tcp_state;
641         switch ( conn->tcp_state ) {
642         case TCP_CLOSED:
643                 DBG ( "tcp_rx(): Invalid state %s\n",
644                                 tcp_states[conn->tcp_state] );
645                 return;
646         case TCP_LISTEN:
647                 if ( tcphdr->flags & TCP_SYN ) {
648                         tcp_trans ( conn, TCP_SYN_RCVD );
649                         /* Synchronize the sequence numbers */
650                         conn->rcv_nxt = ntohl ( tcphdr->seq ) + 1;
651                         out_flags |= TCP_ACK;
652
653                         /* Set the sequence number for the snd stream */
654                         conn->snd_una = ( ( ( uint32_t ) random() ) << 16 );
655                         conn->snd_una &= random();
656                         out_flags |= TCP_SYN;
657
658                         /* Send a SYN,ACK packet */
659                         goto send_tcp_nomsg;
660                 }
661                 /* Unexpected packet */
662                 goto unexpected;
663         case TCP_SYN_SENT:
664                 if ( tcphdr->flags & TCP_SYN ) {
665                         /* Synchronize the sequence number in rcv stream */
666                         conn->rcv_nxt = ntohl ( tcphdr->seq ) + 1;
667                         out_flags |= TCP_ACK;
668
669                         if ( tcphdr->flags & TCP_ACK ) {
670                                 tcp_trans ( conn, TCP_ESTABLISHED );
671                                 /**
672                                  * Process ACK of SYN. This does not invoke the
673                                  * acked() callback function.
674                                  */
675                                 conn->snd_una = ntohl ( tcphdr->ack );
676                                 conn->tcp_op->connected ( conn );
677                         } else {
678                                 tcp_trans ( conn, TCP_SYN_RCVD );
679                                 out_flags |= TCP_SYN;
680                         }
681                         /* Send SYN,ACK or ACK packet */
682                         goto send_tcp_nomsg;
683                 }
684                 /* Unexpected packet */
685                 goto unexpected;
686         case TCP_SYN_RCVD:
687                 if ( tcphdr->flags & TCP_RST ) {
688                         tcp_trans ( conn, TCP_LISTEN );
689                         conn->tcp_op->closed ( conn, CONN_RESTART );
690                         return;
691                 }
692                 if ( tcphdr->flags & TCP_ACK ) {
693                         tcp_trans ( conn, TCP_ESTABLISHED );
694                         /**
695                          * Process ACK of SYN. It neither invokes the callback
696                          * function nor does it send an ACK.
697                          */
698                         conn->snd_una = tcphdr->ack - 1;
699                         conn->tcp_op->connected ( conn );
700                         return;
701                 }
702                 /* Unexpected packet */
703                 goto unexpected;
704         case TCP_ESTABLISHED:
705                 if ( tcphdr->flags & TCP_FIN ) {
706                         tcp_trans ( conn, TCP_CLOSE_WAIT );
707                         /* FIN consumes one byte */
708                         conn->rcv_nxt++;
709                         out_flags |= TCP_ACK;
710                         /* Send an acknowledgement */
711                         goto send_tcp_nomsg;
712                 }
713                 /* Packet might contain data */
714                 break;
715         case TCP_FIN_WAIT_1:
716                 if ( tcphdr->flags & TCP_FIN ) {
717                         conn->rcv_nxt++;
718                         out_flags |= TCP_ACK;
719                         conn->tcp_op->closed ( conn, CONN_SNDCLOSE );
720
721                         if ( tcphdr->flags & TCP_ACK ) {
722                                 tcp_trans ( conn, TCP_TIME_WAIT );
723                         } else {
724                                 tcp_trans ( conn, TCP_CLOSING );
725                         }
726                         /* Send an acknowledgement */
727                         goto send_tcp_nomsg;
728                 }
729                 if ( tcphdr->flags & TCP_ACK ) {
730                         tcp_trans ( conn, TCP_FIN_WAIT_2 );
731                 }
732                 /* Packet might contain data */
733                 break;
734         case TCP_FIN_WAIT_2:
735                 if ( tcphdr->flags & TCP_FIN ) {
736                         tcp_trans ( conn, TCP_TIME_WAIT );
737                         /* FIN consumes one byte */
738                         conn->rcv_nxt++;
739                         out_flags |= TCP_ACK;
740                         goto send_tcp_nomsg;
741                 }
742                 /* Packet might contain data */
743                 break;
744         case TCP_CLOSING:
745                 if ( tcphdr->flags & TCP_ACK ) {
746                         tcp_trans ( conn, TCP_TIME_WAIT );
747                         return;
748                 }
749                 /* Unexpected packet */
750                 goto unexpected;
751         case TCP_TIME_WAIT:
752                 /* Unexpected packet */
753                 goto unexpected;
754         case TCP_CLOSE_WAIT:
755                 /* Packet could acknowledge data */
756                 break;
757         case TCP_LAST_ACK:
758                 if ( tcphdr->flags & TCP_ACK ) {
759                         tcp_trans ( conn, TCP_CLOSED );
760                         return;
761                 }
762                 /* Unexpected packet */
763                 goto unexpected;
764         }
765
766         /**
767          * Any packet reaching this point either contains new data or
768          * acknowledges previously transmitted data.
769          */
770         assert ( ( tcphdr->flags & TCP_ACK ) ||
771                  pkb_len ( pkb ) > sizeof ( *tcphdr ) );
772
773         /* Check for new data */
774         toack = pkb_len ( pkb ) - hlen;
775         if ( toack > 0 ) {
776                 /* Check if expected sequence number */
777                 if ( conn->rcv_nxt == ntohl ( tcphdr->seq ) ) {
778                         conn->rcv_nxt += toack;
779                         conn->tcp_op->newdata ( conn, pkb->data + sizeof ( *tcphdr ), toack );
780                 }
781
782                 /* Acknowledge new data */
783                 out_flags |= TCP_ACK;
784                 if ( !( tcphdr->flags & TCP_ACK ) ) {
785                         goto send_tcp_nomsg;
786                 }
787         }
788
789         /* Process ACK */
790         if ( tcphdr->flags & TCP_ACK ) {
791                 acked = ntohl ( tcphdr->ack ) - conn->snd_una;
792                 if ( acked < 0 ) { /* TODO: Replace all uint32_t arith */
793                         DBG ( "Previously ACKed (%d)\n", tcphdr->ack );
794                         return;
795                 }
796                 /* Advance snd stream */
797                 conn->snd_una += acked;
798                 /* Set the ACK flag */
799                 conn->tcp_flags |= TCP_ACK;
800                 /* Invoke the acked() callback function */
801                 conn->tcp_op->acked ( conn, acked );
802                 /* Invoke the senddata() callback function */
803                 tcp_senddata ( conn );
804         }
805         return;
806
807   send_tcp_nomsg:
808         free_pkb ( conn->tx_pkb );
809         conn->tx_pkb = alloc_pkb ( MIN_PKB_LEN );
810         pkb_reserve ( conn->tx_pkb, MAX_HDR_LEN );
811         int rc;
812         if ( ( rc = tcp_send ( conn, TCP_NOMSG, TCP_NOMSG_LEN ) ) != 0 ) {
813                 DBG ( "Error sending TCP message (rc = %d)\n", rc );
814         }
815         return;
816
817   unexpected:
818         DBG ( "Unexpected packet received in %d state with flags = %hd\n",
819                         conn->tcp_state, tcphdr->flags & TCP_MASK_FLAGS );
820         free_pkb ( conn->tx_pkb );
821         return;
822 }
823
824 /** TCP protocol */
825 struct tcpip_protocol tcp_protocol = {
826         .name = "TCP",
827         .rx = tcp_rx,
828         .trans_proto = IP_TCP,
829         .csum_offset = 16,
830 };
831
832 TCPIP_PROTOCOL ( tcp_protocol );
833
834 #endif /* USE_UIP */