tcp.c File Reference

TCP protocol. More...

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <byteswap.h>
#include <gpxe/timer.h>
#include <gpxe/iobuf.h>
#include <gpxe/malloc.h>
#include <gpxe/retry.h>
#include <gpxe/refcnt.h>
#include <gpxe/xfer.h>
#include <gpxe/open.h>
#include <gpxe/uri.h>
#include <gpxe/tcpip.h>
#include <gpxe/tcp.h>

Go to the source code of this file.

Data Structures

struct  tcp_connection
 A TCP connection. More...

Functions

 FILE_LICENCE (GPL2_OR_LATER)
static LIST_HEAD (tcp_conns)
 List of registered TCP connections.
static void tcp_expired (struct retry_timer *timer, int over)
 Retransmission timer expired.
static int tcp_rx_ack (struct tcp_connection *tcp, uint32_t ack, uint32_t win)
 Handle TCP received ACK.
static const char * tcp_state (int state)
 Name TCP state.
static void tcp_dump_state (struct tcp_connection *tcp)
 Dump TCP state transition.
static void tcp_dump_flags (struct tcp_connection *tcp, unsigned int flags)
 Dump TCP flags.
static int tcp_bind (struct tcp_connection *tcp, unsigned int port)
 Bind TCP connection to local port.
static int tcp_open (struct xfer_interface *xfer, struct sockaddr *peer, struct sockaddr *local)
 Open a TCP connection.
static void tcp_close (struct tcp_connection *tcp, int rc)
 Close TCP connection.
static size_t tcp_xmit_win (struct tcp_connection *tcp)
 Calculate transmission window.
static size_t tcp_process_queue (struct tcp_connection *tcp, size_t max_len, struct io_buffer *dest, int remove)
 Process TCP transmit queue.
static int tcp_xmit (struct tcp_connection *tcp, int force_send)
 Transmit any outstanding data.
static int tcp_xmit_reset (struct tcp_connection *tcp, struct sockaddr_tcpip *st_dest, struct tcp_header *in_tcphdr)
 Send RST response to incoming packet.
static struct tcp_connectiontcp_demux (unsigned int local_port)
 Identify TCP connection by local port number.
static void tcp_rx_opts (struct tcp_connection *tcp, const void *data, size_t len, struct tcp_options *options)
 Parse TCP received options.
static void tcp_rx_seq (struct tcp_connection *tcp, uint32_t seq_len)
 Consume received sequence space.
static int tcp_rx_syn (struct tcp_connection *tcp, uint32_t seq, struct tcp_options *options)
 Handle TCP received SYN.
static int tcp_rx_data (struct tcp_connection *tcp, uint32_t seq, struct io_buffer *iobuf)
 Handle TCP received data.
static int tcp_rx_fin (struct tcp_connection *tcp, uint32_t seq)
 Handle TCP received FIN.
static int tcp_rx_rst (struct tcp_connection *tcp, uint32_t seq)
 Handle TCP received RST.
static int tcp_rx (struct io_buffer *iobuf, struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest __unused, uint16_t pshdr_csum)
 Process received packet.
static void tcp_xfer_close (struct xfer_interface *xfer, int rc)
 Close interface.
static size_t tcp_xfer_window (struct xfer_interface *xfer)
 Check flow control window.
static int tcp_xfer_deliver_iob (struct xfer_interface *xfer, struct io_buffer *iobuf, struct xfer_metadata *meta __unused)
 Deliver datagram as I/O buffer.
static int tcp_open_uri (struct xfer_interface *xfer, struct uri *uri)
 Open TCP URI.

Variables

static struct
xfer_interface_operations 
tcp_xfer_operations
 TCP data transfer interface operations.
struct tcpip_protocol tcp_protocol __tcpip_protocol
 TCP protocol.
struct socket_opener
tcp_socket_opener 
__socket_opener
 TCP socket opener.
int tcp_sock_stream = TCP_SOCK_STREAM
 Linkage hack.
struct uri_opener tcp_uri_opener __uri_opener
 TCP URI opener.


Detailed Description

TCP protocol.

Definition in file tcp.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER   ) 

static LIST_HEAD ( tcp_conns   )  [static]

List of registered TCP connections.

static void tcp_expired ( struct retry_timer timer,
int  over 
) [static]

Retransmission timer expired.

Parameters:
timer Retry timer
over Failure indicator

Definition at line 518 of file tcp.c.

References assert, container_of, DBGC, ETIMEDOUT, tcp_connection::rcv_ack, tcp_connection::snd_sent, tcp_connection::snd_seq, tcp_close(), TCP_CLOSE_WAIT, TCP_CLOSED, TCP_CLOSED_GRACEFULLY, TCP_CLOSING_OR_LAST_ACK, tcp_dump_state(), TCP_ESTABLISHED, TCP_FIN_WAIT_1, tcp_state(), tcp_connection::tcp_state, TCP_SYN_RCVD, TCP_SYN_SENT, TCP_TIME_WAIT, and tcp_xmit().

Referenced by tcp_open().

00518                                                                 {
00519         struct tcp_connection *tcp =
00520                 container_of ( timer, struct tcp_connection, timer );
00521         int graceful_close = TCP_CLOSED_GRACEFULLY ( tcp->tcp_state );
00522 
00523         DBGC ( tcp, "TCP %p timer %s in %s for %08x..%08x %08x\n", tcp,
00524                ( over ? "expired" : "fired" ), tcp_state ( tcp->tcp_state ),
00525                tcp->snd_seq, ( tcp->snd_seq + tcp->snd_sent ), tcp->rcv_ack );
00526 
00527         assert ( ( tcp->tcp_state == TCP_SYN_SENT ) ||
00528                  ( tcp->tcp_state == TCP_SYN_RCVD ) ||
00529                  ( tcp->tcp_state == TCP_ESTABLISHED ) ||
00530                  ( tcp->tcp_state == TCP_FIN_WAIT_1 ) ||
00531                  ( tcp->tcp_state == TCP_TIME_WAIT ) ||
00532                  ( tcp->tcp_state == TCP_CLOSE_WAIT ) ||
00533                  ( tcp->tcp_state == TCP_CLOSING_OR_LAST_ACK ) );
00534 
00535         if ( over || graceful_close ) {
00536                 /* If we have finally timed out and given up, or if
00537                  * this is the result of a graceful close, terminate
00538                  * the connection
00539                  */
00540                 tcp->tcp_state = TCP_CLOSED;
00541                 tcp_dump_state ( tcp );
00542                 tcp_close ( tcp, -ETIMEDOUT );
00543         } else {
00544                 /* Otherwise, retransmit the packet */
00545                 tcp_xmit ( tcp, 0 );
00546         }
00547 }

static int tcp_rx_ack ( struct tcp_connection tcp,
uint32_t  ack,
uint32_t  win 
) [static]

Handle TCP received ACK.

Parameters:
tcp TCP connection
ack ACK value (in host-endian order)
win WIN value (in host-endian order)
Return values:
rc Return status code

Definition at line 723 of file tcp.c.

References DBGC, EINVAL, list_empty(), NULL, tcp_connection::queue, tcp_connection::snd_sent, tcp_connection::snd_seq, tcp_connection::snd_win, stop_timer(), TCP_FIN, TCP_FLAGS_SENDING, TCP_HAS_BEEN_ESTABLISHED, tcp_process_queue(), tcp_connection::tcp_state, TCP_STATE_ACKED, TCP_STATE_SENT, TCP_SYN, tcp_connection::timer, and tcp_connection::xfer_closed.

Referenced by tcp_close(), and tcp_rx().

00724                                        {
00725         uint32_t ack_len = ( ack - tcp->snd_seq );
00726         size_t len;
00727         unsigned int acked_flags;
00728 
00729         /* Check for out-of-range or old duplicate ACKs */
00730         if ( ack_len > tcp->snd_sent ) {
00731                 DBGC ( tcp, "TCP %p received ACK for %08x..%08x, "
00732                        "sent only %08x..%08x\n", tcp, tcp->snd_seq,
00733                        ( tcp->snd_seq + ack_len ), tcp->snd_seq,
00734                        ( tcp->snd_seq + tcp->snd_sent ) );
00735 
00736                 if ( TCP_HAS_BEEN_ESTABLISHED ( tcp->tcp_state ) ) {
00737                         /* Just ignore what might be old duplicate ACKs */
00738                         return 0;
00739                 } else {
00740                         /* Send RST if an out-of-range ACK is received
00741                          * on a not-yet-established connection, as per
00742                          * RFC 793.
00743                          */
00744                         return -EINVAL;
00745                 }
00746         }
00747 
00748         /* Ignore ACKs that don't actually acknowledge any new data.
00749          * (In particular, do not stop the retransmission timer; this
00750          * avoids creating a sorceror's apprentice syndrome when a
00751          * duplicate ACK is received and we still have data in our
00752          * transmit queue.)
00753          */
00754         if ( ack_len == 0 )
00755                 return 0;
00756 
00757         /* Stop the retransmission timer */
00758         stop_timer ( &tcp->timer );
00759 
00760         /* Determine acknowledged flags and data length */
00761         len = ack_len;
00762         acked_flags = ( TCP_FLAGS_SENDING ( tcp->tcp_state ) &
00763                         ( TCP_SYN | TCP_FIN ) );
00764         if ( acked_flags )
00765                 len--;
00766 
00767         /* Update SEQ and sent counters, and window size */
00768         tcp->snd_seq = ack;
00769         tcp->snd_sent = 0;
00770         tcp->snd_win = win;
00771 
00772         /* Remove any acknowledged data from transmit queue */
00773         tcp_process_queue ( tcp, len, NULL, 1 );
00774                 
00775         /* Mark SYN/FIN as acknowledged if applicable. */
00776         if ( acked_flags )
00777                 tcp->tcp_state |= TCP_STATE_ACKED ( acked_flags );
00778 
00779         /* Start sending FIN if we've had all possible data ACKed */
00780         if ( list_empty ( &tcp->queue ) && tcp->xfer_closed )
00781                 tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
00782 
00783         return 0;
00784 }

static const char* tcp_state ( int  state  )  [inline, static]

Name TCP state.

Parameters:
state TCP state
Return values:
name Name of TCP state

Definition at line 107 of file tcp.c.

References TCP_CLOSE_WAIT, TCP_CLOSED, TCP_CLOSING_OR_LAST_ACK, TCP_ESTABLISHED, TCP_FIN_WAIT_1, TCP_FIN_WAIT_2, TCP_LISTEN, TCP_SYN_RCVD, TCP_SYN_SENT, and TCP_TIME_WAIT.

Referenced by tcp_dump_state(), and tcp_expired().

00107                         {
00108         switch ( state ) {
00109         case TCP_CLOSED:                return "CLOSED";
00110         case TCP_LISTEN:                return "LISTEN";
00111         case TCP_SYN_SENT:              return "SYN_SENT";
00112         case TCP_SYN_RCVD:              return "SYN_RCVD";
00113         case TCP_ESTABLISHED:           return "ESTABLISHED";
00114         case TCP_FIN_WAIT_1:            return "FIN_WAIT_1";
00115         case TCP_FIN_WAIT_2:            return "FIN_WAIT_2";
00116         case TCP_CLOSING_OR_LAST_ACK:   return "CLOSING/LAST_ACK";
00117         case TCP_TIME_WAIT:             return "TIME_WAIT";
00118         case TCP_CLOSE_WAIT:            return "CLOSE_WAIT";
00119         default:                        return "INVALID";
00120         }
00121 }

static void tcp_dump_state ( struct tcp_connection tcp  )  [inline, static]

Dump TCP state transition.

Parameters:
tcp TCP connection

Definition at line 129 of file tcp.c.

References DBGC, and tcp_state().

Referenced by tcp_close(), tcp_expired(), tcp_open(), tcp_rx(), and tcp_rx_rst().

00129                                               {
00130 
00131         if ( tcp->tcp_state != tcp->prev_tcp_state ) {
00132                 DBGC ( tcp, "TCP %p transitioned from %s to %s\n", tcp,
00133                        tcp_state ( tcp->prev_tcp_state ),
00134                        tcp_state ( tcp->tcp_state ) );
00135         }
00136         tcp->prev_tcp_state = tcp->tcp_state;
00137 }

static void tcp_dump_flags ( struct tcp_connection tcp,
unsigned int  flags 
) [inline, static]

Dump TCP flags.

Parameters:
flags TCP flags

Definition at line 145 of file tcp.c.

References DBGC2, TCP_ACK, TCP_FIN, TCP_PSH, TCP_RST, and TCP_SYN.

Referenced by tcp_rx(), tcp_xmit(), and tcp_xmit_reset().

00145                                                                   {
00146         if ( flags & TCP_RST )
00147                 DBGC2 ( tcp, " RST" );
00148         if ( flags & TCP_SYN )
00149                 DBGC2 ( tcp, " SYN" );
00150         if ( flags & TCP_PSH )
00151                 DBGC2 ( tcp, " PSH" );
00152         if ( flags & TCP_FIN )
00153                 DBGC2 ( tcp, " FIN" );
00154         if ( flags & TCP_ACK )
00155                 DBGC2 ( tcp, " ACK" );
00156 }

static int tcp_bind ( struct tcp_connection tcp,
unsigned int  port 
) [static]

Bind TCP connection to local port.

Parameters:
tcp TCP connection
port Local port number, in network-endian order
Return values:
rc Return status code
If the port is 0, the connection is assigned an available port between 1024 and 65535.

Definition at line 175 of file tcp.c.

References DBGC, EADDRINUSE, htons, tcp_connection::list, list_for_each_entry, tcp_connection::local_port, and ntohs.

Referenced by tcp_open().

00175                                                                       {
00176         struct tcp_connection *existing;
00177         static uint16_t try_port = 1023;
00178 
00179         /* If no port specified, find the first available port */
00180         if ( ! port ) {
00181                 while ( try_port ) {
00182                         try_port++;
00183                         if ( try_port < 1024 )
00184                                 continue;
00185                         if ( tcp_bind ( tcp, htons ( try_port ) ) == 0 )
00186                                 return 0;
00187                 }
00188                 DBGC ( tcp, "TCP %p could not bind: no free ports\n", tcp );
00189                 return -EADDRINUSE;
00190         }
00191 
00192         /* Attempt bind to local port */
00193         list_for_each_entry ( existing, &tcp_conns, list ) {
00194                 if ( existing->local_port == port ) {
00195                         DBGC ( tcp, "TCP %p could not bind: port %d in use\n",
00196                                tcp, ntohs ( port ) );
00197                         return -EADDRINUSE;
00198                 }
00199         }
00200         tcp->local_port = port;
00201 
00202         DBGC ( tcp, "TCP %p bound to port %d\n", tcp, ntohs ( port ) );
00203         return 0;
00204 }

static int tcp_open ( struct xfer_interface xfer,
struct sockaddr peer,
struct sockaddr local 
) [static]

Open a TCP connection.

Parameters:
xfer Data transfer interface
peer Peer socket address
local Local socket address, or NULL
Return values:
rc Return status code

Definition at line 214 of file tcp.c.

References DBGC, ENOMEM, retry_timer::expired, INIT_LIST_HEAD, tcp_connection::list, list_add, memcpy, tcp_connection::peer, tcp_connection::prev_tcp_state, tcp_connection::queue, random(), ref_put(), tcp_connection::refcnt, tcp_connection::snd_seq, sockaddr_tcpip::st_port, start_timer_nodelay(), tcp_bind(), TCP_CLOSED, tcp_dump_state(), tcp_expired(), tcp_connection::tcp_state, TCP_STATE_SENT, TCP_SYN, tcp_xfer_operations, tcp_connection::timer, tcp_connection::xfer, xfer_init(), and zalloc().

00215                                                {
00216         struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
00217         struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
00218         struct tcp_connection *tcp;
00219         unsigned int bind_port;
00220         int rc;
00221 
00222         /* Allocate and initialise structure */
00223         tcp = zalloc ( sizeof ( *tcp ) );
00224         if ( ! tcp )
00225                 return -ENOMEM;
00226         DBGC ( tcp, "TCP %p allocated\n", tcp );
00227         xfer_init ( &tcp->xfer, &tcp_xfer_operations, &tcp->refcnt );
00228         tcp->prev_tcp_state = TCP_CLOSED;
00229         tcp->tcp_state = TCP_STATE_SENT ( TCP_SYN );
00230         tcp_dump_state ( tcp );
00231         tcp->snd_seq = random();
00232         INIT_LIST_HEAD ( &tcp->queue );
00233         tcp->timer.expired = tcp_expired;
00234         memcpy ( &tcp->peer, st_peer, sizeof ( tcp->peer ) );
00235 
00236         /* Bind to local port */
00237         bind_port = ( st_local ? st_local->st_port : 0 );
00238         if ( ( rc = tcp_bind ( tcp, bind_port ) ) != 0 )
00239                 goto err;
00240 
00241         /* Start timer to initiate SYN */
00242         start_timer_nodelay ( &tcp->timer );
00243 
00244         /* Attach parent interface, transfer reference to connection
00245          * list and return
00246          */
00247         xfer_plug_plug ( &tcp->xfer, xfer );
00248         list_add ( &tcp->list, &tcp_conns );
00249         return 0;
00250 
00251  err:
00252         ref_put ( &tcp->refcnt );
00253         return rc;
00254 }

static void tcp_close ( struct tcp_connection tcp,
int  rc 
) [static]

Close TCP connection.

Parameters:
tcp TCP connection
rc Reason for close
Closes the data transfer interface. If the TCP state machine is in a suitable state, the connection will be deleted.

Definition at line 265 of file tcp.c.

References DBGC, free_iob(), tcp_connection::list, io_buffer::list, list_del, list_empty(), list_for_each_entry_safe, tcp_connection::queue, ref_put(), tcp_connection::refcnt, tcp_connection::snd_seq, stop_timer(), TCP_CLOSED, tcp_dump_state(), TCP_FIN, tcp_rx_ack(), tcp_connection::tcp_state, TCP_STATE_ACKED, TCP_STATE_RCVD, TCP_STATE_SENT, TCP_SYN, tcp_connection::timer, tcp_connection::xfer, xfer_close(), and tcp_connection::xfer_closed.

Referenced by tcp_expired(), tcp_rx_fin(), tcp_rx_rst(), and tcp_xfer_close().

00265                                                              {
00266         struct io_buffer *iobuf;
00267         struct io_buffer *tmp;
00268 
00269         /* Close data transfer interface */
00270         xfer_nullify ( &tcp->xfer );
00271         xfer_close ( &tcp->xfer, rc );
00272         tcp->xfer_closed = 1;
00273 
00274         /* If we are in CLOSED, or have otherwise not yet received a
00275          * SYN (i.e. we are in LISTEN or SYN_SENT), just delete the
00276          * connection.
00277          */
00278         if ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) {
00279 
00280                 /* Transition to CLOSED for the sake of debugging messages */
00281                 tcp->tcp_state = TCP_CLOSED;
00282                 tcp_dump_state ( tcp );
00283 
00284                 /* Free any unsent I/O buffers */
00285                 list_for_each_entry_safe ( iobuf, tmp, &tcp->queue, list ) {
00286                         list_del ( &iobuf->list );
00287                         free_iob ( iobuf );
00288                 }
00289 
00290                 /* Remove from list and drop reference */
00291                 stop_timer ( &tcp->timer );
00292                 list_del ( &tcp->list );
00293                 ref_put ( &tcp->refcnt );
00294                 DBGC ( tcp, "TCP %p connection deleted\n", tcp );
00295                 return;
00296         }
00297 
00298         /* If we have not had our SYN acknowledged (i.e. we are in
00299          * SYN_RCVD), pretend that it has been acknowledged so that we
00300          * can send a FIN without breaking things.
00301          */
00302         if ( ! ( tcp->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) )
00303                 tcp_rx_ack ( tcp, ( tcp->snd_seq + 1 ), 0 );
00304 
00305         /* If we have no data remaining to send, start sending FIN */
00306         if ( list_empty ( &tcp->queue ) ) {
00307                 tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
00308                 tcp_dump_state ( tcp );
00309         }
00310 }

static size_t tcp_xmit_win ( struct tcp_connection tcp  )  [static]

Calculate transmission window.

Parameters:
tcp TCP connection
Return values:
len Maximum length that can be sent in a single packet

Definition at line 325 of file tcp.c.

References tcp_connection::snd_win, TCP_CAN_SEND_DATA, TCP_PATH_MTU, and tcp_connection::tcp_state.

Referenced by tcp_xfer_window(), and tcp_xmit().

00325                                                           {
00326         size_t len;
00327 
00328         /* Not ready if we're not in a suitable connection state */
00329         if ( ! TCP_CAN_SEND_DATA ( tcp->tcp_state ) )
00330                 return 0;
00331 
00332         /* Length is the minimum of the receiver's window and the path MTU */
00333         len = tcp->snd_win;
00334         if ( len > TCP_PATH_MTU )
00335                 len = TCP_PATH_MTU;
00336 
00337         return len;
00338 }

static size_t tcp_process_queue ( struct tcp_connection tcp,
size_t  max_len,
struct io_buffer dest,
int  remove 
) [static]

Process TCP transmit queue.

Parameters:
tcp TCP connection
max_len Maximum length to process
dest I/O buffer to fill with data, or NULL
remove Remove data from queue
Return values:
len Length of data processed
This processes at most max_len bytes from the TCP connection's transmit queue. Data will be copied into the dest I/O buffer (if provided) and, if remove is true, removed from the transmit queue.

Definition at line 354 of file tcp.c.

References io_buffer::data, free_iob(), iob_len(), iob_pull, iob_put, io_buffer::list, list_del, list_for_each_entry_safe, memcpy, and tcp_connection::queue.

Referenced by tcp_rx_ack(), and tcp_xmit().

00355                                                                        {
00356         struct io_buffer *iobuf;
00357         struct io_buffer *tmp;
00358         size_t frag_len;
00359         size_t len = 0;
00360 
00361         list_for_each_entry_safe ( iobuf, tmp, &tcp->queue, list ) {
00362                 frag_len = iob_len ( iobuf );
00363                 if ( frag_len > max_len )
00364                         frag_len = max_len;
00365                 if ( dest ) {
00366                         memcpy ( iob_put ( dest, frag_len ), iobuf->data,
00367                                  frag_len );
00368                 }
00369                 if ( remove ) {
00370                         iob_pull ( iobuf, frag_len );
00371                         if ( ! iob_len ( iobuf ) ) {
00372                                 list_del ( &iobuf->list );
00373                                 free_iob ( iobuf );
00374                         }
00375                 }
00376                 len += frag_len;
00377                 max_len -= frag_len;
00378         }
00379         return len;
00380 }

static int tcp_xmit ( struct tcp_connection tcp,
int  force_send 
) [static]

Transmit any outstanding data.

Parameters:
tcp TCP connection
force_send Force sending of packet
Transmits any outstanding data on the connection.

Note that even if an error is returned, the retransmission timer will have been started if necessary, and so the stack will eventually attempt to retransmit the failed packet.

Definition at line 394 of file tcp.c.

References tcp_header::ack, alloc_iob(), assert, tcp_header::csum, currticks(), io_buffer::data, DBGC, DBGC2, tcp_header::dest, ENOMEM, tcp_header::flags, freemem, tcp_header::hlen, htonl, htons, iob_len(), iob_push, iob_reserve, tcp_timestamp_option::kind, tcp_mss_option::kind, tcp_timestamp_option::length, tcp_mss_option::length, tcp_connection::local_port, MAX_HDR_LEN, memset(), tcp_mss_option::mss, tcp_timestamp_padded_option::nop, ntohl, ntohs, NULL, tcp_connection::peer, tcp_connection::rcv_ack, tcp_connection::rcv_win, tcp_header::seq, tcp_connection::snd_sent, tcp_connection::snd_seq, tcp_header::src, sockaddr_tcpip::st_port, start_timer(), strerror(), TCP_CAN_SEND_DATA, tcp_dump_flags(), TCP_FIN, TCP_FLAGS_SENDING, TCP_MAX_WINDOW_SIZE, TCP_MSS, TCP_OPTION_MSS, TCP_OPTION_NOP, TCP_OPTION_TS, tcp_process_queue(), tcp_protocol, TCP_PSH, tcp_connection::tcp_state, TCP_SYN, tcp_xmit_win(), tcpip_chksum(), tcpip_tx(), tcp_connection::timer, tcp_connection::timestamps, tcp_connection::ts_recent, tcp_timestamp_option::tsecr, tcp_timestamp_padded_option::tsopt, tcp_timestamp_option::tsval, tcp_header::win, tcp_connection::xfer, and xfer_window().

Referenced by tcp_expired(), tcp_rx(), tcp_xfer_close(), and tcp_xfer_deliver_iob().

00394                                                                    {
00395         struct io_buffer *iobuf;
00396         struct tcp_header *tcphdr;
00397         struct tcp_mss_option *mssopt;
00398         struct tcp_timestamp_padded_option *tsopt;
00399         void *payload;
00400         unsigned int flags;
00401         size_t len = 0;
00402         uint32_t seq_len;
00403         uint32_t app_win;
00404         uint32_t max_rcv_win;
00405         int rc;
00406 
00407         /* If retransmission timer is already running, do nothing */
00408         if ( timer_running ( &tcp->timer ) )
00409                 return 0;
00410 
00411         /* Calculate both the actual (payload) and sequence space
00412          * lengths that we wish to transmit.
00413          */
00414         if ( TCP_CAN_SEND_DATA ( tcp->tcp_state ) ) {
00415                 len = tcp_process_queue ( tcp, tcp_xmit_win ( tcp ),
00416                                           NULL, 0 );
00417         }
00418         seq_len = len;
00419         flags = TCP_FLAGS_SENDING ( tcp->tcp_state );
00420         if ( flags & ( TCP_SYN | TCP_FIN ) ) {
00421                 /* SYN or FIN consume one byte, and we can never send both */
00422                 assert ( ! ( ( flags & TCP_SYN ) && ( flags & TCP_FIN ) ) );
00423                 seq_len++;
00424         }
00425         tcp->snd_sent = seq_len;
00426 
00427         /* If we have nothing to transmit, stop now */
00428         if ( ( seq_len == 0 ) && ! force_send )
00429                 return 0;
00430 
00431         /* If we are transmitting anything that requires
00432          * acknowledgement (i.e. consumes sequence space), start the
00433          * retransmission timer.  Do this before attempting to
00434          * allocate the I/O buffer, in case allocation itself fails.
00435          */
00436         if ( seq_len )
00437                 start_timer ( &tcp->timer );
00438 
00439         /* Allocate I/O buffer */
00440         iobuf = alloc_iob ( len + MAX_HDR_LEN );
00441         if ( ! iobuf ) {
00442                 DBGC ( tcp, "TCP %p could not allocate iobuf for %08x..%08x "
00443                        "%08x\n", tcp, tcp->snd_seq, ( tcp->snd_seq + seq_len ),
00444                        tcp->rcv_ack );
00445                 return -ENOMEM;
00446         }
00447         iob_reserve ( iobuf, MAX_HDR_LEN );
00448 
00449         /* Fill data payload from transmit queue */
00450         tcp_process_queue ( tcp, len, iobuf, 0 );
00451 
00452         /* Expand receive window if possible */
00453         max_rcv_win = ( ( freemem * 3 ) / 4 );
00454         if ( max_rcv_win > TCP_MAX_WINDOW_SIZE )
00455                 max_rcv_win = TCP_MAX_WINDOW_SIZE;
00456         app_win = xfer_window ( &tcp->xfer );
00457         if ( max_rcv_win > app_win )
00458                 max_rcv_win = app_win;
00459         max_rcv_win &= ~0x03; /* Keep everything dword-aligned */
00460         if ( tcp->rcv_win < max_rcv_win )
00461                 tcp->rcv_win = max_rcv_win;
00462 
00463         /* Fill up the TCP header */
00464         payload = iobuf->data;
00465         if ( flags & TCP_SYN ) {
00466                 mssopt = iob_push ( iobuf, sizeof ( *mssopt ) );
00467                 mssopt->kind = TCP_OPTION_MSS;
00468                 mssopt->length = sizeof ( *mssopt );
00469                 mssopt->mss = htons ( TCP_MSS );
00470         }
00471         if ( ( flags & TCP_SYN ) || tcp->timestamps ) {
00472                 tsopt = iob_push ( iobuf, sizeof ( *tsopt ) );
00473                 memset ( tsopt->nop, TCP_OPTION_NOP, sizeof ( tsopt->nop ) );
00474                 tsopt->tsopt.kind = TCP_OPTION_TS;
00475                 tsopt->tsopt.length = sizeof ( tsopt->tsopt );
00476                 tsopt->tsopt.tsval = ntohl ( currticks() );
00477                 tsopt->tsopt.tsecr = ntohl ( tcp->ts_recent );
00478         }
00479         if ( ! ( flags & TCP_SYN ) )
00480                 flags |= TCP_PSH;
00481         tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) );
00482         memset ( tcphdr, 0, sizeof ( *tcphdr ) );
00483         tcphdr->src = tcp->local_port;
00484         tcphdr->dest = tcp->peer.st_port;
00485         tcphdr->seq = htonl ( tcp->snd_seq );
00486         tcphdr->ack = htonl ( tcp->rcv_ack );
00487         tcphdr->hlen = ( ( payload - iobuf->data ) << 2 );
00488         tcphdr->flags = flags;
00489         tcphdr->win = htons ( tcp->rcv_win );
00490         tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) );
00491 
00492         /* Dump header */
00493         DBGC2 ( tcp, "TCP %p TX %d->%d %08x..%08x           %08x %4zd",
00494                 tcp, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ),
00495                 ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) + seq_len ),
00496                 ntohl ( tcphdr->ack ), len );
00497         tcp_dump_flags ( tcp, tcphdr->flags );
00498         DBGC2 ( tcp, "\n" );
00499 
00500         /* Transmit packet */
00501         if ( ( rc = tcpip_tx ( iobuf, &tcp_protocol, NULL, &tcp->peer, NULL,
00502                                &tcphdr->csum ) ) != 0 ) {
00503                 DBGC ( tcp, "TCP %p could not transmit %08x..%08x %08x: %s\n",
00504                        tcp, tcp->snd_seq, ( tcp->snd_seq + tcp->snd_sent ),
00505                        tcp->rcv_ack, strerror ( rc ) );
00506                 return rc;
00507         }
00508 
00509         return 0;
00510 }

static int tcp_xmit_reset ( struct tcp_connection tcp,
struct sockaddr_tcpip st_dest,
struct tcp_header in_tcphdr 
) [static]

Send RST response to incoming packet.

Parameters:
in_tcphdr TCP header of incoming packet
Return values:
rc Return status code

Definition at line 555 of file tcp.c.

References tcp_header::ack, alloc_iob(), tcp_header::csum, io_buffer::data, DBGC, DBGC2, tcp_header::dest, ENOMEM, tcp_header::flags, tcp_header::hlen, htons, iob_len(), iob_push, iob_reserve, MAX_HDR_LEN, memset(), ntohl, ntohs, NULL, tcp_header::seq, tcp_header::src, strerror(), TCP_ACK, tcp_dump_flags(), TCP_MAX_WINDOW_SIZE, tcp_protocol, TCP_RST, tcpip_chksum(), tcpip_tx(), and tcp_header::win.

Referenced by tcp_rx().

00557                                                            {
00558         struct io_buffer *iobuf;
00559         struct tcp_header *tcphdr;
00560         int rc;
00561 
00562         /* Allocate space for dataless TX buffer */
00563         iobuf = alloc_iob ( MAX_HDR_LEN );
00564         if ( ! iobuf ) {
00565                 DBGC ( tcp, "TCP %p could not allocate iobuf for RST "
00566                        "%08x..%08x %08x\n", tcp, ntohl ( in_tcphdr->ack ),
00567                        ntohl ( in_tcphdr->ack ), ntohl ( in_tcphdr->seq ) );
00568                 return -ENOMEM;
00569         }
00570         iob_reserve ( iobuf, MAX_HDR_LEN );
00571 
00572         /* Construct RST response */
00573         tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) );
00574         memset ( tcphdr, 0, sizeof ( *tcphdr ) );
00575         tcphdr->src = in_tcphdr->dest;
00576         tcphdr->dest = in_tcphdr->src;
00577         tcphdr->seq = in_tcphdr->ack;
00578         tcphdr->ack = in_tcphdr->seq;
00579         tcphdr->hlen = ( ( sizeof ( *tcphdr ) / 4 ) << 4 );
00580         tcphdr->flags = ( TCP_RST | TCP_ACK );
00581         tcphdr->win = htons ( TCP_MAX_WINDOW_SIZE );
00582         tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) );
00583 
00584         /* Dump header */
00585         DBGC2 ( tcp, "TCP %p TX %d->%d %08x..%08x           %08x %4d",
00586                 tcp, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ),
00587                 ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) ),
00588                 ntohl ( tcphdr->ack ), 0 );
00589         tcp_dump_flags ( tcp, tcphdr->flags );
00590         DBGC2 ( tcp, "\n" );
00591 
00592         /* Transmit packet */
00593         if ( ( rc = tcpip_tx ( iobuf, &tcp_protocol, NULL, st_dest,
00594                                NULL, &tcphdr->csum ) ) != 0 ) {
00595                 DBGC ( tcp, "TCP %p could not transmit RST %08x..%08x %08x: "
00596                        "%s\n", tcp, ntohl ( in_tcphdr->ack ),
00597                        ntohl ( in_tcphdr->ack ), ntohl ( in_tcphdr->seq ),
00598                        strerror ( rc ) );
00599                 return rc;
00600         }
00601 
00602         return 0;
00603 }

static struct tcp_connection* tcp_demux ( unsigned int  local_port  )  [static, read]

Identify TCP connection by local port number.

Parameters:
local_port Local port (in network-endian order)
Return values:
tcp TCP connection, or NULL

Definition at line 618 of file tcp.c.

References tcp_connection::list, list_for_each_entry, tcp_connection::local_port, and NULL.

Referenced by tcp_rx().

00618                                                                      {
00619         struct tcp_connection *tcp;
00620 
00621         list_for_each_entry ( tcp, &tcp_conns, list ) {
00622                 if ( tcp->local_port == local_port )
00623                         return tcp;
00624         }
00625         return NULL;
00626 }

static void tcp_rx_opts ( struct tcp_connection tcp,
const void *  data,
size_t  len,
struct tcp_options options 
) [static]

Parse TCP received options.

Parameters:
tcp TCP connection
data Raw options data
len Raw options length
options Options structure to fill in

Definition at line 636 of file tcp.c.

References DBGC, tcp_option::kind, tcp_option::length, memset(), tcp_options::mssopt, TCP_OPTION_END, TCP_OPTION_MSS, TCP_OPTION_NOP, TCP_OPTION_TS, and tcp_options::tsopt.

Referenced by tcp_rx().

00637                                                                     {
00638         const void *end = ( data + len );
00639         const struct tcp_option *option;
00640         unsigned int kind;
00641 
00642         memset ( options, 0, sizeof ( *options ) );
00643         while ( data < end ) {
00644                 option = data;
00645                 kind = option->kind;
00646                 if ( kind == TCP_OPTION_END )
00647                         return;
00648                 if ( kind == TCP_OPTION_NOP ) {
00649                         data++;
00650                         continue;
00651                 }
00652                 switch ( kind ) {
00653                 case TCP_OPTION_MSS:
00654                         options->mssopt = data;
00655                         break;
00656                 case TCP_OPTION_TS:
00657                         options->tsopt = data;
00658                         break;
00659                 default:
00660                         DBGC ( tcp, "TCP %p received unknown option %d\n",
00661                                tcp, kind );
00662                         break;
00663                 }
00664                 data += option->length;
00665         }
00666 }

static void tcp_rx_seq ( struct tcp_connection tcp,
uint32_t  seq_len 
) [static]

Consume received sequence space.

Parameters:
tcp TCP connection
seq_len Sequence space length to consume

Definition at line 674 of file tcp.c.

References tcp_connection::rcv_ack, and tcp_connection::rcv_win.

Referenced by tcp_rx_data(), tcp_rx_fin(), and tcp_rx_syn().

00674                                                                         {
00675         tcp->rcv_ack += seq_len;
00676         if ( tcp->rcv_win > seq_len ) {
00677                 tcp->rcv_win -= seq_len;
00678         } else {
00679                 tcp->rcv_win = 0;
00680         }
00681 }

static int tcp_rx_syn ( struct tcp_connection tcp,
uint32_t  seq,
struct tcp_options options 
) [static]

Handle TCP received SYN.

Parameters:
tcp TCP connection
seq SEQ value (in host-endian order)
options TCP options
Return values:
rc Return status code

Definition at line 691 of file tcp.c.

References tcp_connection::rcv_ack, TCP_ACK, tcp_rx_seq(), tcp_connection::tcp_state, TCP_STATE_RCVD, TCP_STATE_SENT, TCP_SYN, tcp_connection::timestamps, and tcp_options::tsopt.

Referenced by tcp_rx().

00692                                                       {
00693 
00694         /* Synchronise sequence numbers on first SYN */
00695         if ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) {
00696                 tcp->rcv_ack = seq;
00697                 if ( options->tsopt )
00698                         tcp->timestamps = 1;
00699         }
00700 
00701         /* Ignore duplicate SYN */
00702         if ( ( tcp->rcv_ack - seq ) > 0 )
00703                 return 0;
00704 
00705         /* Mark SYN as received and start sending ACKs with each packet */
00706         tcp->tcp_state |= ( TCP_STATE_SENT ( TCP_ACK ) |
00707                             TCP_STATE_RCVD ( TCP_SYN ) );
00708 
00709         /* Acknowledge SYN */
00710         tcp_rx_seq ( tcp, 1 );
00711 
00712         return 0;
00713 }

static int tcp_rx_data ( struct tcp_connection tcp,
uint32_t  seq,
struct io_buffer iobuf 
) [static]

Handle TCP received data.

Parameters:
tcp TCP connection
seq SEQ value (in host-endian order)
iobuf I/O buffer
Return values:
rc Return status code
This function takes ownership of the I/O buffer.

Definition at line 796 of file tcp.c.

References DBGC, free_iob(), iob_len(), iob_pull, tcp_connection::rcv_ack, strerror(), tcp_rx_seq(), tcp_connection::xfer, and xfer_deliver_iob().

Referenced by tcp_rx().

00797                                                    {
00798         uint32_t already_rcvd;
00799         uint32_t len;
00800         int rc;
00801 
00802         /* Ignore duplicate or out-of-order data */
00803         already_rcvd = ( tcp->rcv_ack - seq );
00804         len = iob_len ( iobuf );
00805         if ( already_rcvd >= len ) {
00806                 free_iob ( iobuf );
00807                 return 0;
00808         }
00809         iob_pull ( iobuf, already_rcvd );
00810         len -= already_rcvd;
00811 
00812         /* Deliver data to application */
00813         if ( ( rc = xfer_deliver_iob ( &tcp->xfer, iobuf ) ) != 0 ) {
00814                 DBGC ( tcp, "TCP %p could not deliver %08x..%08x: %s\n",
00815                        tcp, seq, ( seq + len ), strerror ( rc ) );
00816                 return rc;
00817         }
00818 
00819         /* Acknowledge new data */
00820         tcp_rx_seq ( tcp, len );
00821 
00822         return 0;
00823 }

static int tcp_rx_fin ( struct tcp_connection tcp,
uint32_t  seq 
) [static]

Handle TCP received FIN.

Parameters:
tcp TCP connection
seq SEQ value (in host-endian order)
Return values:
rc Return status code

Definition at line 832 of file tcp.c.

References tcp_connection::rcv_ack, tcp_close(), TCP_FIN, tcp_rx_seq(), tcp_connection::tcp_state, and TCP_STATE_RCVD.

Referenced by tcp_rx().

00832                                                                    {
00833 
00834         /* Ignore duplicate or out-of-order FIN */
00835         if ( ( tcp->rcv_ack - seq ) > 0 )
00836                 return 0;
00837 
00838         /* Mark FIN as received and acknowledge it */
00839         tcp->tcp_state |= TCP_STATE_RCVD ( TCP_FIN );
00840         tcp_rx_seq ( tcp, 1 );
00841 
00842         /* Close connection */
00843         tcp_close ( tcp, 0 );
00844 
00845         return 0;
00846 }

static int tcp_rx_rst ( struct tcp_connection tcp,
uint32_t  seq 
) [static]

Handle TCP received RST.

Parameters:
tcp TCP connection
seq SEQ value (in host-endian order)
Return values:
rc Return status code

Definition at line 855 of file tcp.c.

References DBGC, ECONNRESET, tcp_connection::rcv_ack, tcp_connection::rcv_win, tcp_close(), TCP_CLOSED, tcp_dump_state(), tcp_connection::tcp_state, TCP_STATE_ACKED, TCP_STATE_RCVD, and TCP_SYN.

Referenced by tcp_rx().

00855                                                                    {
00856 
00857         /* Accept RST only if it falls within the window.  If we have
00858          * not yet received a SYN, then we have no window to test
00859          * against, so fall back to checking that our SYN has been
00860          * ACKed.
00861          */
00862         if ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) {
00863                 if ( ( seq - tcp->rcv_ack ) >= tcp->rcv_win )
00864                         return 0;
00865         } else {
00866                 if ( ! ( tcp->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) )
00867                         return 0;
00868         }
00869 
00870         /* Abort connection */
00871         tcp->tcp_state = TCP_CLOSED;
00872         tcp_dump_state ( tcp );
00873         tcp_close ( tcp, -ECONNRESET );
00874 
00875         DBGC ( tcp, "TCP %p connection reset by peer\n", tcp );
00876         return -ECONNRESET;
00877 }

static int tcp_rx ( struct io_buffer iobuf,
struct sockaddr_tcpip st_src,
struct sockaddr_tcpip *st_dest  __unused,
uint16_t  pshdr_csum 
) [static]

Process received packet.

Parameters:
iobuf I/O buffer
st_src Partially-filled source address
st_dest Partially-filled destination address
pshdr_csum Pseudo-header checksum
Return values:
rc Return status code

Definition at line 888 of file tcp.c.

References tcp_header::ack, io_buffer::data, DBG, DBGC2, tcp_header::dest, EINVAL, ENOTCONN, tcp_header::flags, free_iob(), tcp_header::hlen, iob_len(), iob_pull, ntohl, ntohs, tcp_connection::rcv_ack, tcp_connection::rcv_win, tcp_header::seq, start_timer(), TCP_ACK, TCP_CLOSED_GRACEFULLY, tcp_demux(), tcp_dump_flags(), tcp_dump_state(), TCP_FIN, TCP_MASK_HLEN, TCP_MSL, TCP_RST, tcp_rx_ack(), tcp_rx_data(), tcp_rx_fin(), tcp_rx_opts(), tcp_rx_rst(), tcp_rx_syn(), tcp_connection::tcp_state, TCP_SYN, tcp_xmit(), tcp_xmit_reset(), tcpip_continue_chksum(), retry_timer::timeout, tcp_connection::timer, tcp_connection::ts_recent, tcp_options::tsopt, tcp_timestamp_option::tsval, and tcp_header::win.

00891                                           {
00892         struct tcp_header *tcphdr = iobuf->data;
00893         struct tcp_connection *tcp;
00894         struct tcp_options options;
00895         size_t hlen;
00896         uint16_t csum;
00897         uint32_t start_seq;
00898         uint32_t seq;
00899         uint32_t ack;
00900         uint32_t win;
00901         unsigned int flags;
00902         size_t len;
00903         int rc;
00904 
00905         /* Sanity check packet */
00906         if ( iob_len ( iobuf ) < sizeof ( *tcphdr ) ) {
00907                 DBG ( "TCP packet too short at %zd bytes (min %zd bytes)\n",
00908                       iob_len ( iobuf ), sizeof ( *tcphdr ) );
00909                 rc = -EINVAL;
00910                 goto discard;
00911         }
00912         hlen = ( ( tcphdr->hlen & TCP_MASK_HLEN ) / 16 ) * 4;
00913         if ( hlen < sizeof ( *tcphdr ) ) {
00914                 DBG ( "TCP header too short at %zd bytes (min %zd bytes)\n",
00915                       hlen, sizeof ( *tcphdr ) );
00916                 rc = -EINVAL;
00917                 goto discard;
00918         }
00919         if ( hlen > iob_len ( iobuf ) ) {
00920                 DBG ( "TCP header too long at %zd bytes (max %zd bytes)\n",
00921                       hlen, iob_len ( iobuf ) );
00922                 rc = -EINVAL;
00923                 goto discard;
00924         }
00925         csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data,
00926                                        iob_len ( iobuf ) );
00927         if ( csum != 0 ) {
00928                 DBG ( "TCP checksum incorrect (is %04x including checksum "
00929                       "field, should be 0000)\n", csum );
00930                 rc = -EINVAL;
00931                 goto discard;
00932         }
00933         
00934         /* Parse parameters from header and strip header */
00935         tcp = tcp_demux ( tcphdr->dest );
00936         start_seq = seq = ntohl ( tcphdr->seq );
00937         ack = ntohl ( tcphdr->ack );
00938         win = ntohs ( tcphdr->win );
00939         flags = tcphdr->flags;
00940         tcp_rx_opts ( tcp, ( ( ( void * ) tcphdr ) + sizeof ( *tcphdr ) ),
00941                       ( hlen - sizeof ( *tcphdr ) ), &options );
00942         iob_pull ( iobuf, hlen );
00943         len = iob_len ( iobuf );
00944 
00945         /* Dump header */
00946         DBGC2 ( tcp, "TCP %p RX %d<-%d           %08x %08x..%08zx %4zd",
00947                 tcp, ntohs ( tcphdr->dest ), ntohs ( tcphdr->src ),
00948                 ntohl ( tcphdr->ack ), ntohl ( tcphdr->seq ),
00949                 ( ntohl ( tcphdr->seq ) + len +
00950                   ( ( tcphdr->flags & ( TCP_SYN | TCP_FIN ) ) ? 1 : 0 )), len);
00951         tcp_dump_flags ( tcp, tcphdr->flags );
00952         DBGC2 ( tcp, "\n" );
00953 
00954         /* If no connection was found, send RST */
00955         if ( ! tcp ) {
00956                 tcp_xmit_reset ( tcp, st_src, tcphdr );
00957                 rc = -ENOTCONN;
00958                 goto discard;
00959         }
00960 
00961         /* Handle ACK, if present */
00962         if ( flags & TCP_ACK ) {
00963                 if ( ( rc = tcp_rx_ack ( tcp, ack, win ) ) != 0 ) {
00964                         tcp_xmit_reset ( tcp, st_src, tcphdr );
00965                         goto discard;
00966                 }
00967         }
00968 
00969         /* Handle SYN, if present */
00970         if ( flags & TCP_SYN ) {
00971                 tcp_rx_syn ( tcp, seq, &options );
00972                 seq++;
00973         }
00974 
00975         /* Handle RST, if present */
00976         if ( flags & TCP_RST ) {
00977                 if ( ( rc = tcp_rx_rst ( tcp, seq ) ) != 0 )
00978                         goto discard;
00979         }
00980 
00981         /* Handle new data, if any */
00982         tcp_rx_data ( tcp, seq, iobuf );
00983         seq += len;
00984 
00985         /* Handle FIN, if present */
00986         if ( flags & TCP_FIN ) {
00987                 tcp_rx_fin ( tcp, seq );
00988                 seq++;
00989         }
00990 
00991         /* Update timestamp, if present and applicable */
00992         if ( ( seq == tcp->rcv_ack ) && options.tsopt )
00993                 tcp->ts_recent = ntohl ( options.tsopt->tsval );
00994 
00995         /* Dump out any state change as a result of the received packet */
00996         tcp_dump_state ( tcp );
00997 
00998         /* Send out any pending data.  We force sending a reply if either
00999          *
01000          *  a) the peer is expecting an ACK (i.e. consumed sequence space), or
01001          *  b) either end of the packet was outside the receive window
01002          *
01003          * Case (b) enables us to support TCP keepalives using
01004          * zero-length packets, which we would otherwise ignore.  Note
01005          * that for case (b), we need *only* consider zero-length
01006          * packets, since non-zero-length packets will already be
01007          * caught by case (a).
01008          */
01009         tcp_xmit ( tcp, ( ( start_seq != seq ) ||
01010                           ( ( seq - tcp->rcv_ack ) > tcp->rcv_win ) ) );
01011 
01012         /* If this packet was the last we expect to receive, set up
01013          * timer to expire and cause the connection to be freed.
01014          */
01015         if ( TCP_CLOSED_GRACEFULLY ( tcp->tcp_state ) ) {
01016                 tcp->timer.timeout = ( 2 * TCP_MSL );
01017                 start_timer ( &tcp->timer );
01018         }
01019 
01020         return 0;
01021 
01022  discard:
01023         /* Free received packet */
01024         free_iob ( iobuf );
01025         return rc;
01026 }

static void tcp_xfer_close ( struct xfer_interface xfer,
int  rc 
) [static]

Close interface.

Parameters:
xfer Data transfer interface
rc Reason for close

Definition at line 1048 of file tcp.c.

References container_of, tcp_close(), and tcp_xmit().

01048                                                                    {
01049         struct tcp_connection *tcp =
01050                 container_of ( xfer, struct tcp_connection, xfer );
01051 
01052         /* Close data transfer interface */
01053         tcp_close ( tcp, rc );
01054 
01055         /* Transmit FIN, if possible */
01056         tcp_xmit ( tcp, 0 );
01057 }

static size_t tcp_xfer_window ( struct xfer_interface xfer  )  [static]

Check flow control window.

Parameters:
xfer Data transfer interface
Return values:
len Length of window

Definition at line 1065 of file tcp.c.

References container_of, list_empty(), tcp_connection::queue, and tcp_xmit_win().

01065                                                               {
01066         struct tcp_connection *tcp =
01067                 container_of ( xfer, struct tcp_connection, xfer );
01068 
01069         /* Not ready if data queue is non-empty.  This imposes a limit
01070          * of only one unACKed packet in the TX queue at any time; we
01071          * do this to conserve memory usage.
01072          */
01073         if ( ! list_empty ( &tcp->queue ) )
01074                 return 0;
01075 
01076         /* Return TCP window length */
01077         return tcp_xmit_win ( tcp );
01078 }

static int tcp_xfer_deliver_iob ( struct xfer_interface xfer,
struct io_buffer iobuf,
struct xfer_metadata *meta  __unused 
) [static]

Deliver datagram as I/O buffer.

Parameters:
xfer Data transfer interface
iobuf Datagram I/O buffer
meta Data transfer metadata
Return values:
rc Return status code

Definition at line 1088 of file tcp.c.

References container_of, io_buffer::list, list_add_tail, tcp_connection::queue, and tcp_xmit().

01090                                                                         {
01091         struct tcp_connection *tcp =
01092                 container_of ( xfer, struct tcp_connection, xfer );
01093 
01094         /* Enqueue packet */
01095         list_add_tail ( &iobuf->list, &tcp->queue );
01096 
01097         /* Transmit data, if possible */
01098         tcp_xmit ( tcp, 0 );
01099 
01100         return 0;
01101 }

static int tcp_open_uri ( struct xfer_interface xfer,
struct uri uri 
) [static]

Open TCP URI.

Parameters:
xfer Data transfer interface
uri URI
Return values:
rc Return status code

Definition at line 1137 of file tcp.c.

References EINVAL, uri::host, htons, memset(), NULL, SOCK_STREAM, sockaddr_tcpip::st_port, uri_port(), and xfer_open_named_socket().

01137                                                                          {
01138         struct sockaddr_tcpip peer;
01139 
01140         /* Sanity check */
01141         if ( ! uri->host )
01142                 return -EINVAL;
01143 
01144         memset ( &peer, 0, sizeof ( peer ) );
01145         peer.st_port = htons ( uri_port ( uri, 0 ) );
01146         return xfer_open_named_socket ( xfer, SOCK_STREAM,
01147                                         ( struct sockaddr * ) &peer,
01148                                         uri->host, NULL );
01149 }


Variable Documentation

static struct xfer_interface_operations tcp_xfer_operations [static, read]

Initial value:

 {
        .close          = tcp_xfer_close,
        .vredirect      = ignore_xfer_vredirect,
        .window         = tcp_xfer_window,
        .alloc_iob      = default_xfer_alloc_iob,
        .deliver_iob    = tcp_xfer_deliver_iob,
        .deliver_raw    = xfer_deliver_as_iob,
}
TCP data transfer interface operations.

Definition at line 95 of file tcp.c.

Referenced by tcp_open().

Initial value:

 {
        .name = "TCP",
        .rx = tcp_rx,
        .tcpip_proto = IP_TCP,
}
TCP protocol.

Definition at line 1029 of file tcp.c.

struct socket_opener tcp_socket_opener __socket_opener

Initial value:

 {
        .semantics      = TCP_SOCK_STREAM,
        .family         = AF_INET,
        .open           = tcp_open,
}
TCP socket opener.

Definition at line 1121 of file tcp.c.

struct uri_opener tcp_uri_opener __uri_opener

Initial value:

 {
        .scheme         = "tcp",
        .open           = tcp_open_uri,
}
TCP URI opener.

Definition at line 1152 of file tcp.c.


Generated on Tue Apr 6 20:01:56 2010 for gPXE by  doxygen 1.5.7.1