Subject: Splitting up tcp_timers()
To: None <tech-net@netbsd.org>
From: Jason R Thorpe <thorpej@wasabisystems.com>
List: tech-net
Date: 09/10/2001 13:06:42
--cDtQGJ/EJIRf/Cpq
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

The following patch splits up tcp_timers() into a separate function
for each timer.  This will allow the timers to be called directly
from a callout, rather than from tcp_slowtimo().

-- 
        -- Jason R. Thorpe <thorpej@wasabisystems.com>

--cDtQGJ/EJIRf/Cpq
Content-Type: text/plain; charset=us-ascii
Content-Description: tcp_timers.diff
Content-Disposition: attachment; filename=foo

? tcp_output.c.diff
Index: tcp_timer.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/tcp_timer.c,v
retrieving revision 1.50
diff -c -r1.50 tcp_timer.c
*** tcp_timer.c	2001/09/10 15:23:10	1.50
--- tcp_timer.c	2001/09/10 20:00:41
***************
*** 102,107 ****
--- 102,108 ----
   */
  
  #include "opt_inet.h"
+ #include "opt_tcp_debug.h"
  
  #include <sys/param.h>
  #include <sys/systm.h>
***************
*** 136,141 ****
--- 137,145 ----
  #include <netinet/tcp_timer.h>
  #include <netinet/tcp_var.h>
  #include <netinet/tcpip.h>
+ #ifdef TCP_DEBUG
+ #include <netinet/tcp_debug.h>
+ #endif
  
  int	tcp_keepidle = TCPTV_KEEP_IDLE;
  int	tcp_keepintvl = TCPTV_KEEPINTVL;
***************
*** 149,154 ****
--- 153,170 ----
   */
  int	tcp_delack_ticks = 0;
  
+ void	tcp_timer_rexmt(void *);
+ void	tcp_timer_persist(void *);
+ void	tcp_timer_keep(void *);
+ void	tcp_timer_2msl(void *);
+ 
+ tcp_timer_func_t tcp_timer_funcs[TCPT_NTIMERS] = {
+ 	tcp_timer_rexmt,
+ 	tcp_timer_persist,
+ 	tcp_timer_keep,
+ 	tcp_timer_2msl,
+ };
+ 
  /*
   * Callout to process delayed ACKs for a TCPCB.
   */
***************
*** 209,218 ****
  		for (i = 0; i < TCPT_NTIMERS; i++) {
  			if (TCP_TIMER_ISEXPIRED(tp, i)) {
  				TCP_TIMER_DISARM(tp, i);
! 				(void) tcp_usrreq(tp->t_inpcb->inp_socket,
! 				    PRU_SLOWTIMO, (struct mbuf *)0,
! 				    (struct mbuf *)i, (struct mbuf *)0,
! 				    (struct proc *)0);
  				/* XXX NOT MP SAFE */
  				if ((ninp == (void *)&tcbtable.inpt_queue &&
  				    tcbtable.inpt_queue.cqh_last != inp) ||
--- 225,231 ----
  		for (i = 0; i < TCPT_NTIMERS; i++) {
  			if (TCP_TIMER_ISEXPIRED(tp, i)) {
  				TCP_TIMER_DISARM(tp, i);
! 				(*(tcp_timer_funcs[i]))(tp);
  				/* XXX NOT MP SAFE */
  				if ((ninp == (void *)&tcbtable.inpt_queue &&
  				    tcbtable.inpt_queue.cqh_last != inp) ||
***************
*** 239,248 ****
  		for (i = 0; i < TCPT_NTIMERS; i++) {
  			if (TCP_TIMER_ISEXPIRED(tp, i)) {
  				TCP_TIMER_DISARM(tp, i);
! 				(void) tcp_usrreq(tp->t_in6pcb->in6p_socket,
! 				    PRU_SLOWTIMO, (struct mbuf *)0,
! 				    (struct mbuf *)i, (struct mbuf *)0,
! 				    (struct proc *)0);
  				/* XXX NOT MP SAFE */
  				if ((nin6p == (void *)&tcb6 &&
  				    tcb6.in6p_prev != in6p) ||
--- 252,258 ----
  		for (i = 0; i < TCPT_NTIMERS; i++) {
  			if (TCP_TIMER_ISEXPIRED(tp, i)) {
  				TCP_TIMER_DISARM(tp, i);
! 				(*(tcp_timer_funcs[i]))(tp);
  				/* XXX NOT MP SAFE */
  				if ((nin6p == (void *)&tcb6 &&
  				    tcb6.in6p_prev != in6p) ||
***************
*** 289,524 ****
  /*
   * TCP timer processing.
   */
- struct tcpcb *
- tcp_timers(tp, timer)
- 	struct tcpcb *tp;
- 	int timer;
- {
- 	short	rto;
  
! #ifdef DIAGNOSTIC
! 	if (tp->t_inpcb && tp->t_in6pcb)
! 		panic("tcp_timers: both t_inpcb and t_in6pcb are set");
  #endif
  
! 	switch (timer) {
  
! 	/*
! 	 * 2 MSL timeout in shutdown went off.  If we're closed but
! 	 * still waiting for peer to close and connection has been idle
! 	 * too long, or if 2MSL time is up from TIME_WAIT, delete connection
! 	 * control block.  Otherwise, check again in a bit.
! 	 */
! 	case TCPT_2MSL:
! 		if (tp->t_state != TCPS_TIME_WAIT &&
! 		    ((tcp_maxidle == 0) ||
! 		     ((tcp_now - tp->t_rcvtime) <= tcp_maxidle)))
! 			TCP_TIMER_ARM(tp, TCPT_2MSL, tcp_keepintvl);
! 		else
! 			tp = tcp_close(tp);
! 		break;
  
  	/*
  	 * Retransmission timer went off.  Message has not
  	 * been acked within retransmit interval.  Back off
  	 * to a longer retransmit interval and retransmit one segment.
  	 */
! 	case TCPT_REXMT:
! 		if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
! 			tp->t_rxtshift = TCP_MAXRXTSHIFT;
! 			tcpstat.tcps_timeoutdrop++;
! 			tp = tcp_drop(tp, tp->t_softerror ?
! 			    tp->t_softerror : ETIMEDOUT);
! 			break;
! 		}
! 		tcpstat.tcps_rexmttimeo++;
! 		rto = TCP_REXMTVAL(tp);
! 		if (rto < tp->t_rttmin)
! 			rto = tp->t_rttmin;
! 		TCPT_RANGESET(tp->t_rxtcur, rto * tcp_backoff[tp->t_rxtshift],
! 		    tp->t_rttmin, TCPTV_REXMTMAX);
! 		TCP_TIMER_ARM(tp, TCPT_REXMT, tp->t_rxtcur);
  #if 0
! 		/* 
! 		 * If we are losing and we are trying path MTU discovery,
! 		 * try turning it off.  This will avoid black holes in
! 		 * the network which suppress or fail to send "packet
! 		 * too big" ICMP messages.  We should ideally do
! 		 * lots more sophisticated searching to find the right
! 		 * value here...
! 		 */
! 		if (ip_mtudisc && tp->t_rxtshift > TCP_MAXRXTSHIFT / 6) {
! 			struct rtentry *rt = NULL;
  
  #ifdef INET
! 			if (tp->t_inpcb)
! 				rt = in_pcbrtentry(tp->t_inpcb);
  #endif
  #ifdef INET6
! 			if (tp->t_in6pcb)
! 				rt = in6_pcbrtentry(tp->t_in6pcb);
  #endif
  
! 			/* XXX:  Black hole recovery code goes here */
! 		}
  #endif
! 		/*
! 		 * If losing, let the lower level know and try for
! 		 * a better route.  Also, if we backed off this far,
! 		 * our srtt estimate is probably bogus.  Clobber it
! 		 * so we'll take the next rtt measurement as our srtt;
! 		 * move the current srtt into rttvar to keep the current
! 		 * retransmit times until then.
! 		 */
! 		if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
  #ifdef INET
! 			if (tp->t_inpcb)
! 				in_losing(tp->t_inpcb);
  #endif
  #ifdef INET6
! 			if (tp->t_in6pcb)
! 				in6_losing(tp->t_in6pcb);
  #endif
- 			tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
- 			tp->t_srtt = 0;
- 		}
- 		tp->snd_nxt = tp->snd_una;
- 		/*
- 		 * If timing a segment in this window, stop the timer.
- 		 */
- 		tp->t_rtttime = 0;
- 		/*
- 		 * Remember if we are retransmitting a SYN, because if
- 		 * we do, set the initial congestion window must be set
- 		 * to 1 segment.
- 		 */
- 		if (tp->t_state == TCPS_SYN_SENT)
- 			tp->t_flags |= TF_SYN_REXMT;
- 		/*
- 		 * Close the congestion window down to one segment
- 		 * (we'll open it by one segment for each ack we get).
- 		 * Since we probably have a window's worth of unacked
- 		 * data accumulated, this "slow start" keeps us from
- 		 * dumping all that data as back-to-back packets (which
- 		 * might overwhelm an intermediate gateway).
- 		 *
- 		 * There are two phases to the opening: Initially we
- 		 * open by one mss on each ack.  This makes the window
- 		 * size increase exponentially with time.  If the
- 		 * window is larger than the path can handle, this
- 		 * exponential growth results in dropped packet(s)
- 		 * almost immediately.  To get more time between 
- 		 * drops but still "push" the network to take advantage
- 		 * of improving conditions, we switch from exponential
- 		 * to linear window opening at some threshhold size.
- 		 * For a threshhold, we use half the current window
- 		 * size, truncated to a multiple of the mss.
- 		 *
- 		 * (the minimum cwnd that will give us exponential
- 		 * growth is 2 mss.  We don't allow the threshhold
- 		 * to go below this.)
- 		 */
- 		{
- 		u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_segsz;
- 		if (win < 2)
- 			win = 2;
- 		/* Loss Window MUST be one segment. */
- 		tp->snd_cwnd = tp->t_segsz;
- 		tp->snd_ssthresh = win * tp->t_segsz;
- 		tp->t_dupacks = 0;
- 		}
- 		(void) tcp_output(tp);
- 		break;
  
  	/*
  	 * Persistance timer into zero window.
  	 * Force a byte to be output, if possible.
  	 */
- 	case TCPT_PERSIST:
- 		/*
- 		 * Hack: if the peer is dead/unreachable, we do not
- 		 * time out if the window is closed.  After a full
- 		 * backoff, drop the connection if the idle time
- 		 * (no responses to probes) reaches the maximum
- 		 * backoff that we would use if retransmitting.
- 		 */
- 		rto = TCP_REXMTVAL(tp);
- 		if (rto < tp->t_rttmin)
- 			rto = tp->t_rttmin;
- 		if (tp->t_rxtshift == TCP_MAXRXTSHIFT &&
- 		    ((tcp_now - tp->t_rcvtime) >= tcp_maxpersistidle ||
- 		    (tcp_now - tp->t_rcvtime) >= rto * tcp_totbackoff)) {
- 			tcpstat.tcps_persistdrops++;
- 			tp = tcp_drop(tp, ETIMEDOUT);
- 			break;
- 		}
- 		tcpstat.tcps_persisttimeo++;
- 		tcp_setpersist(tp);
- 		tp->t_force = 1;
- 		(void) tcp_output(tp);
- 		tp->t_force = 0;
- 		break;
  
  	/*
  	 * Keep-alive timer went off; send something
  	 * or drop connection if idle for too long.
  	 */
- 	case TCPT_KEEP:
- 	    {
- 		struct socket *so = NULL;
  
! 		tcpstat.tcps_keeptimeo++;
! 		if (TCPS_HAVEESTABLISHED(tp->t_state) == 0)
! 			goto dropit;
  #ifdef INET
! 		if (tp->t_inpcb)
! 			so = tp->t_inpcb->inp_socket;
  #endif
  #ifdef INET6
! 		if (tp->t_in6pcb)
! 			so = tp->t_in6pcb->in6p_socket;
  #endif
! 		if (so->so_options & SO_KEEPALIVE &&
! 		    tp->t_state <= TCPS_CLOSE_WAIT) {
! 		    	if ((tcp_maxidle > 0) &&
! 			    ((tcp_now - tp->t_rcvtime) >=
! 			     tcp_keepidle + tcp_maxidle))
! 				goto dropit;
  			/*
! 			 * Send a packet designed to force a response
! 			 * if the peer is up and reachable:
! 			 * either an ACK if the connection is still alive,
! 			 * or an RST if the peer has closed the connection
! 			 * due to timeout or reboot.
! 			 * Using sequence number tp->snd_una-1
! 			 * causes the transmitted zero-length segment
! 			 * to lie outside the receive window;
! 			 * by the protocol spec, this requires the
! 			 * correspondent TCP to respond.
  			 */
! 			tcpstat.tcps_keepprobe++;
! 			if (tcp_compat_42) {
! 				/*
! 				 * The keepalive packet must have nonzero
! 				 * length to get a 4.2 host to respond.
! 				 */
! 				(void)tcp_respond(tp, tp->t_template,
! 				    (struct mbuf *)NULL, NULL, tp->rcv_nxt - 1,
! 				    tp->snd_una - 1, 0);
! 			} else {
! 				(void)tcp_respond(tp, tp->t_template,
! 				    (struct mbuf *)NULL, NULL, tp->rcv_nxt,
! 				    tp->snd_una - 1, 0);
! 			}
! 			TCP_TIMER_ARM(tp, TCPT_KEEP, tcp_keepintvl);
! 		} else
! 			TCP_TIMER_ARM(tp, TCPT_KEEP, tcp_keepidle);
! 		break;
! 	    }
! 	dropit:
! 		tcpstat.tcps_keepdrops++;
! 		tp = tcp_drop(tp, ETIMEDOUT);
! 		break;
! 	}
! 	return (tp);
  }
--- 299,636 ----
  /*
   * TCP timer processing.
   */
  
! void
! tcp_timer_rexmt(void *arg)
! {
! 	struct tcpcb *tp = arg;
! 	uint32_t rto;
! 	int s;
! #ifdef TCP_DEBUG
! 	struct socket *so;
! 	short ostate;
  #endif
  
! 	s = splsoftnet();
  
! #ifdef TCP_DEBUG
! #ifdef INET
! 	if (tp->t_inpcb)
! 		so = tp->t_inpcb->inp_socket;
! #endif
! #ifdef INET6
! 	if (tp->t_in6pcb)
! 		so = tp->t_in6pcb->in6p_socket;
! #endif
! 	ostate = tp->t_state;
! #endif /* TCP_DEBUG */
  
  	/*
  	 * Retransmission timer went off.  Message has not
  	 * been acked within retransmit interval.  Back off
  	 * to a longer retransmit interval and retransmit one segment.
  	 */
! 
! 	if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
! 		tp->t_rxtshift = TCP_MAXRXTSHIFT;
! 		tcpstat.tcps_timeoutdrop++;
! 		tp = tcp_drop(tp, tp->t_softerror ?
! 		    tp->t_softerror : ETIMEDOUT);
! 		goto out;
! 	}
! 	tcpstat.tcps_rexmttimeo++;
! 	rto = TCP_REXMTVAL(tp);
! 	if (rto < tp->t_rttmin)
! 		rto = tp->t_rttmin;
! 	TCPT_RANGESET(tp->t_rxtcur, rto * tcp_backoff[tp->t_rxtshift],
! 	    tp->t_rttmin, TCPTV_REXMTMAX);
! 	TCP_TIMER_ARM(tp, TCPT_REXMT, tp->t_rxtcur);
  #if 0
! 	/* 
! 	 * If we are losing and we are trying path MTU discovery,
! 	 * try turning it off.  This will avoid black holes in
! 	 * the network which suppress or fail to send "packet
! 	 * too big" ICMP messages.  We should ideally do
! 	 * lots more sophisticated searching to find the right
! 	 * value here...
! 	 */
! 	if (ip_mtudisc && tp->t_rxtshift > TCP_MAXRXTSHIFT / 6) {
! 		struct rtentry *rt = NULL;
  
  #ifdef INET
! 		if (tp->t_inpcb)
! 			rt = in_pcbrtentry(tp->t_inpcb);
  #endif
  #ifdef INET6
! 		if (tp->t_in6pcb)
! 			rt = in6_pcbrtentry(tp->t_in6pcb);
  #endif
  
! 		/* XXX:  Black hole recovery code goes here */
! 	}
! #endif /* 0 */
! 	/*
! 	 * If losing, let the lower level know and try for
! 	 * a better route.  Also, if we backed off this far,
! 	 * our srtt estimate is probably bogus.  Clobber it
! 	 * so we'll take the next rtt measurement as our srtt;
! 	 * move the current srtt into rttvar to keep the current
! 	 * retransmit times until then.
! 	 */
! 	if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
! #ifdef INET
! 		if (tp->t_inpcb)
! 			in_losing(tp->t_inpcb);
  #endif
! #ifdef INET6
! 		if (tp->t_in6pcb)
! 			in6_losing(tp->t_in6pcb);
! #endif
! 		tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
! 		tp->t_srtt = 0;
! 	}
! 	tp->snd_nxt = tp->snd_una;
! 	/*
! 	 * If timing a segment in this window, stop the timer.
! 	 */
! 	tp->t_rtttime = 0;
! 	/*
! 	 * Remember if we are retransmitting a SYN, because if
! 	 * we do, set the initial congestion window must be set
! 	 * to 1 segment.
! 	 */
! 	if (tp->t_state == TCPS_SYN_SENT)
! 		tp->t_flags |= TF_SYN_REXMT;
! 	/*
! 	 * Close the congestion window down to one segment
! 	 * (we'll open it by one segment for each ack we get).
! 	 * Since we probably have a window's worth of unacked
! 	 * data accumulated, this "slow start" keeps us from
! 	 * dumping all that data as back-to-back packets (which
! 	 * might overwhelm an intermediate gateway).
! 	 *
! 	 * There are two phases to the opening: Initially we
! 	 * open by one mss on each ack.  This makes the window
! 	 * size increase exponentially with time.  If the
! 	 * window is larger than the path can handle, this
! 	 * exponential growth results in dropped packet(s)
! 	 * almost immediately.  To get more time between 
! 	 * drops but still "push" the network to take advantage
! 	 * of improving conditions, we switch from exponential
! 	 * to linear window opening at some threshhold size.
! 	 * For a threshhold, we use half the current window
! 	 * size, truncated to a multiple of the mss.
! 	 *
! 	 * (the minimum cwnd that will give us exponential
! 	 * growth is 2 mss.  We don't allow the threshhold
! 	 * to go below this.)
! 	 */
! 	{
! 	u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_segsz;
! 	if (win < 2)
! 		win = 2;
! 	/* Loss Window MUST be one segment. */
! 	tp->snd_cwnd = tp->t_segsz;
! 	tp->snd_ssthresh = win * tp->t_segsz;
! 	tp->t_dupacks = 0;
! 	}
! 	(void) tcp_output(tp);
! 
!  out:
! #ifdef TCP_DEBUG
! 	if (tp && so->so_options & SO_DEBUG)
! 		tcp_trace(TA_USER, ostate, tp, NULL,
! 		    PRU_SLOWTIMO | (TCPT_REXMT << 8));
! #endif
! 	splx(s);
! }
! 
! void
! tcp_timer_persist(void *arg)
! {
! 	struct tcpcb *tp = arg;
! 	struct socket *so;
! 	uint32_t rto;
! 	int s;
! #ifdef TCP_DEBUG
! 	short ostate;
! #endif
! 
! 	s = splsoftnet();
! 
  #ifdef INET
! 	if (tp->t_inpcb)
! 		so = tp->t_inpcb->inp_socket;
  #endif
  #ifdef INET6
! 	if (tp->t_in6pcb)
! 		so = tp->t_in6pcb->in6p_socket;
  #endif
  
+ #ifdef TCP_DEBUG
+ 	ostate = tp->t_state;
+ #endif
+ 
  	/*
  	 * Persistance timer into zero window.
  	 * Force a byte to be output, if possible.
  	 */
  
  	/*
+ 	 * Hack: if the peer is dead/unreachable, we do not
+ 	 * time out if the window is closed.  After a full
+ 	 * backoff, drop the connection if the idle time
+ 	 * (no responses to probes) reaches the maximum
+ 	 * backoff that we would use if retransmitting.
+ 	 */
+ 	rto = TCP_REXMTVAL(tp);
+ 	if (rto < tp->t_rttmin)
+ 		rto = tp->t_rttmin;
+ 	if (tp->t_rxtshift == TCP_MAXRXTSHIFT &&
+ 	    ((tcp_now - tp->t_rcvtime) >= tcp_maxpersistidle ||
+ 	    (tcp_now - tp->t_rcvtime) >= rto * tcp_totbackoff)) {
+ 		tcpstat.tcps_persistdrops++;
+ 		tp = tcp_drop(tp, ETIMEDOUT);
+ 		goto out;
+ 	}
+ 	tcpstat.tcps_persisttimeo++;
+ 	tcp_setpersist(tp);
+ 	tp->t_force = 1;
+ 	(void) tcp_output(tp);
+ 	tp->t_force = 0;
+ 
+  out:
+ #ifdef TCP_DEBUG
+ 	if (tp && so->so_options & SO_DEBUG)
+ 		tcp_trace(TA_USER, ostate, tp, NULL,
+ 		    PRU_SLOWTIMO | (TCPT_PERSIST << 8));
+ #endif
+ 	splx(s);
+ }
+ 
+ void
+ tcp_timer_keep(void *arg)
+ {
+ 	struct tcpcb *tp = arg;
+ 	struct socket *so;
+ 	int s;
+ #ifdef TCP_DEBUG
+ 	short ostate;
+ #endif
+ 
+ 	s = splsoftnet();
+ 
+ #ifdef TCP_DEBUG
+ 	ostate = tp->t_state;
+ #endif /* TCP_DEBUG */
+ 
+ 	/*
  	 * Keep-alive timer went off; send something
  	 * or drop connection if idle for too long.
  	 */
  
! 	tcpstat.tcps_keeptimeo++;
! 	if (TCPS_HAVEESTABLISHED(tp->t_state) == 0)
! 		goto dropit;
  #ifdef INET
! 	if (tp->t_inpcb)
! 		so = tp->t_inpcb->inp_socket;
  #endif
  #ifdef INET6
! 	if (tp->t_in6pcb)
! 		so = tp->t_in6pcb->in6p_socket;
  #endif
! 	if (so->so_options & SO_KEEPALIVE &&
! 	    tp->t_state <= TCPS_CLOSE_WAIT) {
! 	    	if ((tcp_maxidle > 0) &&
! 		    ((tcp_now - tp->t_rcvtime) >=
! 		     tcp_keepidle + tcp_maxidle))
! 			goto dropit;
! 		/*
! 		 * Send a packet designed to force a response
! 		 * if the peer is up and reachable:
! 		 * either an ACK if the connection is still alive,
! 		 * or an RST if the peer has closed the connection
! 		 * due to timeout or reboot.
! 		 * Using sequence number tp->snd_una-1
! 		 * causes the transmitted zero-length segment
! 		 * to lie outside the receive window;
! 		 * by the protocol spec, this requires the
! 		 * correspondent TCP to respond.
! 		 */
! 		tcpstat.tcps_keepprobe++;
! 		if (tcp_compat_42) {
  			/*
! 			 * The keepalive packet must have nonzero
! 			 * length to get a 4.2 host to respond.
  			 */
! 			(void)tcp_respond(tp, tp->t_template,
! 			    (struct mbuf *)NULL, NULL, tp->rcv_nxt - 1,
! 			    tp->snd_una - 1, 0);
! 		} else {
! 			(void)tcp_respond(tp, tp->t_template,
! 			    (struct mbuf *)NULL, NULL, tp->rcv_nxt,
! 			    tp->snd_una - 1, 0);
! 		}
! 		TCP_TIMER_ARM(tp, TCPT_KEEP, tcp_keepintvl);
! 	} else
! 		TCP_TIMER_ARM(tp, TCPT_KEEP, tcp_keepidle);
! 
! #ifdef TCP_DEBUG
! 	if (tp && so->so_options & SO_DEBUG)
! 		tcp_trace(TA_USER, ostate, tp, NULL,
! 		    PRU_SLOWTIMO | (TCPT_KEEP << 8));
! #endif
! 	splx(s);
! 	return;
! 
!  dropit:
! 	tcpstat.tcps_keepdrops++;
! 	(void) tcp_drop(tp, ETIMEDOUT);
! 	splx(s);
! }
! 
! void
! tcp_timer_2msl(void *arg)
! {
! 	struct tcpcb *tp = arg;
! 	struct socket *so;
! 	int s;
! #ifdef TCP_DEBUG
! 	short ostate;
! #endif
! 
! 	s = splsoftnet();
! 
! #ifdef INET
! 	if (tp->t_inpcb)
! 		so = tp->t_inpcb->inp_socket;
! #endif
! #ifdef INET6
! 	if (tp->t_in6pcb)
! 		so = tp->t_in6pcb->in6p_socket;
! #endif
! 
! #ifdef TCP_DEBUG
! 	ostate = tp->t_state;
! #endif
! 
! 	/*
! 	 * 2 MSL timeout in shutdown went off.  If we're closed but
! 	 * still waiting for peer to close and connection has been idle
! 	 * too long, or if 2MSL time is up from TIME_WAIT, delete connection
! 	 * control block.  Otherwise, check again in a bit.
! 	 */
! 	if (tp->t_state != TCPS_TIME_WAIT &&
! 	    ((tcp_maxidle == 0) || ((tcp_now - tp->t_rcvtime) <= tcp_maxidle)))
! 		TCP_TIMER_ARM(tp, TCPT_2MSL, tcp_keepintvl);
! 	else
! 		tp = tcp_close(tp);
! 
! #ifdef TCP_DEBUG
! 	if (tp && so->so_options & SO_DEBUG)
! 		tcp_trace(TA_USER, ostate, tp, NULL,
! 		    PRU_SLOWTIMO | (TCPT_2MSL << 8));
! #endif
! 	splx(s);
  }
Index: tcp_timer.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/tcp_timer.h,v
retrieving revision 1.11
diff -c -r1.11 tcp_timer.h
*** tcp_timer.h	2001/09/10 04:24:25	1.11
--- tcp_timer.h	2001/09/10 20:00:41
***************
*** 142,147 ****
--- 142,151 ----
  }
  
  #ifdef _KERNEL
+ typedef void (*tcp_timer_func_t)(void *);
+ 
+ extern tcp_timer_func_t tcp_timer_funcs[TCPT_NTIMERS];
+ 
  extern int tcp_keepidle;		/* time before keepalive probes begin */
  extern int tcp_keepintvl;		/* time between keepalive probes */
  extern int tcp_keepcnt;			/* number of keepalives, 0=infty */
Index: tcp_usrreq.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/tcp_usrreq.c,v
retrieving revision 1.64
diff -c -r1.64 tcp_usrreq.c
*** tcp_usrreq.c	2001/07/25 23:28:02	1.64
--- tcp_usrreq.c	2001/09/10 20:00:42
***************
*** 594,608 ****
  #endif
  		break;
  
- 	/*
- 	 * TCP slow timer went off; going through this
- 	 * routine for tracing's sake.
- 	 */
- 	case PRU_SLOWTIMO:
- 		tp = tcp_timers(tp, (long)nam);
- 		req |= (long)nam << 8;		/* for debug's sake */
- 		break;
- 
  	default:
  		panic("tcp_usrreq");
  	}
--- 594,599 ----
Index: tcp_var.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/tcp_var.h,v
retrieving revision 1.84
diff -c -r1.84 tcp_var.h
*** tcp_var.h	2001/09/10 15:23:11	1.84
--- tcp_var.h	2001/09/10 20:00:43
***************
*** 694,701 ****
  void	 tcp_slowtimo __P((void));
  struct mbuf *
  	 tcp_template __P((struct tcpcb *));
- struct tcpcb *
- 	 tcp_timers __P((struct tcpcb *, int));
  void	 tcp_trace __P((int, int, struct tcpcb *, struct mbuf *, int));
  struct tcpcb *
  	 tcp_usrclosed __P((struct tcpcb *));
--- 694,699 ----

--cDtQGJ/EJIRf/Cpq--