Ver código fonte

[tcp] Avoid rewinding sequence numbers on receiving old duplicate ACKs

Commit 558c1a4 ("[tcp] Improve robustness in the presence of duplicated
received packets") introduced a regression in that an old duplicate
ACK received while in the ESTABLISHED state would pass through normal
ACK processing, including updating tcp->snd_seq.

Fix by ensuring that ACK processing ignores all duplicate ACKs.
tags/v0.9.8
Michael Brown 15 anos atrás
pai
commit
58f60df66c
1 arquivos alterados com 31 adições e 27 exclusões
  1. 31
    27
      src/net/tcp.c

+ 31
- 27
src/net/tcp.c Ver arquivo

@@ -726,40 +726,44 @@ static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack,
726 726
 	size_t len;
727 727
 	unsigned int acked_flags;
728 728
 
729
-	/* Determine acknowledged flags and data length */
730
-	len = ack_len;
731
-	acked_flags = ( TCP_FLAGS_SENDING ( tcp->tcp_state ) &
732
-			( TCP_SYN | TCP_FIN ) );
733
-	if ( acked_flags )
734
-		len--;
735
-
736
-	/* Stop retransmission timer if necessary */
737
-	if ( ack_len == 0 ) {
738
-		/* Duplicate ACK (or just a packet that isn't
739
-		 * intending to ACK any new data).  If the
740
-		 * retransmission timer is running, leave it running
741
-		 * so that we don't immediately retransmit and cause a
742
-		 * sorceror's apprentice syndrome.
743
-		 */
744
-	} else if ( ack_len <= tcp->snd_sent ) {
745
-		/* ACK of new data.  Stop the retransmission timer. */
746
-		stop_timer ( &tcp->timer );
747
-	} else {
748
-		/* Out-of-range (or old duplicate) ACK.  Leave the
749
-		 * timer running, as for the ack_len==0 case, to
750
-		 * handle old duplicate ACKs.
751
-		 */
729
+	/* Check for out-of-range or old duplicate ACKs */
730
+	if ( ack_len > tcp->snd_sent ) {
752 731
 		DBGC ( tcp, "TCP %p received ACK for %08x..%08zx, "
753 732
 		       "sent only %08x..%08x\n", tcp, tcp->snd_seq,
754 733
 		       ( tcp->snd_seq + ack_len ), tcp->snd_seq,
755 734
 		       ( tcp->snd_seq + tcp->snd_sent ) );
756
-		/* Send RST if an out-of-range ACK is received on a
757
-		 * not-yet-established connection.
758
-		 */
759
-		if ( ! TCP_HAS_BEEN_ESTABLISHED ( tcp->tcp_state ) )
735
+
736
+		if ( TCP_HAS_BEEN_ESTABLISHED ( tcp->tcp_state ) ) {
737
+			/* Just ignore what might be old duplicate ACKs */
738
+			return 0;
739
+		} else {
740
+			/* Send RST if an out-of-range ACK is received
741
+			 * on a not-yet-established connection, as per
742
+			 * RFC 793.
743
+			 */
760 744
 			return -EINVAL;
745
+		}
761 746
 	}
762 747
 
748
+	/* Ignore ACKs that don't actually acknowledge any new data.
749
+	 * (In particular, do not stop the retransmission timer; this
750
+	 * avoids creating a sorceror's apprentice syndrome when a
751
+	 * duplicate ACK is received and we still have data in our
752
+	 * transmit queue.)
753
+	 */
754
+	if ( ack_len == 0 )
755
+		return 0;
756
+
757
+	/* Stop the retransmission timer */
758
+	stop_timer ( &tcp->timer );
759
+
760
+	/* Determine acknowledged flags and data length */
761
+	len = ack_len;
762
+	acked_flags = ( TCP_FLAGS_SENDING ( tcp->tcp_state ) &
763
+			( TCP_SYN | TCP_FIN ) );
764
+	if ( acked_flags )
765
+		len--;
766
+
763 767
 	/* Update SEQ and sent counters, and window size */
764 768
 	tcp->snd_seq = ack;
765 769
 	tcp->snd_sent = 0;

Carregando…
Cancelar
Salvar