From 2bf55008502e9691ab3ace062d854f1b10ba3667 Mon Sep 17 00:00:00 2001 From: ps Date: Thu, 14 Apr 2005 20:09:52 +0000 Subject: Fix for a TCP SACK bug where more than (win/2) bytes could have been in flight in SACK recovery. Found by: Noritoshi Demizu Submitted by: Mohan Srinivasan Noritoshi Demizu Raja Mukerji --- sys/netinet/tcp_sack.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'sys/netinet/tcp_sack.c') diff --git a/sys/netinet/tcp_sack.c b/sys/netinet/tcp_sack.c index efe3bb6..a8e226c 100644 --- a/sys/netinet/tcp_sack.c +++ b/sys/netinet/tcp_sack.c @@ -536,10 +536,10 @@ tcp_sack_partialack(tp, th) struct tcpcb *tp; struct tcphdr *th; { - INP_LOCK_ASSERT(tp->t_inpcb); int num_segs = 1; int sack_bytes_rxmt = 0; + INP_LOCK_ASSERT(tp->t_inpcb); callout_stop(tp->tt_rexmt); tp->t_rtttime = 0; /* send one or 2 segments based on how much new data was acked */ @@ -548,6 +548,8 @@ tcp_sack_partialack(tp, th) (void)tcp_sack_output(tp, &sack_bytes_rxmt); tp->snd_cwnd = sack_bytes_rxmt + (tp->snd_nxt - tp->sack_newdata) + num_segs * tp->t_maxseg; + if (tp->snd_cwnd > tp->snd_ssthresh) + tp->snd_cwnd = tp->snd_ssthresh; tp->t_flags |= TF_ACKNOW; (void) tcp_output(tp); } @@ -632,3 +634,33 @@ tcp_sack_adjust(struct tcpcb *tp) tp->snd_nxt = tp->rcv_lastsack; return; } + +/* + * Calculate the number of SACKed bytes in the scoreboard by + * subtracting the amount of data accounted for in sackholes + * from the total span of the scoreboard. Also returns the + * amount of data that is "lost" and has not yet been retransmitted. + */ +int +tcp_sacked_bytes(struct tcpcb *tp, int *lost_not_rexmitted) +{ + INP_LOCK_ASSERT(tp->t_inpcb); + struct sackhole *cur = tp->snd_holes; + int sacked = 0; + u_long lost = 0; + + if (cur == NULL) /* Scoreboard empty. */ + goto out; + if (SEQ_GEQ(tp->snd_una, tp->rcv_lastsack)) /* Scoreboard is stale. */ + goto out; + sacked = tp->rcv_lastsack - cur->start; + while (cur) { + lost += (cur->end - cur->rxmit); + sacked -= (cur->end - cur->start); + cur = cur->next; + } +out: + if (lost_not_rexmitted) + *lost_not_rexmitted = lost; + return (sacked); +} -- cgit v1.1