Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_timer.c
Show First 20 Lines • Show All 129 Lines • ▼ Show 20 Lines | |||||
int tcp_finwait2_timeout; | int tcp_finwait2_timeout; | ||||
SYSCTL_PROC(_net_inet_tcp, OID_AUTO, finwait2_timeout, CTLTYPE_INT|CTLFLAG_RW, | SYSCTL_PROC(_net_inet_tcp, OID_AUTO, finwait2_timeout, CTLTYPE_INT|CTLFLAG_RW, | ||||
&tcp_finwait2_timeout, 0, sysctl_msec_to_ticks, "I", "FIN-WAIT2 timeout"); | &tcp_finwait2_timeout, 0, sysctl_msec_to_ticks, "I", "FIN-WAIT2 timeout"); | ||||
int tcp_keepcnt = TCPTV_KEEPCNT; | int tcp_keepcnt = TCPTV_KEEPCNT; | ||||
SYSCTL_INT(_net_inet_tcp, OID_AUTO, keepcnt, CTLFLAG_RW, &tcp_keepcnt, 0, | SYSCTL_INT(_net_inet_tcp, OID_AUTO, keepcnt, CTLFLAG_RW, &tcp_keepcnt, 0, | ||||
"Number of keepalive probes to send"); | "Number of keepalive probes to send"); | ||||
int tcp_keepslop = TCPTV_KEEPSLOP; | |||||
SYSCTL_INT(_net_inet_tcp, OID_AUTO, keepslop, CTLFLAG_RW, &tcp_keepslop, 0, | |||||
"Percentage variance allowed in the idle time (0-100)"); | |||||
tuexen: I'm wondering if it would be better to use a `SYSCTL_PROC` where a function is used to enforce… | |||||
/* max idle probes */ | /* max idle probes */ | ||||
int tcp_maxpersistidle; | int tcp_maxpersistidle; | ||||
static int tcp_rexmit_drop_options = 0; | static int tcp_rexmit_drop_options = 0; | ||||
SYSCTL_INT(_net_inet_tcp, OID_AUTO, rexmit_drop_options, CTLFLAG_RW, | SYSCTL_INT(_net_inet_tcp, OID_AUTO, rexmit_drop_options, CTLFLAG_RW, | ||||
&tcp_rexmit_drop_options, 0, | &tcp_rexmit_drop_options, 0, | ||||
"Drop TCP options from 3rd and later retransmitted SYN"); | "Drop TCP options from 3rd and later retransmitted SYN"); | ||||
▲ Show 20 Lines • Show All 270 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
void | void | ||||
tcp_timer_keep(void *xtp) | tcp_timer_keep(void *xtp) | ||||
{ | { | ||||
struct tcpcb *tp = xtp; | struct tcpcb *tp = xtp; | ||||
struct tcptemp *t_template; | struct tcptemp *t_template; | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
int earlytime, idletime; | |||||
CURVNET_SET(tp->t_vnet); | CURVNET_SET(tp->t_vnet); | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
int ostate; | int ostate; | ||||
ostate = tp->t_state; | ostate = tp->t_state; | ||||
#endif | #endif | ||||
inp = tp->t_inpcb; | inp = tp->t_inpcb; | ||||
KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); | KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); | ||||
Show All 9 Lines | if ((inp->inp_flags & INP_DROPPED) != 0) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} | } | ||||
KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, | KASSERT((tp->t_timers->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 | |||||
* the ESTABLISHED state, it may be that we don't actually need | |||||
* to send a keepalive yet. If that occurs, schedule another | |||||
* call for the next time the keepalive timer might expire. | |||||
*/ | |||||
if (TCPS_HAVEESTABLISHED(tp->t_state)) { | |||||
u_int idletime; | |||||
idletime = ticks - tp->t_rcvtime; | |||||
if (idletime < TP_KEEPIDLE(tp)) { | |||||
callout_reset(&tp->t_timers->tt_keep, | |||||
TP_KEEPIDLE(tp) - idletime, tcp_timer_keep, tp); | |||||
INP_WUNLOCK(inp); | |||||
CURVNET_RESTORE(); | |||||
return; | |||||
} | |||||
} | |||||
/* | |||||
* Keep-alive timer went off; send something | * Keep-alive timer went off; send something | ||||
* or drop connection if idle for too long. | * or drop connection if idle for too long. | ||||
*/ | */ | ||||
TCPSTAT_INC(tcps_keeptimeo); | TCPSTAT_INC(tcps_keeptimeo); | ||||
if (tp->t_state < TCPS_ESTABLISHED) | if (tp->t_state < TCPS_ESTABLISHED) | ||||
goto dropit; | goto dropit; | ||||
if ((tcp_always_keepalive || | if ((tcp_always_keepalive || | ||||
inp->inp_socket->so_options & SO_KEEPALIVE) && | inp->inp_socket->so_options & SO_KEEPALIVE) && | ||||
tp->t_state <= TCPS_CLOSING) { | tp->t_state <= TCPS_CLOSING) { | ||||
if (ticks - tp->t_rcvtime >= TP_KEEPIDLE(tp) + TP_MAXIDLE(tp)) | idletime = ticks - tp->t_rcvtime; | ||||
if (idletime >= TP_KEEPIDLE(tp) + TP_MAXIDLE(tp)) | |||||
goto dropit; | goto dropit; | ||||
/* | /* | ||||
* Because we don't regularly reset the keepalive callout in | |||||
* the ESTABLISHED state, it may be that we don't actually need | |||||
* to send a keepalive yet. If that occurs, schedule another | |||||
* call for the next time the keepalive timer might expire. | |||||
* However, to avoid unnecessarily rescheduling the keepalive | |||||
* timer to fire again in the very near future, let's proceed | |||||
* to send a keepalive early if we are "close" (as defined | |||||
* by tcp_keepslop) of the allowed time. | |||||
*/ | |||||
idletime = ticks - tp->t_rcvtime; | |||||
tuexenUnsubmitted Not Done Inline ActionsLine 477 is a duplicate of line 463. So I think line 477 can be removed. tuexen: Line 477 is a duplicate of line 463. So I think line 477 can be removed. | |||||
if (idletime < TP_KEEPIDLE(tp) - | |||||
tcp_keepslop * (TP_KEEPIDLE(tp) / 100)) { | |||||
callout_reset(&tp->t_timers->tt_keep, | |||||
TP_KEEPIDLE(tp) - idletime, tcp_timer_keep, tp); | |||||
goto done; | |||||
} else if (idletime < TP_KEEPIDLE(tp)) | |||||
earlytime = TP_KEEPIDLE(tp) - idletime; | |||||
else | |||||
earlytime = 0; | |||||
/* | |||||
* Send a packet designed to force a response | * Send a packet designed to force a response | ||||
* if the peer is up and reachable: | * if the peer is up and reachable: | ||||
* either an ACK if the connection is still alive, | * either an ACK if the connection is still alive, | ||||
* or an RST if the peer has closed the connection | * or an RST if the peer has closed the connection | ||||
* due to timeout or reboot. | * due to timeout or reboot. | ||||
* Using sequence number tp->snd_una-1 | * Using sequence number tp->snd_una-1 | ||||
* causes the transmitted zero-length segment | * causes the transmitted zero-length segment | ||||
* to lie outside the receive window; | * to lie outside the receive window; | ||||
* by the protocol spec, this requires the | * by the protocol spec, this requires the | ||||
* correspondent TCP to respond. | * correspondent TCP to respond. | ||||
*/ | */ | ||||
TCPSTAT_INC(tcps_keepprobe); | TCPSTAT_INC(tcps_keepprobe); | ||||
t_template = tcpip_maketemplate(inp); | t_template = tcpip_maketemplate(inp); | ||||
if (t_template) { | if (t_template) { | ||||
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); | ||||
free(t_template, M_TEMP); | free(t_template, M_TEMP); | ||||
} | } | ||||
callout_reset(&tp->t_timers->tt_keep, TP_KEEPINTVL(tp), | callout_reset(&tp->t_timers->tt_keep, | ||||
tcp_timer_keep, tp); | TP_KEEPINTVL(tp) + earlytime, tcp_timer_keep, tp); | ||||
} else | } else | ||||
callout_reset(&tp->t_timers->tt_keep, TP_KEEPIDLE(tp), | callout_reset(&tp->t_timers->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); | ||||
done: | |||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
dropit: | dropit: | ||||
TCPSTAT_INC(tcps_keepdrops); | TCPSTAT_INC(tcps_keepdrops); | ||||
if (tcp_inpinfo_lock_add(inp)) { | if (tcp_inpinfo_lock_add(inp)) { | ||||
▲ Show 20 Lines • Show All 469 Lines • Show Last 20 Lines |
I'm wondering if it would be better to use a SYSCTL_PROC where a function is used to enforce that tcp_keepslop is between 0 and 100. At least in some places we do input validation for sysctl-variables.