[ipxe-devel] [PATCH 2/4] [tcp] Distinguish passive and active close with proper actions

Guo-Fu Tseng cooldavid at cooldavid.org
Fri Jul 30 12:40:36 UTC 2010


From: Guo-Fu Tseng <cooldavid at cooldavid.org>

The original design of TCP stack dose not distinguish passive and active
close, support is to make close action more compatible with RFC 793 and
having the ability to benefit from passive closing that can release all
resources immediately.

Signed-off-by: Guo-Fu Tseng <cooldavid at cooldavid.org>
---
 src/include/ipxe/tcp.h |   43 ++++++++++++++++++++++++++++++++++++-------
 src/net/tcp.c          |   26 +++++++++++++++++++++-----
 2 files changed, 57 insertions(+), 12 deletions(-)

diff --git a/src/include/ipxe/tcp.h b/src/include/ipxe/tcp.h
index b189afd..b57e365 100644
--- a/src/include/ipxe/tcp.h
+++ b/src/include/ipxe/tcp.h
@@ -132,6 +132,12 @@ struct tcp_options {
  */
 #define TCP_CLOSED TCP_RST
 
+/** TCP Passive Close
+ *
+ * Received FIN while FIN not sent
+ */
+#define TCP_PASV_CLOSE	0x80000000
+
 /** LISTEN
  *
  * Not currently used as a state; we have no support for listening
@@ -187,20 +193,31 @@ struct tcp_options {
 			  TCP_STATE_ACKED ( TCP_SYN | TCP_FIN ) |	    \
 			  TCP_STATE_RCVD ( TCP_SYN ) )
 
-/** CLOSING / LAST_ACK
+/** CLOSING
+ *
+ * For the active close
  *
  * SYN has been sent and acknowledged, SYN has been received, FIN has
  * been sent but not acknowledged, FIN has been received.
- *
- * This state actually encompasses both CLOSING and LAST_ACK; they are
- * identical with the definition of state that we use.  I don't
- * *believe* that they need to be distinguished.
  */
-#define TCP_CLOSING_OR_LAST_ACK						    \
+#define TCP_CLOSING							    \
 			( TCP_STATE_SENT ( TCP_SYN | TCP_ACK | TCP_FIN ) |  \
 			  TCP_STATE_ACKED ( TCP_SYN ) |			    \
 			  TCP_STATE_RCVD ( TCP_SYN | TCP_FIN ) )
 
+/** LAST_ACK
+ *
+ * For the passive close
+ *
+ * SYN has been sent and acknowledged, SYN has been received, FIN has
+ * been sent but not acknowledged, FIN has been received.
+ */
+#define TCP_LAST_ACK						    \
+			( TCP_STATE_SENT ( TCP_SYN | TCP_ACK | TCP_FIN ) |  \
+			  TCP_STATE_ACKED ( TCP_SYN ) |			    \
+			  TCP_STATE_RCVD ( TCP_SYN | TCP_FIN ) |	    \
+			  TCP_PASV_CLOSE )
+
 /** TIME_WAIT
  *
  * SYN has been sent and acknowledged, SYN has been received, FIN has
@@ -210,6 +227,17 @@ struct tcp_options {
 			  TCP_STATE_ACKED ( TCP_SYN | TCP_FIN ) |	    \
 			  TCP_STATE_RCVD ( TCP_SYN | TCP_FIN ) )
 
+/** PASV_CLOSED
+ *
+ * SYN has been sent and acknowledged, SYN has been received, FIN has
+ * been sent and acknowledged, FIN has been received.
+ * And was passive close.
+ */
+#define TCP_PASV_CLOSED	( TCP_STATE_SENT ( TCP_SYN | TCP_ACK | TCP_FIN ) |  \
+			  TCP_STATE_ACKED ( TCP_SYN | TCP_FIN ) |	    \
+			  TCP_STATE_RCVD ( TCP_SYN | TCP_FIN ) |	    \
+			  TCP_PASV_CLOSE )
+
 /** CLOSE_WAIT
  *
  * SYN has been sent and acknowledged, SYN has been received, FIN has
@@ -217,7 +245,8 @@ struct tcp_options {
  */
 #define TCP_CLOSE_WAIT	( TCP_STATE_SENT ( TCP_SYN | TCP_ACK ) |	    \
 			  TCP_STATE_ACKED ( TCP_SYN ) |			    \
-			  TCP_STATE_RCVD ( TCP_SYN | TCP_FIN ) )
+			  TCP_STATE_RCVD ( TCP_SYN | TCP_FIN ) |	    \
+			  TCP_PASV_CLOSE )
 
 /** Can send data in current state
  *
diff --git a/src/net/tcp.c b/src/net/tcp.c
index 19815fb..94277c9 100644
--- a/src/net/tcp.c
+++ b/src/net/tcp.c
@@ -150,9 +150,11 @@ tcp_state ( int state ) {
 	case TCP_ESTABLISHED:		return "ESTABLISHED";
 	case TCP_FIN_WAIT_1:		return "FIN_WAIT_1";
 	case TCP_FIN_WAIT_2:		return "FIN_WAIT_2";
-	case TCP_CLOSING_OR_LAST_ACK:	return "CLOSING/LAST_ACK";
+	case TCP_CLOSING:		return "CLOSING";
+	case TCP_LAST_ACK:		return "LAST_ACK";
 	case TCP_TIME_WAIT:		return "TIME_WAIT";
 	case TCP_CLOSE_WAIT:		return "CLOSE_WAIT";
+	case TCP_PASV_CLOSED:		return "PASV_CLOSED";
 	default:			return "INVALID";
 	}
 }
@@ -577,7 +579,8 @@ static void tcp_expired ( struct retry_timer *timer, int over ) {
 		 ( tcp->tcp_state == TCP_ESTABLISHED ) ||
 		 ( tcp->tcp_state == TCP_FIN_WAIT_1 ) ||
 		 ( tcp->tcp_state == TCP_CLOSE_WAIT ) ||
-		 ( tcp->tcp_state == TCP_CLOSING_OR_LAST_ACK ) );
+		 ( tcp->tcp_state == TCP_CLOSING ) ||
+		 ( tcp->tcp_state == TCP_LAST_ACK ) );
 
 	if ( over ) {
 		/* If we have finally timed out and given up,
@@ -901,6 +904,12 @@ static int tcp_rx_fin ( struct tcp_connection *tcp, uint32_t seq ) {
 	/* Mark FIN as received */
 	tcp->tcp_state |= TCP_STATE_RCVD ( TCP_FIN );
 
+	/* Mark as passive close if we receive FIN privier than sending FIN */
+	if ( !( tcp->tcp_state & TCP_FLAGS_SENT ( TCP_FIN ) ) ) {
+		tcp->tcp_state |= TCP_PASV_CLOSE;
+		DBGC ( tcp, "TCP %p passive closing.\n", tcp );
+	}
+
 	return 0;
 }
 
@@ -1171,10 +1180,17 @@ static int tcp_rx ( struct io_buffer *iobuf,
 	/* Send out any pending data */
 	tcp_xmit ( tcp );
 
-	/* If this packet was the last we expect to receive, set up
-	 * timer to expire and cause the connection to be freed.
+	/* If this packet was the last we expect to receive:
+	 * For passive close:
+	 * 	Free the connection immediately.
+	 * For active close:
+	 *	Set up timer to expire and cause the connection to be freed.
 	 */
-	if ( TCP_CLOSED_GRACEFULLY ( tcp->tcp_state ) ) {
+	if ( tcp->tcp_state == TCP_PASV_CLOSED ) {
+		tcp->tcp_state = TCP_CLOSED;
+		tcp_dump_state ( tcp );
+		tcp_close ( tcp, 0 );
+	} else if ( TCP_CLOSED_GRACEFULLY ( tcp->tcp_state ) ) {
 		stop_timer ( &tcp->wait );
 		start_timer_fixed ( &tcp->wait, ( 2 * TCP_MSL ) );
 	}
-- 
1.7.1




More information about the ipxe-devel mailing list