[gPXE-devel] [PATCHv2 6/6] [tcp] Fix possible misjudged SYN/FIN ACKed status

cooldavid at cooldavid.org cooldavid at cooldavid.org
Wed Jul 14 01:25:07 EDT 2010


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

gPXE did not check the ACK number while receiving a response from remote
server with ACK flag set. gPXE assumes the remote server ACKed the
SYN/FIN sent by gPXE if received ANY packet with ACK flag being set.
This error might occur when the packet is out-of-order.

Signed-off-by: Guo-Fu Tseng <cooldavid at cooldavid.org>
---
 src/net/tcp.c |   26 +++++++++++++++++++++++---
 1 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/src/net/tcp.c b/src/net/tcp.c
index d79dc57..41fae41 100644
--- a/src/net/tcp.c
+++ b/src/net/tcp.c
@@ -62,6 +62,17 @@ struct tcp_connection {
 	 * Equivalent to SND.WND in RFC 793 terminology
 	 */
 	uint32_t snd_win;
+	/** Send SYN sequence
+	 *
+	 * Sequence number of sent SYN packet
+	 */
+	uint32_t snd_syn_seq;
+	/** Send FIN sequence
+	 *
+	 * Sequence number of sent FIN packet
+	 */
+	uint32_t snd_fin_seq;
+
 	/** Current acknowledgement number
 	 *
 	 * Equivalent to RCV.NXT in RFC 793 terminology.
@@ -525,6 +536,11 @@ static int tcp_xmit ( struct tcp_connection *tcp, int force_send ) {
 		return rc;
 	}
 
+	if ( flags & TCP_SYN )
+		tcp->snd_syn_seq = tcp->snd_seq;
+	if ( flags & TCP_FIN )
+		tcp->snd_fin_seq = tcp->snd_seq;
+
 	return 0;
 }
 
@@ -745,7 +761,7 @@ static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack,
 			uint32_t win ) {
 	uint32_t ack_len = ( ack - tcp->snd_seq );
 	size_t len;
-	unsigned int acked_flags;
+	unsigned int acked_flags = 0;
 
 	/* Check for out-of-range or old duplicate ACKs */
 	if ( ack_len > tcp->snd_sent ) {
@@ -780,8 +796,12 @@ static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack,
 
 	/* Determine acknowledged flags and data length */
 	len = ack_len;
-	acked_flags = ( TCP_FLAGS_SENDING ( tcp->tcp_state ) &
-			( TCP_SYN | TCP_FIN ) );
+	if ( ( TCP_FLAGS_SENDING ( tcp->tcp_state ) & TCP_SYN ) &&
+		after ( ack, tcp->snd_syn_seq ) )
+		acked_flags |= TCP_SYN;
+	if ( ( TCP_FLAGS_SENDING ( tcp->tcp_state ) & TCP_FIN ) &&
+		after ( ack, tcp->snd_fin_seq ) )
+		acked_flags |= TCP_FIN;
 	if ( acked_flags )
 		len--;
 
-- 
1.7.1



More information about the gPXE-devel mailing list