Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_timer.c
Show First 20 Lines • Show All 249 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct tcpcb *tp = xtp; | struct tcpcb *tp = xtp; | ||||
struct inpcb *inp = tptoinpcb(tp); | struct inpcb *inp = tptoinpcb(tp); | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
CURVNET_SET(inp->inp_vnet); | CURVNET_SET(inp->inp_vnet); | ||||
if (callout_pending(&tp->t_timers->tt_delack) || | if (callout_pending(&tp->tt_delack) || | ||||
!callout_active(&tp->t_timers->tt_delack)) { | !callout_active(&tp->tt_delack)) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} | } | ||||
callout_deactivate(&tp->t_timers->tt_delack); | callout_deactivate(&tp->tt_delack); | ||||
if ((inp->inp_flags & INP_DROPPED) != 0) { | if ((inp->inp_flags & INP_DROPPED) != 0) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} | } | ||||
tp->t_flags |= TF_ACKNOW; | tp->t_flags |= TF_ACKNOW; | ||||
TCPSTAT_INC(tcps_delack); | TCPSTAT_INC(tcps_delack); | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | #ifdef TCPDEBUG | ||||
ostate = tp->t_state; | ostate = tp->t_state; | ||||
#endif | #endif | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
CURVNET_SET(inp->inp_vnet); | CURVNET_SET(inp->inp_vnet); | ||||
tcp_log_end_status(tp, TCP_EI_STATUS_2MSL); | tcp_log_end_status(tp, TCP_EI_STATUS_2MSL); | ||||
tcp_free_sackholes(tp); | tcp_free_sackholes(tp); | ||||
if (callout_pending(&tp->t_timers->tt_2msl) || | if (callout_pending(&tp->tt_2msl) || | ||||
!callout_active(&tp->t_timers->tt_2msl)) { | !callout_active(&tp->tt_2msl)) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} | } | ||||
callout_deactivate(&tp->t_timers->tt_2msl); | callout_deactivate(&tp->tt_2msl); | ||||
if (inp->inp_flags & INP_DROPPED) { | if (inp->inp_flags & INP_DROPPED) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} | } | ||||
KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, | KASSERT((tp->tt_flags & TT_STOPPED) == 0, | ||||
("%s: tp %p tcpcb can't be stopped here", __func__, tp)); | ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); | ||||
/* | /* | ||||
* 2 MSL timeout in shutdown went off. If we're closed but | * 2 MSL timeout in shutdown went off. If we're closed but | ||||
* still waiting for peer to close and connection has been idle | * still waiting for peer to close and connection has been idle | ||||
* too long delete connection control block. Otherwise, check | * too long delete connection control block. Otherwise, check | ||||
* again in a bit. | * again in a bit. | ||||
* | * | ||||
* If fastrecycle of FIN_WAIT_2, in FIN_WAIT_2 and receiver has closed, | * If fastrecycle of FIN_WAIT_2, in FIN_WAIT_2 and receiver has closed, | ||||
Show All 10 Lines | return; | ||||
tcp_fast_finwait2_recycle && inp->inp_socket && | tcp_fast_finwait2_recycle && inp->inp_socket && | ||||
(inp->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) { | (inp->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) { | ||||
TCPSTAT_INC(tcps_finwait2_drops); | TCPSTAT_INC(tcps_finwait2_drops); | ||||
tcp_timer_close(tp); | tcp_timer_close(tp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} else { | } else { | ||||
if (ticks - tp->t_rcvtime <= TP_MAXIDLE(tp)) { | if (ticks - tp->t_rcvtime <= TP_MAXIDLE(tp)) { | ||||
callout_reset(&tp->t_timers->tt_2msl, | callout_reset(&tp->tt_2msl, | ||||
TP_KEEPINTVL(tp), tcp_timer_2msl, tp); | TP_KEEPINTVL(tp), tcp_timer_2msl, tp); | ||||
} else { | } else { | ||||
tcp_timer_close(tp); | tcp_timer_close(tp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
Show All 19 Lines | #ifdef TCPDEBUG | ||||
int ostate; | int ostate; | ||||
ostate = tp->t_state; | ostate = tp->t_state; | ||||
#endif | #endif | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
CURVNET_SET(inp->inp_vnet); | CURVNET_SET(inp->inp_vnet); | ||||
if (callout_pending(&tp->t_timers->tt_keep) || | if (callout_pending(&tp->tt_keep) || | ||||
!callout_active(&tp->t_timers->tt_keep)) { | !callout_active(&tp->tt_keep)) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} | } | ||||
callout_deactivate(&tp->t_timers->tt_keep); | callout_deactivate(&tp->tt_keep); | ||||
if (inp->inp_flags & INP_DROPPED) { | if (inp->inp_flags & INP_DROPPED) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} | } | ||||
KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, | KASSERT((tp->tt_flags & TT_STOPPED) == 0, | ||||
("%s: tp %p tcpcb can't be stopped here", __func__, tp)); | ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); | ||||
/* | /* | ||||
* Because we don't regularly reset the keepalive callout in | * Because we don't regularly reset the keepalive callout in | ||||
* the ESTABLISHED state, it may be that we don't actually need | * the ESTABLISHED state, it may be that we don't actually need | ||||
* to send a keepalive yet. If that occurs, schedule another | * to send a keepalive yet. If that occurs, schedule another | ||||
* call for the next time the keepalive timer might expire. | * call for the next time the keepalive timer might expire. | ||||
*/ | */ | ||||
if (TCPS_HAVEESTABLISHED(tp->t_state)) { | if (TCPS_HAVEESTABLISHED(tp->t_state)) { | ||||
u_int idletime; | u_int idletime; | ||||
idletime = ticks - tp->t_rcvtime; | idletime = ticks - tp->t_rcvtime; | ||||
if (idletime < TP_KEEPIDLE(tp)) { | if (idletime < TP_KEEPIDLE(tp)) { | ||||
callout_reset(&tp->t_timers->tt_keep, | callout_reset(&tp->tt_keep, | ||||
TP_KEEPIDLE(tp) - idletime, tcp_timer_keep, tp); | TP_KEEPIDLE(tp) - idletime, tcp_timer_keep, tp); | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
Show All 25 Lines | if ((V_tcp_always_keepalive || | ||||
if (t_template) { | if (t_template) { | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
tcp_respond(tp, t_template->tt_ipgen, | tcp_respond(tp, t_template->tt_ipgen, | ||||
&t_template->tt_t, (struct mbuf *)NULL, | &t_template->tt_t, (struct mbuf *)NULL, | ||||
tp->rcv_nxt, tp->snd_una - 1, 0); | tp->rcv_nxt, tp->snd_una - 1, 0); | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
free(t_template, M_TEMP); | free(t_template, M_TEMP); | ||||
} | } | ||||
callout_reset(&tp->t_timers->tt_keep, TP_KEEPINTVL(tp), | callout_reset(&tp->tt_keep, TP_KEEPINTVL(tp), | ||||
tcp_timer_keep, tp); | tcp_timer_keep, tp); | ||||
} else | } else | ||||
callout_reset(&tp->t_timers->tt_keep, TP_KEEPIDLE(tp), | callout_reset(&tp->tt_keep, TP_KEEPIDLE(tp), | ||||
tcp_timer_keep, tp); | tcp_timer_keep, tp); | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
if (inp->inp_socket->so_options & SO_DEBUG) | if (inp->inp_socket->so_options & SO_DEBUG) | ||||
tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, | tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, | ||||
PRU_SLOWTIMO); | PRU_SLOWTIMO); | ||||
#endif | #endif | ||||
TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); | TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | #ifdef TCPDEBUG | ||||
int ostate; | int ostate; | ||||
ostate = tp->t_state; | ostate = tp->t_state; | ||||
#endif | #endif | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
CURVNET_SET(inp->inp_vnet); | CURVNET_SET(inp->inp_vnet); | ||||
if (callout_pending(&tp->t_timers->tt_persist) || | if (callout_pending(&tp->tt_persist) || | ||||
!callout_active(&tp->t_timers->tt_persist)) { | !callout_active(&tp->tt_persist)) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} | } | ||||
callout_deactivate(&tp->t_timers->tt_persist); | callout_deactivate(&tp->tt_persist); | ||||
if (inp->inp_flags & INP_DROPPED) { | if (inp->inp_flags & INP_DROPPED) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} | } | ||||
KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, | KASSERT((tp->tt_flags & TT_STOPPED) == 0, | ||||
("%s: tp %p tcpcb can't be stopped here", __func__, tp)); | ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); | ||||
/* | /* | ||||
* Persistence timer into zero window. | * Persistence timer into zero window. | ||||
* Force a byte to be output, if possible. | * Force a byte to be output, if possible. | ||||
*/ | */ | ||||
TCPSTAT_INC(tcps_persisttimeo); | TCPSTAT_INC(tcps_persisttimeo); | ||||
/* | /* | ||||
* Hack: if the peer is dead/unreachable, we do not | * Hack: if the peer is dead/unreachable, we do not | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | #ifdef TCPDEBUG | ||||
int ostate; | int ostate; | ||||
ostate = tp->t_state; | ostate = tp->t_state; | ||||
#endif | #endif | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
CURVNET_SET(inp->inp_vnet); | CURVNET_SET(inp->inp_vnet); | ||||
if (callout_pending(&tp->t_timers->tt_rexmt) || | if (callout_pending(&tp->tt_rexmt) || | ||||
!callout_active(&tp->t_timers->tt_rexmt)) { | !callout_active(&tp->tt_rexmt)) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} | } | ||||
callout_deactivate(&tp->t_timers->tt_rexmt); | callout_deactivate(&tp->tt_rexmt); | ||||
if (inp->inp_flags & INP_DROPPED) { | if (inp->inp_flags & INP_DROPPED) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} | } | ||||
KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, | KASSERT((tp->tt_flags & TT_STOPPED) == 0, | ||||
("%s: tp %p tcpcb can't be stopped here", __func__, tp)); | ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); | ||||
tcp_free_sackholes(tp); | tcp_free_sackholes(tp); | ||||
TCP_LOG_EVENT(tp, NULL, NULL, NULL, TCP_LOG_RTO, 0, 0, NULL, false); | TCP_LOG_EVENT(tp, NULL, NULL, NULL, TCP_LOG_RTO, 0, 0, NULL, false); | ||||
if (tp->t_fb->tfb_tcp_rexmit_tmr) { | if (tp->t_fb->tfb_tcp_rexmit_tmr) { | ||||
/* The stack has a timer action too. */ | /* The stack has a timer action too. */ | ||||
(*tp->t_fb->tfb_tcp_rexmit_tmr)(tp); | (*tp->t_fb->tfb_tcp_rexmit_tmr)(tp); | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 165 Lines • ▼ Show 20 Lines | #ifdef INET | ||||
TCPSTAT_INC(tcps_pmtud_blackhole_activated_min_mss); | TCPSTAT_INC(tcps_pmtud_blackhole_activated_min_mss); | ||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
* Reset the slow-start flight size | * Reset the slow-start flight size | ||||
* as it may depend on the new MSS. | * as it may depend on the new MSS. | ||||
*/ | */ | ||||
if (CC_ALGO(tp)->conn_init != NULL) | if (CC_ALGO(tp)->conn_init != NULL) | ||||
CC_ALGO(tp)->conn_init(tp->ccv); | CC_ALGO(tp)->conn_init(&tp->t_ccv); | ||||
} else { | } else { | ||||
/* | /* | ||||
* If further retransmissions are still unsuccessful | * If further retransmissions are still unsuccessful | ||||
* with a lowered MTU, maybe this isn't a blackhole and | * with a lowered MTU, maybe this isn't a blackhole and | ||||
* we restore the previous MSS and blackhole detection | * we restore the previous MSS and blackhole detection | ||||
* flags. | * flags. | ||||
*/ | */ | ||||
if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) && | if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) && | ||||
(tp->t_rxtshift >= tp->t_blackhole_exit)) { | (tp->t_rxtshift >= tp->t_blackhole_exit)) { | ||||
tp->t_flags2 |= TF2_PLPMTU_PMTUD; | tp->t_flags2 |= TF2_PLPMTU_PMTUD; | ||||
tp->t_flags2 &= ~TF2_PLPMTU_BLACKHOLE; | tp->t_flags2 &= ~TF2_PLPMTU_BLACKHOLE; | ||||
tp->t_maxseg = tp->t_pmtud_saved_maxseg; | tp->t_maxseg = tp->t_pmtud_saved_maxseg; | ||||
TCPSTAT_INC(tcps_pmtud_blackhole_failed); | TCPSTAT_INC(tcps_pmtud_blackhole_failed); | ||||
/* | /* | ||||
* Reset the slow-start flight size as it | * Reset the slow-start flight size as it | ||||
* may depend on the new MSS. | * may depend on the new MSS. | ||||
*/ | */ | ||||
if (CC_ALGO(tp)->conn_init != NULL) | if (CC_ALGO(tp)->conn_init != NULL) | ||||
CC_ALGO(tp)->conn_init(tp->ccv); | CC_ALGO(tp)->conn_init(&tp->t_ccv); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Disable RFC1323 and SACK if we haven't got any response to | * Disable RFC1323 and SACK if we haven't got any response to | ||||
* our third SYN to work-around some broken terminal servers | * our third SYN to work-around some broken terminal servers | ||||
* (most of which have hopefully been retired) that have bad VJ | * (most of which have hopefully been retired) that have bad VJ | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | tcp_timer_activate(struct tcpcb *tp, uint32_t timer_type, u_int delta) | ||||
struct inpcb *inp = tptoinpcb(tp); | struct inpcb *inp = tptoinpcb(tp); | ||||
int cpu = inp_to_cpuid(inp); | int cpu = inp_to_cpuid(inp); | ||||
#ifdef TCP_OFFLOAD | #ifdef TCP_OFFLOAD | ||||
if (tp->t_flags & TF_TOE) | if (tp->t_flags & TF_TOE) | ||||
return; | return; | ||||
#endif | #endif | ||||
if (tp->t_timers->tt_flags & TT_STOPPED) | if (tp->tt_flags & TT_STOPPED) | ||||
return; | return; | ||||
switch (timer_type) { | switch (timer_type) { | ||||
case TT_DELACK: | case TT_DELACK: | ||||
t_callout = &tp->t_timers->tt_delack; | t_callout = &tp->tt_delack; | ||||
f_callout = tcp_timer_delack; | f_callout = tcp_timer_delack; | ||||
break; | break; | ||||
case TT_REXMT: | case TT_REXMT: | ||||
t_callout = &tp->t_timers->tt_rexmt; | t_callout = &tp->tt_rexmt; | ||||
f_callout = tcp_timer_rexmt; | f_callout = tcp_timer_rexmt; | ||||
break; | break; | ||||
case TT_PERSIST: | case TT_PERSIST: | ||||
t_callout = &tp->t_timers->tt_persist; | t_callout = &tp->tt_persist; | ||||
f_callout = tcp_timer_persist; | f_callout = tcp_timer_persist; | ||||
break; | break; | ||||
case TT_KEEP: | case TT_KEEP: | ||||
t_callout = &tp->t_timers->tt_keep; | t_callout = &tp->tt_keep; | ||||
f_callout = tcp_timer_keep; | f_callout = tcp_timer_keep; | ||||
break; | break; | ||||
case TT_2MSL: | case TT_2MSL: | ||||
t_callout = &tp->t_timers->tt_2msl; | t_callout = &tp->tt_2msl; | ||||
f_callout = tcp_timer_2msl; | f_callout = tcp_timer_2msl; | ||||
break; | break; | ||||
default: | default: | ||||
if (tp->t_fb->tfb_tcp_timer_activate) { | if (tp->t_fb->tfb_tcp_timer_activate) { | ||||
tp->t_fb->tfb_tcp_timer_activate(tp, timer_type, delta); | tp->t_fb->tfb_tcp_timer_activate(tp, timer_type, delta); | ||||
return; | return; | ||||
} | } | ||||
panic("tp %p bad timer_type %#x", tp, timer_type); | panic("tp %p bad timer_type %#x", tp, timer_type); | ||||
} | } | ||||
if (delta == 0) { | if (delta == 0) { | ||||
callout_stop(t_callout); | callout_stop(t_callout); | ||||
} else { | } else { | ||||
callout_reset_on(t_callout, delta, f_callout, tp, cpu); | callout_reset_on(t_callout, delta, f_callout, tp, cpu); | ||||
} | } | ||||
} | } | ||||
int | int | ||||
tcp_timer_active(struct tcpcb *tp, uint32_t timer_type) | tcp_timer_active(struct tcpcb *tp, uint32_t timer_type) | ||||
{ | { | ||||
struct callout *t_callout; | struct callout *t_callout; | ||||
switch (timer_type) { | switch (timer_type) { | ||||
case TT_DELACK: | case TT_DELACK: | ||||
t_callout = &tp->t_timers->tt_delack; | t_callout = &tp->tt_delack; | ||||
break; | break; | ||||
case TT_REXMT: | case TT_REXMT: | ||||
t_callout = &tp->t_timers->tt_rexmt; | t_callout = &tp->tt_rexmt; | ||||
break; | break; | ||||
case TT_PERSIST: | case TT_PERSIST: | ||||
t_callout = &tp->t_timers->tt_persist; | t_callout = &tp->tt_persist; | ||||
break; | break; | ||||
case TT_KEEP: | case TT_KEEP: | ||||
t_callout = &tp->t_timers->tt_keep; | t_callout = &tp->tt_keep; | ||||
break; | break; | ||||
case TT_2MSL: | case TT_2MSL: | ||||
t_callout = &tp->t_timers->tt_2msl; | t_callout = &tp->tt_2msl; | ||||
break; | break; | ||||
default: | default: | ||||
if (tp->t_fb->tfb_tcp_timer_active) { | if (tp->t_fb->tfb_tcp_timer_active) { | ||||
return(tp->t_fb->tfb_tcp_timer_active(tp, timer_type)); | return(tp->t_fb->tfb_tcp_timer_active(tp, timer_type)); | ||||
} | } | ||||
panic("tp %p bad timer_type %#x", tp, timer_type); | panic("tp %p bad timer_type %#x", tp, timer_type); | ||||
} | } | ||||
return callout_active(t_callout); | return callout_active(t_callout); | ||||
Show All 11 Lines | |||||
tcp_timer_suspend(struct tcpcb *tp, uint32_t timer_type) | tcp_timer_suspend(struct tcpcb *tp, uint32_t timer_type) | ||||
{ | { | ||||
struct callout *t_callout; | struct callout *t_callout; | ||||
uint32_t t_flags; | uint32_t t_flags; | ||||
switch (timer_type) { | switch (timer_type) { | ||||
case TT_DELACK: | case TT_DELACK: | ||||
t_flags = TT_DELACK_SUS; | t_flags = TT_DELACK_SUS; | ||||
t_callout = &tp->t_timers->tt_delack; | t_callout = &tp->tt_delack; | ||||
break; | break; | ||||
case TT_REXMT: | case TT_REXMT: | ||||
t_flags = TT_REXMT_SUS; | t_flags = TT_REXMT_SUS; | ||||
t_callout = &tp->t_timers->tt_rexmt; | t_callout = &tp->tt_rexmt; | ||||
break; | break; | ||||
case TT_PERSIST: | case TT_PERSIST: | ||||
t_flags = TT_PERSIST_SUS; | t_flags = TT_PERSIST_SUS; | ||||
t_callout = &tp->t_timers->tt_persist; | t_callout = &tp->tt_persist; | ||||
break; | break; | ||||
case TT_KEEP: | case TT_KEEP: | ||||
t_flags = TT_KEEP_SUS; | t_flags = TT_KEEP_SUS; | ||||
t_callout = &tp->t_timers->tt_keep; | t_callout = &tp->tt_keep; | ||||
break; | break; | ||||
case TT_2MSL: | case TT_2MSL: | ||||
t_flags = TT_2MSL_SUS; | t_flags = TT_2MSL_SUS; | ||||
t_callout = &tp->t_timers->tt_2msl; | t_callout = &tp->tt_2msl; | ||||
break; | break; | ||||
default: | default: | ||||
panic("tp:%p bad timer_type 0x%x", tp, timer_type); | panic("tp:%p bad timer_type 0x%x", tp, timer_type); | ||||
} | } | ||||
tp->t_timers->tt_flags |= t_flags; | tp->tt_flags |= t_flags; | ||||
return (callout_stop(t_callout)); | return (callout_stop(t_callout)); | ||||
} | } | ||||
void | void | ||||
tcp_timers_unsuspend(struct tcpcb *tp, uint32_t timer_type) | tcp_timers_unsuspend(struct tcpcb *tp, uint32_t timer_type) | ||||
{ | { | ||||
switch (timer_type) { | switch (timer_type) { | ||||
case TT_DELACK: | case TT_DELACK: | ||||
if (tp->t_timers->tt_flags & TT_DELACK_SUS) { | if (tp->tt_flags & TT_DELACK_SUS) { | ||||
tp->t_timers->tt_flags &= ~TT_DELACK_SUS; | tp->tt_flags &= ~TT_DELACK_SUS; | ||||
if (tp->t_flags & TF_DELACK) { | if (tp->t_flags & TF_DELACK) { | ||||
/* Delayed ack timer should be up activate a timer */ | /* Delayed ack timer should be up activate a timer */ | ||||
tp->t_flags &= ~TF_DELACK; | tp->t_flags &= ~TF_DELACK; | ||||
tcp_timer_activate(tp, TT_DELACK, | tcp_timer_activate(tp, TT_DELACK, | ||||
tcp_delacktime); | tcp_delacktime); | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case TT_REXMT: | case TT_REXMT: | ||||
if (tp->t_timers->tt_flags & TT_REXMT_SUS) { | if (tp->tt_flags & TT_REXMT_SUS) { | ||||
tp->t_timers->tt_flags &= ~TT_REXMT_SUS; | tp->tt_flags &= ~TT_REXMT_SUS; | ||||
if (SEQ_GT(tp->snd_max, tp->snd_una) && | if (SEQ_GT(tp->snd_max, tp->snd_una) && | ||||
(tcp_timer_active((tp), TT_PERSIST) == 0) && | (tcp_timer_active((tp), TT_PERSIST) == 0) && | ||||
tp->snd_wnd) { | tp->snd_wnd) { | ||||
/* We have outstanding data activate a timer */ | /* We have outstanding data activate a timer */ | ||||
tcp_timer_activate(tp, TT_REXMT, | tcp_timer_activate(tp, TT_REXMT, | ||||
tp->t_rxtcur); | tp->t_rxtcur); | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case TT_PERSIST: | case TT_PERSIST: | ||||
if (tp->t_timers->tt_flags & TT_PERSIST_SUS) { | if (tp->tt_flags & TT_PERSIST_SUS) { | ||||
tp->t_timers->tt_flags &= ~TT_PERSIST_SUS; | tp->tt_flags &= ~TT_PERSIST_SUS; | ||||
if (tp->snd_wnd == 0) { | if (tp->snd_wnd == 0) { | ||||
/* Activate the persists timer */ | /* Activate the persists timer */ | ||||
tp->t_rxtshift = 0; | tp->t_rxtshift = 0; | ||||
tcp_setpersist(tp); | tcp_setpersist(tp); | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case TT_KEEP: | case TT_KEEP: | ||||
if (tp->t_timers->tt_flags & TT_KEEP_SUS) { | if (tp->tt_flags & TT_KEEP_SUS) { | ||||
tp->t_timers->tt_flags &= ~TT_KEEP_SUS; | tp->tt_flags &= ~TT_KEEP_SUS; | ||||
tcp_timer_activate(tp, TT_KEEP, | tcp_timer_activate(tp, TT_KEEP, | ||||
TCPS_HAVEESTABLISHED(tp->t_state) ? | TCPS_HAVEESTABLISHED(tp->t_state) ? | ||||
TP_KEEPIDLE(tp) : TP_KEEPINIT(tp)); | TP_KEEPIDLE(tp) : TP_KEEPINIT(tp)); | ||||
} | } | ||||
break; | break; | ||||
case TT_2MSL: | case TT_2MSL: | ||||
if (tp->t_timers->tt_flags &= TT_2MSL_SUS) { | if (tp->tt_flags &= TT_2MSL_SUS) { | ||||
struct socket *so = tptosocket(tp); | struct socket *so = tptosocket(tp); | ||||
tp->t_timers->tt_flags &= ~TT_2MSL_SUS; | tp->tt_flags &= ~TT_2MSL_SUS; | ||||
if ((tp->t_state == TCPS_FIN_WAIT_2) && | if ((tp->t_state == TCPS_FIN_WAIT_2) && | ||||
(so == NULL || /* XXXGL: needed? */ | (so == NULL || /* XXXGL: needed? */ | ||||
(so->so_rcv.sb_state & SBS_CANTRCVMORE))) { | (so->so_rcv.sb_state & SBS_CANTRCVMORE))) { | ||||
/* Star the 2MSL timer */ | /* Star the 2MSL timer */ | ||||
tcp_timer_activate(tp, TT_2MSL, | tcp_timer_activate(tp, TT_2MSL, | ||||
(tcp_fast_finwait2_recycle) ? | (tcp_fast_finwait2_recycle) ? | ||||
tcp_finwait2_timeout : TP_MAXIDLE(tp)); | tcp_finwait2_timeout : TP_MAXIDLE(tp)); | ||||
} | } | ||||
Show All 10 Lines | tcp_timer_discard(void *ptp) | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct tcpcb *tp = (struct tcpcb *)ptp; | struct tcpcb *tp = (struct tcpcb *)ptp; | ||||
struct inpcb *inp = tptoinpcb(tp); | struct inpcb *inp = tptoinpcb(tp); | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
CURVNET_SET(inp->inp_vnet); | CURVNET_SET(inp->inp_vnet); | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
KASSERT((tp->t_timers->tt_flags & TT_STOPPED) != 0, | KASSERT((tp->tt_flags & TT_STOPPED) != 0, | ||||
("%s: tcpcb has to be stopped here", __func__)); | ("%s: tcpcb has to be stopped here", __func__)); | ||||
if (--tp->t_timers->tt_draincnt > 0 || | if (--tp->tt_draincnt > 0 || | ||||
tcp_freecb(tp) == false) | tcp_freecb(tp) == false) | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
} | } | ||||
void | void | ||||
tcp_timer_stop(struct tcpcb *tp, uint32_t timer_type) | tcp_timer_stop(struct tcpcb *tp, uint32_t timer_type) | ||||
{ | { | ||||
struct callout *t_callout; | struct callout *t_callout; | ||||
tp->t_timers->tt_flags |= TT_STOPPED; | tp->tt_flags |= TT_STOPPED; | ||||
switch (timer_type) { | switch (timer_type) { | ||||
case TT_DELACK: | case TT_DELACK: | ||||
t_callout = &tp->t_timers->tt_delack; | t_callout = &tp->tt_delack; | ||||
break; | break; | ||||
case TT_REXMT: | case TT_REXMT: | ||||
t_callout = &tp->t_timers->tt_rexmt; | t_callout = &tp->tt_rexmt; | ||||
break; | break; | ||||
case TT_PERSIST: | case TT_PERSIST: | ||||
t_callout = &tp->t_timers->tt_persist; | t_callout = &tp->tt_persist; | ||||
break; | break; | ||||
case TT_KEEP: | case TT_KEEP: | ||||
t_callout = &tp->t_timers->tt_keep; | t_callout = &tp->tt_keep; | ||||
break; | break; | ||||
case TT_2MSL: | case TT_2MSL: | ||||
t_callout = &tp->t_timers->tt_2msl; | t_callout = &tp->tt_2msl; | ||||
break; | break; | ||||
default: | default: | ||||
if (tp->t_fb->tfb_tcp_timer_stop) { | if (tp->t_fb->tfb_tcp_timer_stop) { | ||||
/* | /* | ||||
* XXXrrs we need to look at this with the | * XXXrrs we need to look at this with the | ||||
* stop case below (flags). | * stop case below (flags). | ||||
*/ | */ | ||||
tp->t_fb->tfb_tcp_timer_stop(tp, timer_type); | tp->t_fb->tfb_tcp_timer_stop(tp, timer_type); | ||||
return; | return; | ||||
} | } | ||||
panic("tp %p bad timer_type %#x", tp, timer_type); | panic("tp %p bad timer_type %#x", tp, timer_type); | ||||
} | } | ||||
if (callout_async_drain(t_callout, tcp_timer_discard) == 0) { | if (callout_async_drain(t_callout, tcp_timer_discard) == 0) { | ||||
/* | /* | ||||
* Can't stop the callout, defer tcpcb actual deletion | * Can't stop the callout, defer tcpcb actual deletion | ||||
* to the last one. We do this using the async drain | * to the last one. We do this using the async drain | ||||
* function and incrementing the count in | * function and incrementing the count in | ||||
*/ | */ | ||||
tp->t_timers->tt_draincnt++; | tp->tt_draincnt++; | ||||
} | } | ||||
} | } |