summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>2000-02-21 21:42:14 +0000
committerNiels Provos <provos@cvs.openbsd.org>2000-02-21 21:42:14 +0000
commit8e5ea50ac7894e04a29346fc325a5926926bda49 (patch)
tree6bf90e4f39e004c1211b750b02527775fb9ef3d2
parent7686a9d107cbe24bfc6976fcf40b4eb9607eed1c (diff)
TCP SACK fixes via Tom Henderson (tomh@cs.berkeley.edu):
- tcp_sack_adjust() was completely rewritten, since it was erroneously referencing receiver side sequence numbers and comparing with sender side sequence numbers (thanks to Arun Desai (adesai@cisco.com) who discovered the problem) - in tcp_output(), moved assignment of sendalot=0 to the piece of code immediately following the search for sack-eligible retransmissions (bug identified by Arun Desai). - tcp_input() was not clearing t_dupacks if fewer than three dupacks arrived between acks of new data. (bug identified by Gaurav Banga (gaurav@netapp.com))
-rw-r--r--sys/netinet/tcp_input.c4
-rw-r--r--sys/netinet/tcp_output.c53
2 files changed, 35 insertions, 22 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 5b28a0fd020..d84f9583b87 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_input.c,v 1.56 1999/12/21 17:49:28 provos Exp $ */
+/* $OpenBSD: tcp_input.c,v 1.57 2000/02/21 21:42:13 provos Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
@@ -1672,6 +1672,8 @@ trimthenstep6:
tp->t_dupacks = 0;
}
}
+ if (tp->t_dupacks < tcprexmtthresh)
+ tp->t_dupacks = 0;
#else /* else no TCP_SACK */
if (tp->t_dupacks >= tcprexmtthresh &&
tp->snd_cwnd > tp->snd_ssthresh)
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 6d6cf41dfa6..07164c6ff8a 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_output.c,v 1.29 2000/01/07 00:57:54 itojun Exp $ */
+/* $OpenBSD: tcp_output.c,v 1.30 2000/02/21 21:42:13 provos Exp $ */
/* $NetBSD: tcp_output.c,v 1.16 1997/06/03 16:17:09 kml Exp $ */
/*
@@ -152,19 +152,30 @@ void
tcp_sack_adjust(tp)
struct tcpcb *tp;
{
- int i;
-
- for (i = 0; i < tp->rcv_numsacks; i++) {
- if (SEQ_LT(tp->snd_nxt, tp->sackblks[i].start))
- break;
- if (SEQ_LEQ(tp->sackblks[i].end, tp->snd_nxt))
- continue;
- if (tp->sackblks[i].start == 0 && tp->sackblks[i].end == 0)
- continue;
- /* snd_nxt must be in middle of block of SACKed data */
- tp->snd_nxt = tp->sackblks[i].end;
- break;
+ struct sackhole *cur = tp->snd_holes;
+ if (cur == 0)
+ return; /* No holes */
+ if (SEQ_GEQ(tp->snd_nxt, tp->rcv_lastsack))
+ return; /* We're already beyond any SACKed blocks */
+ /*
+ * Two cases for which we want to advance snd_nxt:
+ * i) snd_nxt lies between end of one hole and beginning of another
+ * ii) snd_nxt lies between end of last hole and rcv_lastsack
+ */
+ while (cur->next) {
+ if (SEQ_LT(tp->snd_nxt, cur->end))
+ return;
+ if (SEQ_GEQ(tp->snd_nxt, cur->next->start))
+ cur = cur->next;
+ else {
+ tp->snd_nxt = cur->next->start;
+ return;
+ }
}
+ if (SEQ_LT(tp->snd_nxt, cur->end))
+ return;
+ tp->snd_nxt = tp->rcv_lastsack;
+ return;
}
#endif /* TCP_SACK */
@@ -182,7 +193,7 @@ tcp_output(tp)
register struct tcphdr *th;
u_char opt[MAX_TCPOPTLEN];
unsigned int optlen, hdrlen;
- int idle, sendalot;
+ int idle, sendalot = 0;
#ifdef TCP_SACK
int i, sack_rxmit = 0;
struct sackhole *p;
@@ -214,7 +225,6 @@ tcp_output(tp)
*/
tp->snd_cwnd = tp->t_maxseg;
again:
- sendalot = 0;
#ifdef TCP_SACK
/*
* If we've recently taken a timeout, snd_max will be greater than
@@ -228,12 +238,6 @@ again:
win = ulmin(tp->snd_wnd, tp->snd_cwnd);
flags = tcp_outflags[tp->t_state];
- /*
- * If in persist timeout with window of 0, send 1 byte.
- * Otherwise, if window is small but nonzero
- * and timer expired, we will send what we can
- * and go to transmit state.
- */
#ifdef TCP_SACK
/*
@@ -260,6 +264,13 @@ again:
}
#endif /* TCP_SACK */
+ sendalot = 0;
+ /*
+ * If in persist timeout with window of 0, send 1 byte.
+ * Otherwise, if window is small but nonzero
+ * and timer expired, we will send what we can
+ * and go to transmit state.
+ */
if (tp->t_force) {
if (win == 0) {
/*