It's a little tricky about already_rcvd
(uint32_t
).
if tcp→rcv_ack
==
seq
: Normal case
already_rcvd
= 0
if tcp→rcv_ack
>
seq
: Segment contains previous data
already_rcvd
= small positive number
if tcp→rcv_ack
<
seq
: Out-Of-Order future data
already_rcvd
= VERY LARGE positive numberif ( already_rcvd >= len ) {
Acctually have two meanings:
/** * Handle TCP received data * * @v tcp TCP connection * @v seq SEQ value (in host-endian order) * @v iobuf I/O buffer * @ret rc Return status code * * This function takes ownership of the I/O buffer. */ static int tcp_rx_data ( struct tcp_connection *tcp, uint32_t seq, struct io_buffer *iobuf ) { uint32_t already_rcvd; uint32_t len; int rc; /* Ignore duplicate or out-of-order data */ already_rcvd = ( tcp->rcv_ack - seq ); len = iob_len ( iobuf ); if ( already_rcvd >= len ) { free_iob ( iobuf ); return 0; } iob_pull ( iobuf, already_rcvd ); len -= already_rcvd; /* Deliver data to application */ if ( ( rc = xfer_deliver_iob ( &tcp->xfer, iobuf ) ) != 0 ) { DBGC ( tcp, "TCP %p could not deliver %08x..%08x: %s\n", tcp, seq, ( seq + len ), strerror ( rc ) ); return rc; } /* Acknowledge new data */ tcp_rx_seq ( tcp, len ); return 0; }