mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-24 11:29:10 +00:00
Fix a potential panic in the SACK code that was causing
1) data to be sent to the right of snd_recover. 2) send more data then whats in the send buffer. The fix is to postpone sack retransmit to a subsequent recovery episode if the current retransmit pointer is beyond snd_recover. Thanks to Mohan Srinivasan for helping fix the bug. Submitted by:Daniel Lang
This commit is contained in:
parent
ec47b83454
commit
f787edd847
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=132417
@ -200,23 +200,44 @@ tcp_output(struct tcpcb *tp)
|
||||
sack_rxmit = 0;
|
||||
len = 0;
|
||||
p = NULL;
|
||||
if (tp->sack_enable && IN_FASTRECOVERY(tp) &&
|
||||
if (tp->sack_enable && SEQ_LT(tp->snd_una,tp->snd_recover) &&
|
||||
(p = tcp_sack_output(tp))) {
|
||||
KASSERT(tp->snd_cwnd >= 0,
|
||||
("%s: CWIN is negative : %ld", __func__, tp->snd_cwnd));
|
||||
/* Do not retransmit SACK segments beyond snd_recover */
|
||||
if (SEQ_GT(p->end, tp->snd_recover)) {
|
||||
/*
|
||||
* (At least) part of sack hole extends beyond
|
||||
* snd_recover. Check to see if we can rexmit data
|
||||
* for this hole.
|
||||
*/
|
||||
if (SEQ_GEQ(p->rxmit, tp->snd_recover)) {
|
||||
/*
|
||||
* Can't rexmit any more data for this hole.
|
||||
* That data will be rexmitted in the next
|
||||
* sack recovery episode, when snd_recover
|
||||
* moves past p->rxmit.
|
||||
*/
|
||||
p = NULL;
|
||||
goto after_sack_rexmit;
|
||||
} else
|
||||
/* Can rexmit part of the current hole */
|
||||
len = ((long)ulmin(tp->snd_cwnd,
|
||||
tp->snd_recover - p->rxmit));
|
||||
} else
|
||||
len = ((long)ulmin(tp->snd_cwnd, p->end - p->rxmit));
|
||||
sack_rxmit = 1;
|
||||
sendalot = 1;
|
||||
off = p->rxmit - tp->snd_una;
|
||||
KASSERT(tp->snd_cwnd >= 0,("%s: CWIN is negative: %ld", __func__, tp->snd_cwnd));
|
||||
/* Do not retransmit SACK segments beyond snd_recover */
|
||||
if (SEQ_GT(p->end, tp->snd_recover))
|
||||
len = min(tp->snd_cwnd, tp->snd_recover - p->rxmit);
|
||||
else
|
||||
len = min(tp->snd_cwnd, p->end - p->rxmit);
|
||||
KASSERT(off >= 0,("%s: sack block to the left of una : %d",
|
||||
__func__, off));
|
||||
if (len > 0) {
|
||||
tcpstat.tcps_sack_rexmits++;
|
||||
tcpstat.tcps_sack_rexmit_bytes +=
|
||||
min(len, tp->t_maxseg);
|
||||
min(len, tp->t_maxseg);
|
||||
}
|
||||
}
|
||||
after_sack_rexmit:
|
||||
/*
|
||||
* Get standard flags, and add SYN or FIN if requested by 'hidden'
|
||||
* state flags.
|
||||
|
Loading…
Reference in New Issue
Block a user