Index: sys/netinet/tcp_output.c =================================================================== --- sys/netinet/tcp_output.c +++ sys/netinet/tcp_output.c @@ -1234,6 +1234,14 @@ } else { th->th_seq = htonl(p->rxmit); p->rxmit += len; + /* + * Lost Retransmission Detection + * trigger resending of a (then + * still existing) hole, when + * fack acks recoverypoint. + */ + if (SEQ_GEQ(p->rxmit, p->end)) + p->rxmit = tp->snd_recover; tp->sackhint.sack_bytes_rexmit += len; } th->th_ack = htonl(tp->rcv_nxt); Index: sys/netinet/tcp_sack.c =================================================================== --- sys/netinet/tcp_sack.c +++ sys/netinet/tcp_sack.c @@ -665,6 +665,17 @@ tp->snd_fack = sblkp->end; sack_changed = 1; } + /* + * Lost Retransmission Detection + * Check is FACK is >= than the end of the leftmost hole. + * if yes, we start sending from still existing holes + */ + if ((temp = TAILQ_FIRST(&tp->snd_holes)) != NULL) { + if (SEQ_GEQ(tp->snd_fack, temp->rxmit)) { + temp->rxmit = temp->start; + tp->sackhint.nexthole = temp; + } + } cur = TAILQ_LAST(&tp->snd_holes, sackhole_head); /* Last SACK hole. */ /* * Since the incoming sack blocks are sorted, we can process them @@ -687,7 +698,8 @@ cur = TAILQ_PREV(cur, sackhole_head, scblink); continue; } - tp->sackhint.sack_bytes_rexmit -= (cur->rxmit - cur->start); + tp->sackhint.sack_bytes_rexmit -= + (SEQ_MIN(cur->rxmit, cur->end) - cur->start); KASSERT(tp->sackhint.sack_bytes_rexmit >= 0, ("sackhint bytes rtx >= 0")); sack_changed = 1; @@ -717,7 +729,8 @@ /* Move end of hole backward. */ delivered_data += (cur->end - sblkp->start); cur->end = sblkp->start; - cur->rxmit = SEQ_MIN(cur->rxmit, cur->end); + if (SEQ_GEQ(cur->rxmit, cur->end)) + cur->rxmit = tp->snd_recover; } else { /* * ACKs some data in middle of a hole; need @@ -729,17 +742,18 @@ if (SEQ_GT(cur->rxmit, temp->rxmit)) { temp->rxmit = cur->rxmit; tp->sackhint.sack_bytes_rexmit - += (temp->rxmit - - temp->start); + += (SEQ_MIN(temp->rxmit, + temp->end) - temp->start); } cur->end = sblkp->start; - cur->rxmit = SEQ_MIN(cur->rxmit, - cur->end); + if (SEQ_GEQ(cur->rxmit, cur->end)) + cur->rxmit = tp->snd_recover; delivered_data += (sblkp->end - sblkp->start); } } } - tp->sackhint.sack_bytes_rexmit += (cur->rxmit - cur->start); + tp->sackhint.sack_bytes_rexmit += + (SEQ_MIN(cur->rxmit, cur->end) - cur->start); /* * Testing sblkp->start against cur->start tells us whether * we're done with the sack block or the sack hole. @@ -858,7 +872,7 @@ *sack_bytes_rexmt += (p->rxmit - p->start); break; } - *sack_bytes_rexmt += (p->rxmit - p->start); + *sack_bytes_rexmt += (SEQ_MIN(p->rxmit, p->end) - p->start); } return (p); }