From eea1167a85e3f7a3d244a5aaa55a9ba624aec07b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 3 Jan 2007 21:51:36 +0000 Subject: [PATCH] Accept RST on received packets --- src/net/tcp.c | 58 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/src/net/tcp.c b/src/net/tcp.c index 8b56604a..579495c3 100644 --- a/src/net/tcp.c +++ b/src/net/tcp.c @@ -559,7 +559,8 @@ static int tcp_rx_data ( struct tcp_connection *conn, uint32_t seq, return 0; } -/** Handle TCP received FIN +/** + * Handle TCP received FIN * * @v conn TCP connection * @v seq SEQ value (in host-endian order) @@ -587,6 +588,46 @@ static int tcp_rx_fin ( struct tcp_connection *conn, uint32_t seq ) { return 0; } +/** + * Handle TCP received RST + * + * @v conn TCP connection + * @v seq SEQ value (in host-endian order) + * @ret rc Return status code + */ +static int tcp_rx_rst ( struct tcp_connection *conn, uint32_t seq ) { + struct tcp_application *app = conn->app; + + /* Accept RST only if it falls within the window. If we have + * not yet received a SYN, then we have no window to test + * against, so fall back to checking that our SYN has been + * ACKed. + */ + if ( conn->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) { + if ( ( conn->rcv_ack - seq ) > 0 ) + return 0; + } else { + if ( ! ( conn->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) ) + return 0; + } + + /* Transition to CLOSED */ + conn->tcp_state = TCP_CLOSED; + tcp_dump_state ( conn ); + + /* Break association between application and connection */ + tcp_disassociate ( conn ); + + /* Free the connection */ + free_tcp ( conn ); + + /* Notify application */ + if ( app && app->tcp_op->closed ) + app->tcp_op->closed ( app, -ECONNRESET ); + + return -ECONNRESET; +} + /** * Process received packet * @@ -668,13 +709,6 @@ static int tcp_rx ( struct pk_buff *pkb, goto done; } - /* Handle RST, if present */ -#warning "Handle RST" - if ( flags & TCP_RST ) { - rc = -ECONNRESET; - goto done; - } - /* Handle ACK, if present */ if ( flags & TCP_ACK ) tcp_rx_ack ( conn, ack, win ); @@ -685,6 +719,12 @@ static int tcp_rx ( struct pk_buff *pkb, seq++; } + /* Handle RST, if present */ + if ( flags & TCP_RST ) { + if ( ( rc = tcp_rx_rst ( conn, seq ) ) != 0 ) + goto done; + } + /* Handle new data, if any */ tcp_rx_data ( conn, seq, data, len ); seq += len; @@ -695,7 +735,7 @@ static int tcp_rx ( struct pk_buff *pkb, seq++; } - /* Dump out any state change as a result of SYN, FIN or ACK */ + /* Dump out any state change as a result of the received packet */ tcp_dump_state ( conn ); /* Send out any pending data. If peer is expecting an ACK for