Added features that will be required for PXE UDP support.
[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,
383                     struct sockaddr_tcpip *peer ) {
384         int rc;
385
386         /* A connection can only be established from the CLOSED state */
387         if ( conn->tcp_state != TCP_CLOSED ) {
388                 DBG ( "Error opening connection: Invalid state %s\n",
389                                 tcp_states[conn->tcp_state] );
390                 return -EISCONN;
391         }
392
393         /* Add the connection to the set of listening connections */
394         if ( ( rc = tcp_listen ( conn, conn->local_port ) ) != 0 ) {
395                 return rc;
396         }
397         memcpy ( &conn->peer, peer, sizeof ( conn->peer ) );
398
399         /* Send a SYN packet and transition to TCP_SYN_SENT */
400         conn->snd_una = ( ( ( uint32_t ) random() ) << 16 ) & random();
401         tcp_trans ( conn, TCP_SYN_SENT );
402         /* Allocate space for the packet */
403         free_pkb ( conn->tx_pkb );
404         conn->tx_pkb = alloc_pkb ( MIN_PKB_LEN );
405         pkb_reserve ( conn->tx_pkb, MAX_HDR_LEN );
406         conn->rcv_win = MAX_PKB_LEN - MAX_HDR_LEN; /* TODO: Is this OK? */
407         return tcp_send ( conn, TCP_NOMSG, TCP_NOMSG_LEN );
408 }
409
410 int tcp_connect ( struct tcp_connection *conn ) {
411         return tcp_connectto ( conn, &conn->peer );
412 }
413
414 /**
415  * Close the connection
416  *
417  * @v conn
418  *
419  * This function sends a FIN packet to the remote end of the connection. When
420  * the remote end of the connection ACKs the FIN (FIN consumes one byte on the
421  * snd stream), the stack invokes the closed() callback function.
422  */
423 int tcp_close ( struct tcp_connection *conn ) {
424         /* A connection can only be closed if it is a connected state */
425         switch ( conn->tcp_state ) {
426         case TCP_SYN_RCVD:
427         case TCP_ESTABLISHED:
428                 tcp_trans ( conn, TCP_FIN_WAIT_1 );
429                 conn->tcp_op->closed ( conn, CONN_SNDCLOSE ); /* TODO: Check! */
430                 /* FIN consumes one byte on the snd stream */
431 //              conn->snd_una++;
432                 goto send_tcp_nomsg;
433         case TCP_SYN_SENT:
434         case TCP_LISTEN:
435                 /**
436                  * Since the connection does not expect any packets from the
437                  * remote end, it can be removed from the set of listening
438                  * connections.
439                  */
440                 list_del ( &conn->list );
441                 tcp_trans ( conn, TCP_CLOSED );
442                 conn->tcp_op->closed ( conn, CONN_SNDCLOSE );
443                 return 0;
444         case TCP_CLOSE_WAIT:
445                 tcp_trans ( conn, TCP_LAST_ACK );
446                 conn->tcp_op->closed ( conn, CONN_SNDCLOSE ); /* TODO: Check! */
447                 /* FIN consumes one byte on the snd stream */
448 //              conn->snd_una++;
449                 goto send_tcp_nomsg;
450         default:
451                 DBG ( "tcp_close(): Invalid state %s\n",
452                                         tcp_states[conn->tcp_state] );
453                 return -EPROTO;
454         }
455
456   send_tcp_nomsg:
457         free_pkb ( conn->tx_pkb );
458         conn->tx_pkb = alloc_pkb ( MIN_PKB_LEN );
459         conn->tcp_flags = TCP_FIN;
460         pkb_reserve ( conn->tx_pkb, MAX_HDR_LEN );
461         return tcp_send ( conn, TCP_NOMSG, TCP_NOMSG_LEN );
462 }
463
464
465 /**
466  * Listen for a packet
467  *
468  * @v conn      TCP connection
469  * @v port      Local port, in network byte order
470  *
471  * This function adds the connection to a list of registered tcp connections. If
472  * the local port is 0, the connection is assigned the lowest available port
473  * between MIN_TCP_PORT and 65535.
474  */
475 int tcp_listen ( struct tcp_connection *conn, uint16_t port ) {
476         struct tcp_connection *cconn;
477         if ( port != 0 ) {
478                 list_for_each_entry ( cconn, &tcp_conns, list ) {
479                         if ( cconn->local_port == port ) {
480                                 DBG ( "Error listening to %d\n", 
481                                                         ntohs ( port ) );
482                                 return -EISCONN;
483                         }
484                 }
485                 /* Add the connection to the list of registered connections */
486                 conn->local_port = port;
487                 list_add ( &conn->list, &tcp_conns );
488                 return 0;
489         }
490         /* Assigning lowest port not supported */
491         DBG ( "Assigning lowest port not implemented\n");
492         return -ENOSYS;
493 }
494
495 /**
496  * Send data
497  *
498  * @v conn      TCP connection
499  * 
500  * This function allocates space to the transmit buffer and invokes the
501  * senddata() callback function. It passes the allocated buffer to senddata().
502  * The applicaion may use this space to write it's data.
503  */
504 int tcp_senddata ( struct tcp_connection *conn ) {
505         /* The connection must be in a state in which the user can send data */
506         switch ( conn->tcp_state ) {
507         case TCP_LISTEN:
508                 tcp_trans ( conn, TCP_SYN_SENT );
509                 conn->snd_una = ( ( ( uint32_t ) random() ) << 16 ) & random();
510                 break;
511         case TCP_ESTABLISHED:
512         case TCP_CLOSE_WAIT:
513                 break;
514         default:
515                 DBG ( "tcp_senddata: Invalid state %s\n",
516                                 tcp_states[conn->tcp_state] );
517                 return -EPROTO;
518         }
519
520         /* Allocate space to the TX buffer */
521         free_pkb ( conn->tx_pkb );
522         conn->tx_pkb = alloc_pkb ( MAX_PKB_LEN );
523         if ( !conn->tx_pkb ) {
524                 DBG ( "Insufficient memory\n" );
525                 return -ENOMEM;
526         }
527         pkb_reserve ( conn->tx_pkb, MAX_HDR_LEN );
528         /* Set the advertised window */
529         conn->rcv_win = pkb_available ( conn->tx_pkb );
530         /* Call the senddata() call back function */
531         conn->tcp_op->senddata ( conn, conn->tx_pkb->data, 
532                                         pkb_available ( conn->tx_pkb ) );
533         return 0;
534 }
535
536 /**
537  * Transmit data
538  *
539  * @v conn      TCP connection
540  * @v data      Data to be sent
541  * @v len       Length of the data
542  *
543  * This function sends data to the peer socket address
544  */
545 int tcp_send ( struct tcp_connection *conn, const void *data, size_t len ) {
546         struct sockaddr_tcpip *peer = &conn->peer;
547         struct pk_buff *pkb = conn->tx_pkb;
548         int slen;
549
550         /* Determine the amount of data to be sent */
551         slen = len < conn->snd_win ? len : conn->snd_win;
552         /* Copy payload */
553         memmove ( pkb_put ( pkb, slen ), data, slen );
554
555         /* Fill up the TCP header */
556         struct tcp_header *tcphdr = pkb_push ( pkb, sizeof ( *tcphdr ) );
557
558         /* Source port, assumed to be in network byte order in conn */
559         tcphdr->src = conn->local_port;
560         /* Destination port, assumed to be in network byte order in peer */
561         tcphdr->dest = peer->st_port;
562         tcphdr->seq = htonl ( conn->snd_una );
563         tcphdr->ack = htonl ( conn->rcv_nxt );
564         /* Header length, = 0x50 (without TCP options) */
565         tcphdr->hlen = ( uint8_t ) ( ( sizeof ( *tcphdr ) / 4 ) << 4 );
566         /* Copy TCP flags, and then reset the variable */
567         tcphdr->flags = conn->tcp_flags;
568         conn->tcp_flags = 0;
569         /* Advertised window, in network byte order */
570         tcphdr->win = htons ( conn->rcv_win );
571         /* Set urgent pointer to 0 */
572         tcphdr->urg = 0;
573         /* Calculate and store partial checksum, in network byte order */
574         tcphdr->csum = 0;
575         tcphdr->csum = tcpip_chksum ( pkb->data, pkb_len ( pkb ) );
576         
577         /* Dump the TCP header */
578         tcp_dump ( tcphdr );
579
580         /* Transmit packet */
581         return tcpip_tx ( pkb, &tcp_protocol, peer );
582 }
583
584 /**
585  * Process received packet
586  *
587  * @v pkb       Packet buffer
588  * @v partial   Partial checksum
589  */
590 static int tcp_rx ( struct pk_buff *pkb,
591                     struct sockaddr_tcpip *st_src __unused,
592                     struct sockaddr_tcpip *st_dest __unused ) {
593         struct tcp_connection *conn;
594         struct tcp_header *tcphdr;
595         uint32_t acked, toack;
596         int hlen;
597
598         /* Sanity check */
599         if ( pkb_len ( pkb ) < sizeof ( *tcphdr ) ) {
600                 DBG ( "Packet too short (%d bytes)\n", pkb_len ( pkb ) );
601                 return -EINVAL;
602         }
603
604         /* Process TCP header */
605         tcphdr = pkb->data;
606
607         /* Verify header length */
608         hlen = ( ( tcphdr->hlen & TCP_MASK_HLEN ) / 16 ) * 4;
609         if ( hlen != sizeof ( *tcphdr ) ) {
610                 DBG ( "Bad header length (%d bytes)\n", hlen );
611                 return -EINVAL;
612         }
613         
614         /* TODO: Verify checksum */
615         
616         /* Demux TCP connection */
617         list_for_each_entry ( conn, &tcp_conns, list ) {
618                 if ( tcphdr->dest == conn->local_port ) {
619                         goto found_conn;
620                 }
621         }
622         
623         DBG ( "No connection found on port %d\n", ntohs ( tcphdr->dest ) );
624         return 0;
625
626   found_conn:
627         /* Set the advertised window */
628         conn->snd_win = tcphdr->win;
629
630         /* TCP State Machine */
631         uint8_t out_flags = 0;
632         conn->tcp_lstate = conn->tcp_state;
633         switch ( conn->tcp_state ) {
634         case TCP_CLOSED:
635                 DBG ( "tcp_rx(): Invalid state %s\n",
636                                 tcp_states[conn->tcp_state] );
637                 return -EINVAL;
638         case TCP_LISTEN:
639                 if ( tcphdr->flags & TCP_SYN ) {
640                         tcp_trans ( conn, TCP_SYN_RCVD );
641                         /* Synchronize the sequence numbers */
642                         conn->rcv_nxt = ntohl ( tcphdr->seq ) + 1;
643                         out_flags |= TCP_ACK;
644
645                         /* Set the sequence number for the snd stream */
646                         conn->snd_una = ( ( ( uint32_t ) random() ) << 16 );
647                         conn->snd_una &= random();
648                         out_flags |= TCP_SYN;
649
650                         /* Send a SYN,ACK packet */
651                         goto send_tcp_nomsg;
652                 }
653                 /* Unexpected packet */
654                 goto unexpected;
655         case TCP_SYN_SENT:
656                 if ( tcphdr->flags & TCP_SYN ) {
657                         /* Synchronize the sequence number in rcv stream */
658                         conn->rcv_nxt = ntohl ( tcphdr->seq ) + 1;
659                         out_flags |= TCP_ACK;
660
661                         if ( tcphdr->flags & TCP_ACK ) {
662                                 tcp_trans ( conn, TCP_ESTABLISHED );
663                                 /**
664                                  * Process ACK of SYN. This does not invoke the
665                                  * acked() callback function.
666                                  */
667                                 conn->snd_una = ntohl ( tcphdr->ack );
668                                 conn->tcp_op->connected ( conn );
669                         } else {
670                                 tcp_trans ( conn, TCP_SYN_RCVD );
671                                 out_flags |= TCP_SYN;
672                         }
673                         /* Send SYN,ACK or ACK packet */
674                         goto send_tcp_nomsg;
675                 }
676                 /* Unexpected packet */
677                 goto unexpected;
678         case TCP_SYN_RCVD:
679                 if ( tcphdr->flags & TCP_RST ) {
680                         tcp_trans ( conn, TCP_LISTEN );
681                         conn->tcp_op->closed ( conn, CONN_RESTART );
682                         return 0;
683                 }
684                 if ( tcphdr->flags & TCP_ACK ) {
685                         tcp_trans ( conn, TCP_ESTABLISHED );
686                         /**
687                          * Process ACK of SYN. It neither invokes the callback
688                          * function nor does it send an ACK.
689                          */
690                         conn->snd_una = tcphdr->ack - 1;
691                         conn->tcp_op->connected ( conn );
692                         return 0;
693                 }
694                 /* Unexpected packet */
695                 goto unexpected;
696         case TCP_ESTABLISHED:
697                 if ( tcphdr->flags & TCP_FIN ) {
698                         tcp_trans ( conn, TCP_CLOSE_WAIT );
699                         /* FIN consumes one byte */
700                         conn->rcv_nxt++;
701                         out_flags |= TCP_ACK;
702                         /* Send an acknowledgement */
703                         goto send_tcp_nomsg;
704                 }
705                 /* Packet might contain data */
706                 break;
707         case TCP_FIN_WAIT_1:
708                 if ( tcphdr->flags & TCP_FIN ) {
709                         conn->rcv_nxt++;
710                         out_flags |= TCP_ACK;
711                         conn->tcp_op->closed ( conn, CONN_SNDCLOSE );
712
713                         if ( tcphdr->flags & TCP_ACK ) {
714                                 tcp_trans ( conn, TCP_TIME_WAIT );
715                         } else {
716                                 tcp_trans ( conn, TCP_CLOSING );
717                         }
718                         /* Send an acknowledgement */
719                         goto send_tcp_nomsg;
720                 }
721                 if ( tcphdr->flags & TCP_ACK ) {
722                         tcp_trans ( conn, TCP_FIN_WAIT_2 );
723                 }
724                 /* Packet might contain data */
725                 break;
726         case TCP_FIN_WAIT_2:
727                 if ( tcphdr->flags & TCP_FIN ) {
728                         tcp_trans ( conn, TCP_TIME_WAIT );
729                         /* FIN consumes one byte */
730                         conn->rcv_nxt++;
731                         out_flags |= TCP_ACK;
732                         goto send_tcp_nomsg;
733                 }
734                 /* Packet might contain data */
735                 break;
736         case TCP_CLOSING:
737                 if ( tcphdr->flags & TCP_ACK ) {
738                         tcp_trans ( conn, TCP_TIME_WAIT );
739                         return 0;
740                 }
741                 /* Unexpected packet */
742                 goto unexpected;
743         case TCP_TIME_WAIT:
744                 /* Unexpected packet */
745                 goto unexpected;
746         case TCP_CLOSE_WAIT:
747                 /* Packet could acknowledge data */
748                 break;
749         case TCP_LAST_ACK:
750                 if ( tcphdr->flags & TCP_ACK ) {
751                         tcp_trans ( conn, TCP_CLOSED );
752                         return 0;
753                 }
754                 /* Unexpected packet */
755                 goto unexpected;
756         }
757
758         /**
759          * Any packet reaching this point either contains new data or
760          * acknowledges previously transmitted data.
761          */
762         assert ( ( tcphdr->flags & TCP_ACK ) ||
763                  pkb_len ( pkb ) > sizeof ( *tcphdr ) );
764
765         /* Check for new data */
766         toack = pkb_len ( pkb ) - hlen;
767         if ( toack > 0 ) {
768                 /* Check if expected sequence number */
769                 if ( conn->rcv_nxt == ntohl ( tcphdr->seq ) ) {
770                         conn->rcv_nxt += toack;
771                         conn->tcp_op->newdata ( conn, pkb->data + sizeof ( *tcphdr ), toack );
772                 }
773
774                 /* Acknowledge new data */
775                 out_flags |= TCP_ACK;
776                 if ( !( tcphdr->flags & TCP_ACK ) ) {
777                         goto send_tcp_nomsg;
778                 }
779         }
780
781         /* Process ACK */
782         if ( tcphdr->flags & TCP_ACK ) {
783                 acked = ntohl ( tcphdr->ack ) - conn->snd_una;
784                 if ( acked < 0 ) { /* TODO: Replace all uint32_t arith */
785                         DBG ( "Previously ACKed (%d)\n", tcphdr->ack );
786                         return 0;
787                 }
788                 /* Advance snd stream */
789                 conn->snd_una += acked;
790                 /* Set the ACK flag */
791                 conn->tcp_flags |= TCP_ACK;
792                 /* Invoke the acked() callback function */
793                 conn->tcp_op->acked ( conn, acked );
794                 /* Invoke the senddata() callback function */
795                 tcp_senddata ( conn );
796         }
797         return 0;
798
799   send_tcp_nomsg:
800         free_pkb ( conn->tx_pkb );
801         conn->tx_pkb = alloc_pkb ( MIN_PKB_LEN );
802         pkb_reserve ( conn->tx_pkb, MAX_HDR_LEN );
803         int rc;
804         if ( ( rc = tcp_send ( conn, TCP_NOMSG, TCP_NOMSG_LEN ) ) != 0 ) {
805                 DBG ( "Error sending TCP message (rc = %d)\n", rc );
806         }
807         return 0;
808
809   unexpected:
810         DBG ( "Unexpected packet received in %d state with flags = %hd\n",
811                         conn->tcp_state, tcphdr->flags & TCP_MASK_FLAGS );
812         free_pkb ( conn->tx_pkb );
813         return -EINVAL;
814 }
815
816 /** TCP protocol */
817 struct tcpip_protocol tcp_protocol = {
818         .name = "TCP",
819         .rx = tcp_rx,
820         .tcpip_proto = IP_TCP,
821         .csum_offset = 16,
822 };
823
824 TCPIP_PROTOCOL ( tcp_protocol );
825
826 #endif /* USE_UIP */