From: Guo-Fu Tseng <[email protected]> Separate tcp_terminate() from tcp_close(). Use tcp_terminate to immediately free all tcp resources. And use tcp_close() to bing TCP connection to closing state.
Signed-off-by: Guo-Fu Tseng <[email protected]> --- src/net/tcp.c | 124 +++++++++++++++++++++++++++++---------------------------- 1 files changed, 63 insertions(+), 61 deletions(-) diff --git a/src/net/tcp.c b/src/net/tcp.c index 3e6543c..4e69f70 100644 --- a/src/net/tcp.c +++ b/src/net/tcp.c @@ -265,6 +265,12 @@ static int tcp_open ( struct xfer_interface *xfer, struct sockaddr *peer, if ( ! tcp ) return -ENOMEM; DBGC ( tcp, "TCP %p allocated\n", tcp ); + /** + * refcnt is the first object of struct tcp_connection + * In other word, &tcp->refcnt == tcp. + * So that we can use default free(&tcp->refcnt) in ref_put() + * to free this tcp_connection structure. + */ ref_init ( &tcp->refcnt, NULL ); xfer_init ( &tcp->xfer, &tcp_xfer_operations, &tcp->refcnt ); timer_init ( &tcp->timer, tcp_expired ); @@ -297,42 +303,65 @@ static int tcp_open ( struct xfer_interface *xfer, struct sockaddr *peer, } /** - * Close TCP connection + * Shutdown TCP xfer interface * * @v tcp TCP connection * @v rc Reason for close * - * If the TCP state machine is in a suitable state, the - * connection will be deleted. + * Closes the data transfer interface. */ -static void tcp_close ( struct tcp_connection *tcp ) { +static void tcp_xfer_shutdown ( struct tcp_connection *tcp, int rc ) { + if ( tcp->flags & TCP_XFER_CLOSED ) + return; + + /* Close data transfer interface */ + xfer_nullify ( &tcp->xfer ); + xfer_close ( &tcp->xfer, rc ); + tcp->flags |= TCP_XFER_CLOSED; +} + +/** + * TCP connection final cleanup + * + * @v tcp TCP connection + * @v rc Reason for close + * + * Terminate TCP connection and free all resources + */ +static void tcp_terminate ( struct tcp_connection *tcp, int rc ) { struct io_buffer *iobuf; struct io_buffer *tmp; - /* If we are in CLOSED, or have otherwise not yet received a - * SYN (i.e. we are in LISTEN or SYN_SENT), just delete the - * connection. - */ - if ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) { - - /* Transition to CLOSED for the sake of debugging messages */ - tcp->tcp_state = TCP_CLOSED; - tcp_dump_state ( tcp ); + /* Shutdown TCP xfer interface */ + tcp_xfer_shutdown ( tcp, rc ); - /* Free any unsent I/O buffers */ - list_for_each_entry_safe ( iobuf, tmp, &tcp->queue, list ) { - list_del ( &iobuf->list ); - free_iob ( iobuf ); - } + /* Transition to CLOSED for the sake of debugging messages */ + tcp->tcp_state = TCP_CLOSED; + tcp_dump_state ( tcp ); - /* Remove from list and drop reference */ - stop_timer ( &tcp->timer ); - list_del ( &tcp->list ); - ref_put ( &tcp->refcnt ); - DBGC ( tcp, "TCP %p connection deleted\n", tcp ); - return; + /* Free any unsent I/O buffers */ + list_for_each_entry_safe ( iobuf, tmp, &tcp->queue, list ) { + list_del ( &iobuf->list ); + free_iob ( iobuf ); } + /* Remove from list and drop reference */ + stop_timer ( &tcp->timer ); + stop_timer ( &tcp->wait ); + list_del ( &tcp->list ); + ref_put ( &tcp->refcnt ); + DBGC ( tcp, "TCP %p connection deleted\n", tcp ); +} + +/** + * Start to close TCP connection + * + * @v tcp TCP connection + * @v rc Reason for close + * + * Bring TCP connection to closing state + */ +static void tcp_close ( struct tcp_connection *tcp ) { /* If we have not had our SYN acknowledged (i.e. we are in * SYN_RCVD), pretend that it has been acknowledged so that we * can send a FIN without breaking things. @@ -347,24 +376,6 @@ static void tcp_close ( struct tcp_connection *tcp ) { } } -/** - * Shutdown TCP xfer interface - * - * @v tcp TCP connection - * @v rc Reason for close - * - * Closes the data transfer interface. - */ -static void tcp_xfer_shutdown ( struct tcp_connection *tcp, int rc ) { - if ( tcp->flags & TCP_XFER_CLOSED ) - return; - - /* Close data transfer interface */ - xfer_nullify ( &tcp->xfer ); - xfer_close ( &tcp->xfer, rc ); - tcp->flags |= TCP_XFER_CLOSED; -} - /*************************************************************************** * * Transmit data path @@ -601,10 +612,7 @@ static void tcp_expired ( struct retry_timer *timer, int over ) { /* If we have finally timed out and given up, * terminate the connection */ - tcp->tcp_state = TCP_CLOSED; - tcp_dump_state ( tcp ); - tcp_close ( tcp ); - tcp_xfer_shutdown ( tcp, -ETIMEDOUT ); + tcp_terminate ( tcp, -ETIMEDOUT ); } else { /* Otherwise, retransmit the packet */ tcp_xmit ( tcp ); @@ -627,10 +635,7 @@ static void tcp_wait_expired ( struct retry_timer *timer, int over __unused ) { tcp_state ( tcp->tcp_state ), tcp->snd_seq, ( tcp->snd_seq + tcp->snd_sent ), tcp->rcv_ack ); - tcp->tcp_state = TCP_CLOSED; - tcp_dump_state ( tcp ); - tcp_close ( tcp ); - tcp_xfer_shutdown ( tcp, 0 ); + tcp_terminate ( tcp, 0 ); } /** @@ -930,7 +935,7 @@ static int tcp_rx_fin ( struct tcp_connection *tcp, uint32_t seq ) { DBGC ( tcp, "TCP %p passive closing.\n", tcp ); } - /* Close connection */ + /* Start to close connection */ tcp_close ( tcp ); return 0; @@ -959,10 +964,7 @@ static int tcp_rx_rst ( struct tcp_connection *tcp, uint32_t seq ) { } /* Abort connection */ - tcp->tcp_state = TCP_CLOSED; - tcp_dump_state ( tcp ); - tcp_close ( tcp ); - tcp_xfer_shutdown ( tcp, -ECONNRESET ); + tcp_terminate ( tcp, -ECONNRESET ); DBGC ( tcp, "TCP %p connection reset by peer\n", tcp ); return -ECONNRESET; @@ -1111,10 +1113,7 @@ static int tcp_rx ( struct io_buffer *iobuf, * Set up timer to expire and cause the connection to be freed. */ if ( tcp->tcp_state == TCP_PASV_CLOSED ) { - tcp->tcp_state = TCP_CLOSED; - tcp_dump_state ( tcp ); - tcp_close ( tcp ); - tcp_xfer_shutdown ( tcp, 0 ); + tcp_terminate ( tcp, 0 ); } else if ( TCP_CLOSED_GRACEFULLY ( tcp->tcp_state ) ) { stop_timer ( &tcp->wait ); start_timer_fixed ( &tcp->wait, ( 2 * TCP_MSL ) ); @@ -1152,10 +1151,13 @@ static void tcp_xfer_close ( struct xfer_interface *xfer, int rc ) { struct tcp_connection *tcp = container_of ( xfer, struct tcp_connection, xfer ); - /* Close TCP Connection */ + /* Start to close TCP Connection */ tcp_close ( tcp ); - /* Shutdown xfer interface */ + /** + * Shutdown xfer interface + * Upper layer stopped transmitting data after calling this + */ tcp_xfer_shutdown ( tcp, rc ); /* Transmit FIN, if possible */ -- 1.7.1 _______________________________________________ gPXE-devel mailing list [email protected] http://etherboot.org/mailman/listinfo/gpxe-devel
