From c4369eb6c2d14e92c7b820be14da25afad456a5e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 3 Apr 2011 00:37:27 +0100 Subject: [PATCH] [tcp] Update ts_recent whenever window is advanced Commit 3f442d3 ("[tcp] Record ts_recent on first received packet") failed to achieve its stated intention. Fix this (and reduce the code size) by moving the ts_recent update to tcp_rx_seq(). This is the code responsible for advancing the window, called by both tcp_rx_syn() and tcp_rx_data(), and so the window check is now redundant. Reported-by: Frank Weed Signed-off-by: Michael Brown --- src/net/tcp.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/net/tcp.c b/src/net/tcp.c index d9529882..fbcf279e 100644 --- a/src/net/tcp.c +++ b/src/net/tcp.c @@ -74,7 +74,13 @@ struct tcp_connection { * Equivalent to RCV.WND in RFC 793 terminology. */ uint32_t rcv_win; - /** Most recent received timestamp + /** Received timestamp value + * + * Updated when a packet is received; copied to ts_recent when + * the window is advanced. + */ + uint32_t ts_val; + /** Most recent received timestamp that advanced the window * * Equivalent to TS.Recent in RFC 1323 terminology. */ @@ -740,12 +746,24 @@ static void tcp_rx_opts ( struct tcp_connection *tcp, const void *data, * @v seq_len Sequence space length to consume */ static void tcp_rx_seq ( struct tcp_connection *tcp, uint32_t seq_len ) { + + /* Sanity check */ + assert ( seq_len > 0 ); + + /* Update acknowledgement number */ tcp->rcv_ack += seq_len; + + /* Update window */ if ( tcp->rcv_win > seq_len ) { tcp->rcv_win -= seq_len; } else { tcp->rcv_win = 0; } + + /* Update timestamp */ + tcp->ts_recent = tcp->ts_val; + + /* Mark ACK as pending */ tcp->flags |= TCP_ACK_PENDING; } @@ -1060,7 +1078,6 @@ static int tcp_rx ( struct io_buffer *iobuf, struct tcp_options options; size_t hlen; uint16_t csum; - uint32_t start_seq; uint32_t seq; uint32_t ack; uint32_t win; @@ -1100,12 +1117,14 @@ static int tcp_rx ( struct io_buffer *iobuf, /* Parse parameters from header and strip header */ tcp = tcp_demux ( ntohs ( tcphdr->dest ) ); - seq = start_seq = ntohl ( tcphdr->seq ); + seq = ntohl ( tcphdr->seq ); ack = ntohl ( tcphdr->ack ); win = ntohs ( tcphdr->win ); flags = tcphdr->flags; tcp_rx_opts ( tcp, ( ( ( void * ) tcphdr ) + sizeof ( *tcphdr ) ), ( hlen - sizeof ( *tcphdr ) ), &options ); + if ( options.tsopt ) + tcp->ts_val = ntohl ( options.tsopt->tsval ); iob_pull ( iobuf, hlen ); len = iob_len ( iobuf ); seq_len = ( len + ( ( flags & TCP_SYN ) ? 1 : 0 ) + @@ -1152,12 +1171,6 @@ static int tcp_rx ( struct io_buffer *iobuf, goto discard; } - /* Update timestamp, if applicable */ - if ( options.tsopt && - tcp_in_window ( tcp->rcv_ack, start_seq, seq_len ) ) { - tcp->ts_recent = ntohl ( options.tsopt->tsval ); - } - /* Enqueue received data */ tcp_rx_enqueue ( tcp, seq, flags, iob_disown ( iobuf ) );