[tcp] Update received sequence number before delivering received data

iPXE currently updates the TCP sequence number after delivering the
data to the application via xfer_deliver_iob().  If the application
responds to the received data by transmitting more data, this would
result in a stale ACK number appearing in the transmitted packet,
which potentially causes retransmissions and also gives the
undesirable appearance of violating causality (by sending a response
to a message that we claim not to have yet received).

Reported-by: Guo-Fu Tseng <cooldavid@cooldavid.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
pull/1/head
Michael Brown 2010-05-22 00:45:49 +01:00
parent 13dfe2cf51
commit 9ff8229693
1 changed files with 10 additions and 8 deletions

View File

@ -702,13 +702,13 @@ static int tcp_rx_syn ( struct tcp_connection *tcp, uint32_t seq,
if ( ( tcp->rcv_ack - seq ) > 0 ) if ( ( tcp->rcv_ack - seq ) > 0 )
return 0; return 0;
/* Acknowledge SYN */
tcp_rx_seq ( tcp, 1 );
/* Mark SYN as received and start sending ACKs with each packet */ /* Mark SYN as received and start sending ACKs with each packet */
tcp->tcp_state |= ( TCP_STATE_SENT ( TCP_ACK ) | tcp->tcp_state |= ( TCP_STATE_SENT ( TCP_ACK ) |
TCP_STATE_RCVD ( TCP_SYN ) ); TCP_STATE_RCVD ( TCP_SYN ) );
/* Acknowledge SYN */
tcp_rx_seq ( tcp, 1 );
return 0; return 0;
} }
@ -809,6 +809,9 @@ static int tcp_rx_data ( struct tcp_connection *tcp, uint32_t seq,
iob_pull ( iobuf, already_rcvd ); iob_pull ( iobuf, already_rcvd );
len -= already_rcvd; len -= already_rcvd;
/* Acknowledge new data */
tcp_rx_seq ( tcp, len );
/* Deliver data to application */ /* Deliver data to application */
if ( ( rc = xfer_deliver_iob ( &tcp->xfer, iobuf ) ) != 0 ) { if ( ( rc = xfer_deliver_iob ( &tcp->xfer, iobuf ) ) != 0 ) {
DBGC ( tcp, "TCP %p could not deliver %08x..%08x: %s\n", DBGC ( tcp, "TCP %p could not deliver %08x..%08x: %s\n",
@ -816,9 +819,6 @@ static int tcp_rx_data ( struct tcp_connection *tcp, uint32_t seq,
return rc; return rc;
} }
/* Acknowledge new data */
tcp_rx_seq ( tcp, len );
return 0; return 0;
} }
@ -835,10 +835,12 @@ static int tcp_rx_fin ( struct tcp_connection *tcp, uint32_t seq ) {
if ( ( tcp->rcv_ack - seq ) > 0 ) if ( ( tcp->rcv_ack - seq ) > 0 )
return 0; return 0;
/* Mark FIN as received and acknowledge it */ /* Acknowledge FIN */
tcp->tcp_state |= TCP_STATE_RCVD ( TCP_FIN );
tcp_rx_seq ( tcp, 1 ); tcp_rx_seq ( tcp, 1 );
/* Mark FIN as received */
tcp->tcp_state |= TCP_STATE_RCVD ( TCP_FIN );
/* Close connection */ /* Close connection */
tcp_close ( tcp, 0 ); tcp_close ( tcp, 0 );