xref: /csrg-svn/sys/netiso/tp_timer.c (revision 63222)
149268Sbostic /*-
2*63222Sbostic  * Copyright (c) 1991, 1993
3*63222Sbostic  *	The Regents of the University of California.  All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*63222Sbostic  *	@(#)tp_timer.c	8.1 (Berkeley) 06/10/93
849268Sbostic  */
949268Sbostic 
1036415Ssklower /***********************************************************
1136415Ssklower 		Copyright IBM Corporation 1987
1236415Ssklower 
1336415Ssklower                       All Rights Reserved
1436415Ssklower 
1536415Ssklower Permission to use, copy, modify, and distribute this software and its
1636415Ssklower documentation for any purpose and without fee is hereby granted,
1736415Ssklower provided that the above copyright notice appear in all copies and that
1836415Ssklower both that copyright notice and this permission notice appear in
1936415Ssklower supporting documentation, and that the name of IBM not be
2036415Ssklower used in advertising or publicity pertaining to distribution of the
2136415Ssklower software without specific, written prior permission.
2236415Ssklower 
2336415Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436415Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536415Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636415Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736415Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836415Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936415Ssklower SOFTWARE.
3036415Ssklower 
3136415Ssklower ******************************************************************/
3236415Ssklower 
3336415Ssklower /*
3436415Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536415Ssklower  */
3636415Ssklower /*
3736415Ssklower  * ARGO TP
3836415Ssklower  *
3936415Ssklower  * $Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $
4036415Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_timer.c,v $
4136415Ssklower  *
4236415Ssklower  */
4336415Ssklower 
4456533Sbostic #include <sys/param.h>
4556533Sbostic #include <sys/systm.h>
4656533Sbostic #include <sys/time.h>
4756533Sbostic #include <sys/malloc.h>
4856533Sbostic #include <sys/protosw.h>
4956533Sbostic #include <sys/socket.h>
5056533Sbostic #include <sys/kernel.h>
5136415Ssklower 
5256533Sbostic #include <netiso/argo_debug.h>
5356533Sbostic #include <netiso/tp_param.h>
5456533Sbostic #include <netiso/tp_timer.h>
5556533Sbostic #include <netiso/tp_stat.h>
5656533Sbostic #include <netiso/tp_pcb.h>
5756533Sbostic #include <netiso/tp_tpdu.h>
5856533Sbostic #include <netiso/tp_trace.h>
5956533Sbostic #include <netiso/tp_seq.h>
6036415Ssklower 
6148752Ssklower struct	tp_ref *tp_ref;
6251254Ssklower int	tp_rttdiv, tp_rttadd, N_TPREF = 127;
6351006Ssklower struct	tp_refinfo tp_refinfo;
6451024Ssklower struct	tp_pcb *tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist;
6536415Ssklower 
6636415Ssklower /*
6736415Ssklower  * CALLED FROM:
6836415Ssklower  *  at autoconfig time from tp_init()
6936415Ssklower  * 	a combo of event, state, predicate
7036415Ssklower  * FUNCTION and ARGUMENTS:
7136415Ssklower  *  initialize data structures for the timers
7236415Ssklower  */
7336415Ssklower void
tp_timerinit()7436415Ssklower tp_timerinit()
7536415Ssklower {
7648752Ssklower 	register int s;
7736415Ssklower 	/*
7848752Ssklower 	 * Initialize storage
7936415Ssklower 	 */
8051254Ssklower 	if (tp_refinfo.tpr_base)
8151254Ssklower 		return;
8251204Ssklower 	tp_refinfo.tpr_size = N_TPREF + 1;  /* Need to start somewhere */
8351254Ssklower 	s = sizeof(*tp_ref) * tp_refinfo.tpr_size;
8451254Ssklower 	if ((tp_ref = (struct tp_ref *) malloc(s, M_PCB, M_NOWAIT)) == 0)
8551254Ssklower 		panic("tp_timerinit");
8651340Ssklower 	bzero((caddr_t)tp_ref, (unsigned) s);
8751006Ssklower 	tp_refinfo.tpr_base = tp_ref;
8851254Ssklower 	tp_rttdiv = hz / PR_SLOWHZ;
8951254Ssklower 	tp_rttadd = (2 * tp_rttdiv) - 1;
9036415Ssklower }
9151254Ssklower #ifdef TP_DEBUG_TIMERS
9236415Ssklower /**********************  e timers *************************/
9336415Ssklower 
9436415Ssklower /*
9536415Ssklower  * CALLED FROM:
9636415Ssklower  *  tp.trans all over
9736415Ssklower  * FUNCTION and ARGUMENTS:
9851204Ssklower  * Set an E type timer.
9936415Ssklower  */
10036415Ssklower void
tp_etimeout(tpcb,fun,ticks)10151204Ssklower tp_etimeout(tpcb, fun, ticks)
10251204Ssklower 	register struct tp_pcb	*tpcb;
10351204Ssklower 	int 					fun; 	/* function to be called */
10451204Ssklower 	int						ticks;
10536415Ssklower {
10636415Ssklower 
10751204Ssklower 	register u_int *callp;
10836415Ssklower 	IFDEBUG(D_TIMER)
10951204Ssklower 		printf("etimeout pcb 0x%x state 0x%x\n", tpcb, tpcb->tp_state);
11036415Ssklower 	ENDDEBUG
11136415Ssklower 	IFTRACE(D_TIMER)
11251204Ssklower 		tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", tpcb->tp_lref,
11351204Ssklower 		tpcb->tp_state, ticks, tp_stat.ts_Eticks);
11436415Ssklower 	ENDTRACE
11551007Ssklower 	if (tpcb == 0)
11651007Ssklower 		return;
11736415Ssklower 	IncStat(ts_Eset);
11836415Ssklower 	if (ticks == 0)
11936415Ssklower 		ticks = 1;
12051204Ssklower 	callp = tpcb->tp_timer + fun;
12151204Ssklower 	if (*callp == 0 || *callp > ticks)
12251204Ssklower 		*callp = ticks;
12336415Ssklower }
12436415Ssklower 
12536415Ssklower /*
12636415Ssklower  * CALLED FROM:
12736415Ssklower  *  tp.trans all over
12836415Ssklower  * FUNCTION and ARGUMENTS:
12936415Ssklower  *  Cancel all occurrences of E-timer function (fun) for reference (refp)
13036415Ssklower  */
13136415Ssklower void
tp_euntimeout(tpcb,fun)13251204Ssklower tp_euntimeout(tpcb, fun)
13351204Ssklower 	register struct tp_pcb	*tpcb;
13436415Ssklower 	int			  fun;
13536415Ssklower {
13636415Ssklower 	IFTRACE(D_TIMER)
13751204Ssklower 		tptrace(TPPTmisc, "tp_euntimeout ref", tpcb->tp_lref, 0, 0, 0);
13836415Ssklower 	ENDTRACE
13936415Ssklower 
14051007Ssklower 	if (tpcb)
14151204Ssklower 		tpcb->tp_timer[fun] = 0;
14236415Ssklower }
14336415Ssklower 
14436415Ssklower /****************  c timers **********************
14536415Ssklower  *
14636415Ssklower  * These are not chained together; they sit
14736415Ssklower  * in the tp_ref structure. they are the kind that
14836415Ssklower  * are typically cancelled so it's faster not to
14936415Ssklower  * mess with the chains
15036415Ssklower  */
15151254Ssklower #endif
15236415Ssklower /*
15336415Ssklower  * CALLED FROM:
15436415Ssklower  *  the clock, every 500 ms
15536415Ssklower  * FUNCTION and ARGUMENTS:
15636415Ssklower  *  Look for open references with active timers.
15736415Ssklower  *  If they exist, call the appropriate timer routines to update
15836415Ssklower  *  the timers and possibly generate events.
15936415Ssklower  */
16036415Ssklower ProtoHook
tp_slowtimo()16136415Ssklower tp_slowtimo()
16236415Ssklower {
16351340Ssklower 	register u_int 	*cp;
16451007Ssklower 	register struct tp_ref		*rp;
16551007Ssklower 	struct tp_pcb		*tpcb;
16636415Ssklower 	struct tp_event		E;
16751007Ssklower 	int 				s = splnet(), t;
16836415Ssklower 
16936415Ssklower 	/* check only open reference structures */
17036415Ssklower 	IncStat(ts_Cticks);
17151007Ssklower 	/* tp_ref[0] is never used */
17251007Ssklower 	for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) {
17351254Ssklower 		if ((tpcb = rp->tpr_pcb) == 0 || tpcb->tp_refstate < REF_OPEN)
17436415Ssklower 			continue;
17551204Ssklower 		/* check the timers */
17651340Ssklower 		for (t = 0; t < TM_NTIMERS; t++) {
17751340Ssklower 			cp = tpcb->tp_timer + t;
17851204Ssklower 			if (*cp && --(*cp) <= 0 ) {
17951204Ssklower 				*cp = 0;
18051007Ssklower 				E.ev_number = t;
18151007Ssklower 				IFDEBUG(D_TIMER)
18253681Ssklower 					printf("tp_slowtimo: pcb 0x%x t %d\n",
18353681Ssklower 							tpcb, t);
18451007Ssklower 				ENDDEBUG
18551007Ssklower 				IncStat(ts_Cexpired);
18651340Ssklower 				tp_driver(tpcb, &E);
18751007Ssklower 				if (t == TM_reference && tpcb->tp_state == TP_CLOSED) {
18851007Ssklower 					if (tpcb->tp_notdetached) {
18951007Ssklower 						IFDEBUG(D_CONN)
19051007Ssklower 							printf("PRU_DETACH: not detached\n");
19151007Ssklower 						ENDDEBUG
19251007Ssklower 						tp_detach(tpcb);
19351007Ssklower 					}
19451007Ssklower 					/* XXX wart; where else to do it? */
19551007Ssklower 					free((caddr_t)tpcb, M_PCB);
19651007Ssklower 				}
19736415Ssklower 			}
19836415Ssklower 		}
19936415Ssklower 	}
20036415Ssklower 	splx(s);
20136415Ssklower 	return 0;
20236415Ssklower }
20336415Ssklower 
20451204Ssklower /*
20551204Ssklower  * Called From: tp.trans from tp_slowtimo() -- retransmission timer went off.
20651204Ssklower  */
tp_data_retrans(tpcb)20751204Ssklower tp_data_retrans(tpcb)
20851204Ssklower register struct tp_pcb *tpcb;
20951204Ssklower {
21051204Ssklower 	int rexmt, win;
21151204Ssklower 	tpcb->tp_rttemit = 0;	/* cancel current round trip time */
21251204Ssklower 	tpcb->tp_dupacks = 0;
21351204Ssklower 	tpcb->tp_sndnxt = tpcb->tp_snduna;
21451204Ssklower 	if (tpcb->tp_fcredit == 0) {
21551204Ssklower 		/*
21651204Ssklower 		 * We transmitted new data, started timing it and the window
21751204Ssklower 		 * got shrunk under us.  This can only happen if all data
21851204Ssklower 		 * that they wanted us to send got acked, so don't
21951204Ssklower 		 * bother shrinking the congestion windows, et. al.
22051204Ssklower 		 * The retransmission timer should have been reset in goodack()
22151204Ssklower 		 */
22251340Ssklower 		IFDEBUG(D_ACKRECV)
22351340Ssklower 			printf("tp_data_retrans: 0 window tpcb 0x%x una 0x%x\n",
22451340Ssklower 				tpcb, tpcb->tp_snduna);
22551340Ssklower 		ENDDEBUG
22651204Ssklower 		tpcb->tp_rxtshift = 0;
22751204Ssklower 		tpcb->tp_timer[TM_data_retrans] = 0;
22851204Ssklower 		tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks;
22951340Ssklower 		return;
23051204Ssklower 	}
23151204Ssklower 	rexmt = tpcb->tp_dt_ticks << min(tpcb->tp_rxtshift, TP_MAXRXTSHIFT);
23251204Ssklower 	win = min(tpcb->tp_fcredit, (tpcb->tp_cong_win / tpcb->tp_l_tpdusize / 2));
23351204Ssklower 	win = max(win, 2);
23451204Ssklower 	tpcb->tp_cong_win = tpcb->tp_l_tpdusize;	/* slow start again. */
23551204Ssklower 	tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize;
23651204Ssklower 	/* We're losing; our srtt estimate is probably bogus.
23751204Ssklower 	 * Clobber it so we'll take the next rtt measurement as our srtt;
23851204Ssklower 	 * Maintain current rxt times until then.
23951204Ssklower 	 */
24051204Ssklower 	if (++tpcb->tp_rxtshift > TP_NRETRANS / 4) {
24151204Ssklower 		/* tpcb->tp_nlprotosw->nlp_losing(tpcb->tp_npcb) someday */
24251204Ssklower 		tpcb->tp_rtt = 0;
24351204Ssklower 	}
24451254Ssklower 	TP_RANGESET(tpcb->tp_rxtcur, rexmt, tpcb->tp_peer_acktime, 128);
24551254Ssklower 	tpcb->tp_timer[TM_data_retrans] = tpcb->tp_rxtcur;
24651204Ssklower 	tp_send(tpcb);
24751204Ssklower }
24851204Ssklower 
24951024Ssklower int
tp_fasttimo()25051024Ssklower tp_fasttimo()
25151024Ssklower {
25251024Ssklower 	register struct tp_pcb *t;
25351024Ssklower 	int s = splnet();
25451024Ssklower 	struct tp_event		E;
25551024Ssklower 
25651024Ssklower 	E.ev_number = TM_sendack;
25751024Ssklower 	while ((t = tp_ftimeolist) != (struct tp_pcb *)&tp_ftimeolist) {
25851024Ssklower 		if (t == 0) {
25951024Ssklower 			printf("tp_fasttimeo: should panic");
26051024Ssklower 			tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist;
26151024Ssklower 		} else {
26251024Ssklower 			if (t->tp_flags & TPF_DELACK) {
26351024Ssklower 				IncStat(ts_Fdelack);
26451024Ssklower 				tp_driver(t, &E);
26551340Ssklower 				t->tp_flags &= ~TPF_DELACK;
26651024Ssklower 			} else
26751024Ssklower 				IncStat(ts_Fpruned);
26851024Ssklower 			tp_ftimeolist = t->tp_fasttimeo;
26951024Ssklower 			t->tp_fasttimeo = 0;
27051024Ssklower 		}
27151024Ssklower 	}
27251024Ssklower 	splx(s);
27351024Ssklower }
27451024Ssklower 
27551254Ssklower #ifdef TP_DEBUG_TIMERS
27636415Ssklower /*
27736415Ssklower  * CALLED FROM:
27836415Ssklower  *  tp.trans, tp_emit()
27936415Ssklower  * FUNCTION and ARGUMENTS:
28036415Ssklower  * 	Set a C type timer of type (which) to go off after (ticks) time.
28136415Ssklower  */
28236415Ssklower void
tp_ctimeout(tpcb,which,ticks)28351204Ssklower tp_ctimeout(tpcb, which, ticks)
28451204Ssklower 	register struct tp_pcb	*tpcb;
28536415Ssklower 	int 					which, ticks;
28636415Ssklower {
28736415Ssklower 
28836415Ssklower 	IFTRACE(D_TIMER)
28936415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active",
29051204Ssklower 			tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]);
29136415Ssklower 	ENDTRACE
29251204Ssklower 	if(tpcb->tp_timer[which])
29336415Ssklower 		IncStat(ts_Ccan_act);
29436415Ssklower 	IncStat(ts_Cset);
29551007Ssklower 	if (ticks <= 0)
29651007Ssklower 		ticks = 1;
29751204Ssklower 	tpcb->tp_timer[which] = ticks;
29836415Ssklower }
29936415Ssklower 
30036415Ssklower /*
30136415Ssklower  * CALLED FROM:
30236415Ssklower  *  tp.trans
30336415Ssklower  * FUNCTION and ARGUMENTS:
30436415Ssklower  * 	Version of tp_ctimeout that resets the C-type time if the
30536415Ssklower  * 	parameter (ticks) is > the current value of the timer.
30636415Ssklower  */
30736415Ssklower void
tp_ctimeout_MIN(tpcb,which,ticks)30851204Ssklower tp_ctimeout_MIN(tpcb, which, ticks)
30951204Ssklower 	register struct tp_pcb	*tpcb;
31036415Ssklower 	int						which, ticks;
31136415Ssklower {
31236415Ssklower 	IFTRACE(D_TIMER)
31336415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active",
31451204Ssklower 			tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]);
31536415Ssklower 	ENDTRACE
31636415Ssklower 	IncStat(ts_Cset);
31751204Ssklower 	if (tpcb->tp_timer[which])  {
31856306Smckusick 		tpcb->tp_timer[which] = min(ticks, tpcb->tp_timer[which]);
31951007Ssklower 		IncStat(ts_Ccan_act);
32051007Ssklower 	} else
32151204Ssklower 		tpcb->tp_timer[which] = ticks;
32236415Ssklower }
32336415Ssklower 
32436415Ssklower /*
32536415Ssklower  * CALLED FROM:
32636415Ssklower  *  tp.trans
32736415Ssklower  * FUNCTION and ARGUMENTS:
32836415Ssklower  *  Cancel the (which) timer in the ref structure indicated by (refp).
32936415Ssklower  */
33036415Ssklower void
tp_cuntimeout(tpcb,which)33151204Ssklower tp_cuntimeout(tpcb, which)
33251204Ssklower 	register struct tp_pcb	*tpcb;
33336415Ssklower 	int						which;
33436415Ssklower {
33536415Ssklower 	IFDEBUG(D_TIMER)
33651204Ssklower 		printf("tp_cuntimeout(0x%x, %d) active %d\n",
33751204Ssklower 				tpcb, which, tpcb->tp_timer[which]);
33836415Ssklower 	ENDDEBUG
33936415Ssklower 
34036415Ssklower 	IFTRACE(D_TIMER)
34136415Ssklower 		tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref,
34251204Ssklower 			which, tpcb->tp_timer[which], 0);
34336415Ssklower 	ENDTRACE
34436415Ssklower 
34551204Ssklower 	if (tpcb->tp_timer[which])
34636415Ssklower 		IncStat(ts_Ccan_act);
34736415Ssklower 	else
34836415Ssklower 		IncStat(ts_Ccan_inact);
34951204Ssklower 	tpcb->tp_timer[which] = 0;
35036415Ssklower }
35151254Ssklower #endif
352