[tcp] Update received sequence number before delivering received data
authorMichael Brown <mcb30@ipxe.org>
Fri, 21 May 2010 23:45:49 +0000 (00:45 +0100)
committerMarty Connor <mdc@etherboot.org>
Sun, 1 Aug 2010 19:19:49 +0000 (15:19 -0400)
gPXE 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>
Signed-off-by: Marty Connor <mdc@etherboot.org>
src/net/tcp.c

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