Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_output.c
Show First 20 Lines • Show All 500 Lines • ▼ Show 20 Lines | if (len <= 0) { | ||||
* We also do a general check here to ensure that | * We also do a general check here to ensure that | ||||
* we will set the persist timer when we have data | * we will set the persist timer when we have data | ||||
* to send, but a 0-byte window. This makes sure | * to send, but a 0-byte window. This makes sure | ||||
* the persist timer is set even if the packet | * the persist timer is set even if the packet | ||||
* hits one of the "goto send" lines below. | * hits one of the "goto send" lines below. | ||||
*/ | */ | ||||
len = 0; | len = 0; | ||||
if ((sendwin == 0) && (TCPS_HAVEESTABLISHED(tp->t_state)) && | if ((sendwin == 0) && (TCPS_HAVEESTABLISHED(tp->t_state)) && | ||||
(off < (int) sbavail(&so->so_snd))) { | (off < (int) sbavail(&so->so_snd)) && | ||||
!tcp_timer_active(tp, TT_PERSIST)) { | |||||
tcp_timer_activate(tp, TT_REXMT, 0); | tcp_timer_activate(tp, TT_REXMT, 0); | ||||
tp->t_rxtshift = 0; | tp->t_rxtshift = 0; | ||||
tp->snd_nxt = tp->snd_una; | tp->snd_nxt = tp->snd_una; | ||||
if (!tcp_timer_active(tp, TT_PERSIST)) | if (!tcp_timer_active(tp, TT_PERSIST)) | ||||
tcp_setpersist(tp); | tcp_setpersist(tp); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 211 Lines • ▼ Show 20 Lines | dontupdate: | ||||
* In SACK, it is possible for tcp_output to fail to send a segment | * In SACK, it is possible for tcp_output to fail to send a segment | ||||
* after the retransmission timer has been turned off. Make sure | * after the retransmission timer has been turned off. Make sure | ||||
* that the retransmission timer is set. | * that the retransmission timer is set. | ||||
*/ | */ | ||||
if ((tp->t_flags & TF_SACK_PERMIT) && | if ((tp->t_flags & TF_SACK_PERMIT) && | ||||
SEQ_GT(tp->snd_max, tp->snd_una) && | SEQ_GT(tp->snd_max, tp->snd_una) && | ||||
!tcp_timer_active(tp, TT_REXMT) && | !tcp_timer_active(tp, TT_REXMT) && | ||||
!tcp_timer_active(tp, TT_PERSIST)) { | !tcp_timer_active(tp, TT_PERSIST)) { | ||||
tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur); | tcp_timer_activate(tp, TT_REXMT, TP_RXTCUR(tp)); | ||||
goto just_return; | goto just_return; | ||||
} | } | ||||
/* | /* | ||||
* TCP window updates are not reliable, rather a polling protocol | * TCP window updates are not reliable, rather a polling protocol | ||||
* using ``persist'' packets is used to insure receipt of window | * using ``persist'' packets is used to insure receipt of window | ||||
* updates. The three ``states'' for the output side are: | * updates. The three ``states'' for the output side are: | ||||
* idle not doing retransmits or persists | * idle not doing retransmits or persists | ||||
* persisting to move a small or zero window | * persisting to move a small or zero window | ||||
▲ Show 20 Lines • Show All 827 Lines • ▼ Show 20 Lines | if (flags & (TH_SYN|TH_FIN)) { | ||||
tp->snd_nxt++; | tp->snd_nxt++; | ||||
tp->t_flags |= TF_SENTFIN; | tp->t_flags |= TF_SENTFIN; | ||||
} | } | ||||
} | } | ||||
if (sack_rxmit) | if (sack_rxmit) | ||||
goto timer; | goto timer; | ||||
tp->snd_nxt += len; | tp->snd_nxt += len; | ||||
if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { | if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { | ||||
/* | |||||
* Update "made progress" indication if we just | |||||
* added new data to an empty socket buffer. | |||||
*/ | |||||
if (tp->snd_una == tp->snd_max) | |||||
tp->t_acktime = ticks; | |||||
tp->snd_max = tp->snd_nxt; | tp->snd_max = tp->snd_nxt; | ||||
/* | /* | ||||
* Time this transmission if not a retransmission and | * Time this transmission if not a retransmission and | ||||
* not currently timing anything. | * not currently timing anything. | ||||
*/ | */ | ||||
tp->t_sndtime = ticks; | tp->t_sndtime = ticks; | ||||
if (tp->t_rtttime == 0) { | if (tp->t_rtttime == 0) { | ||||
tp->t_rtttime = ticks; | tp->t_rtttime = ticks; | ||||
Show All 22 Lines | |||||
timer: | timer: | ||||
if (!tcp_timer_active(tp, TT_REXMT) && | if (!tcp_timer_active(tp, TT_REXMT) && | ||||
((sack_rxmit && tp->snd_nxt != tp->snd_max) || | ((sack_rxmit && tp->snd_nxt != tp->snd_max) || | ||||
(tp->snd_nxt != tp->snd_una))) { | (tp->snd_nxt != tp->snd_una))) { | ||||
if (tcp_timer_active(tp, TT_PERSIST)) { | if (tcp_timer_active(tp, TT_PERSIST)) { | ||||
tcp_timer_activate(tp, TT_PERSIST, 0); | tcp_timer_activate(tp, TT_PERSIST, 0); | ||||
tp->t_rxtshift = 0; | tp->t_rxtshift = 0; | ||||
} | } | ||||
tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur); | tcp_timer_activate(tp, TT_REXMT, TP_RXTCUR(tp)); | ||||
} else if (len == 0 && sbavail(&so->so_snd) && | } else if (len == 0 && sbavail(&so->so_snd) && | ||||
!tcp_timer_active(tp, TT_REXMT) && | !tcp_timer_active(tp, TT_REXMT) && | ||||
!tcp_timer_active(tp, TT_PERSIST)) { | !tcp_timer_active(tp, TT_PERSIST)) { | ||||
/* | /* | ||||
* Avoid a situation where we do not set persist timer | * Avoid a situation where we do not set persist timer | ||||
* after a zero window condition. For example: | * after a zero window condition. For example: | ||||
* 1) A -> B: packet with enough data to fill the window | * 1) A -> B: packet with enough data to fill the window | ||||
* 2) B -> A: ACK for #1 + new data (0 window | * 2) B -> A: ACK for #1 + new data (0 window | ||||
▲ Show 20 Lines • Show All 136 Lines • ▼ Show 20 Lines | #endif | ||||
return (0); | return (0); | ||||
} | } | ||||
void | void | ||||
tcp_setpersist(struct tcpcb *tp) | tcp_setpersist(struct tcpcb *tp) | ||||
{ | { | ||||
int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; | int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; | ||||
int tt; | int tt; | ||||
int maxunacktime; | |||||
tp->t_flags &= ~TF_PREVVALID; | tp->t_flags &= ~TF_PREVVALID; | ||||
if (tcp_timer_active(tp, TT_REXMT)) | if (tcp_timer_active(tp, TT_REXMT)) | ||||
panic("tcp_setpersist: retransmit pending"); | panic("tcp_setpersist: retransmit pending"); | ||||
/* | /* | ||||
* If the state is already closed, don't bother. | |||||
*/ | |||||
if (tp->t_state == TCPS_CLOSED) | |||||
return; | |||||
/* | |||||
* Start/restart persistence timer. | * Start/restart persistence timer. | ||||
*/ | */ | ||||
TCPT_RANGESET(tt, t * tcp_backoff[tp->t_rxtshift], | TCPT_RANGESET(tt, t * tcp_backoff[tp->t_rxtshift], | ||||
tcp_persmin, tcp_persmax); | tcp_persmin, tcp_persmax); | ||||
if (TP_MAXUNACKTIME(tp) && tp->t_acktime) { | |||||
maxunacktime = tp->t_acktime + TP_MAXUNACKTIME(tp) - ticks; | |||||
if (maxunacktime < 1) | |||||
maxunacktime = 1; | |||||
if (maxunacktime < tt) | |||||
tt = maxunacktime; | |||||
} | |||||
tcp_timer_activate(tp, TT_PERSIST, tt); | tcp_timer_activate(tp, TT_PERSIST, tt); | ||||
if (tp->t_rxtshift < TCP_MAXRXTSHIFT) | if (tp->t_rxtshift < TCP_MAXRXTSHIFT) | ||||
tp->t_rxtshift++; | tp->t_rxtshift++; | ||||
} | } | ||||
/* | /* | ||||
* Insert TCP options according to the supplied parameters to the place | * Insert TCP options according to the supplied parameters to the place | ||||
* optp in a consistent way. Can handle unaligned destinations. | * optp in a consistent way. Can handle unaligned destinations. | ||||
▲ Show 20 Lines • Show All 401 Lines • Show Last 20 Lines |