From 6b40ef55c34c5b06f335f63f127ff9eeccd79de1 Mon Sep 17 00:00:00 2001 From: ps Date: Mon, 21 Nov 2005 19:22:10 +0000 Subject: Fix for a bug that causes SACK scoreboard corruption when the limit on holes per connection is reached. Reported by: Patrik Roos Submitted by: Mohan Srinivasan Reviewed by: Raja Mukerji, Noritoshi Demizu --- sys/netinet/tcp_sack.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'sys/netinet/tcp_sack.c') diff --git a/sys/netinet/tcp_sack.c b/sys/netinet/tcp_sack.c index 163e0a4..02ffdde 100644 --- a/sys/netinet/tcp_sack.c +++ b/sys/netinet/tcp_sack.c @@ -448,11 +448,26 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack) * way of hole splitting in the while-loop below. */ temp = tcp_sackhole_insert(tp, tp->snd_fack,sblkp->start,NULL); - if (temp == NULL) - return; - tp->snd_fack = sblkp->end; - /* Go to the previous sack block. */ - sblkp--; + if (temp != NULL) { + tp->snd_fack = sblkp->end; + /* Go to the previous sack block. */ + sblkp--; + } else { + /* + * We failed to add a new hole based on the current + * sack block. Skip over all the sack blocks that + * fall completely to the right of snd_fack and proceed + * to trim the scoreboard based on the remaining sack + * blocks. This also trims the scoreboard for th_ack + * (which is sack_blocks[0]). + */ + while (sblkp >= sack_blocks && + SEQ_LT(tp->snd_fack, sblkp->start)) + sblkp--; + if (sblkp >= sack_blocks && + SEQ_LT(tp->snd_fack, sblkp->end)) + tp->snd_fack = sblkp->end; + } } else if (SEQ_LT(tp->snd_fack, sblkp->end)) /* fack is advanced. */ tp->snd_fack = sblkp->end; @@ -463,7 +478,7 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack) * Since the incoming sack blocks are sorted, we can process them * making one sweep of the scoreboard. */ - while (sblkp - sack_blocks >= 0 && cur != NULL) { + while (sblkp >= sack_blocks && cur != NULL) { if (SEQ_GEQ(sblkp->start, cur->end)) { /* * SACKs data beyond the current hole. -- cgit v1.1