From: Guo-Fu Tseng <coolda...@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 <coolda...@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 22f3936..c9ebc35 100644
--- a/src/net/tcp.c
+++ b/src/net/tcp.c
@@ -63,6 +63,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

_______________________________________________
gPXE-devel mailing list
gPXE-devel@etherboot.org
http://etherboot.org/mailman/listinfo/gpxe-devel

Reply via email to