xref: /csrg-svn/sys/netiso/tp_timer.c (revision 51254)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*51254Ssklower  *	@(#)tp_timer.c	7.11 (Berkeley) 10/02/91
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 
4436415Ssklower #include "param.h"
45*51254Ssklower #include "systm.h"
4636415Ssklower #include "time.h"
4737469Ssklower #include "malloc.h"
48*51254Ssklower #include "protosw.h"
4948752Ssklower #include "socket.h"
50*51254Ssklower #include "kernel.h"
5136415Ssklower 
5237469Ssklower #include "tp_param.h"
5337469Ssklower #include "tp_timer.h"
5437469Ssklower #include "tp_stat.h"
5537469Ssklower #include "tp_pcb.h"
5637469Ssklower #include "tp_tpdu.h"
5737469Ssklower #include "argo_debug.h"
5837469Ssklower #include "tp_trace.h"
5937469Ssklower #include "tp_seq.h"
6036415Ssklower 
6148752Ssklower struct	tp_ref *tp_ref;
62*51254Ssklower 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
7436415Ssklower tp_timerinit()
7536415Ssklower {
7648752Ssklower 	register int s;
7736415Ssklower 	/*
7848752Ssklower 	 * Initialize storage
7936415Ssklower 	 */
80*51254Ssklower 	if (tp_refinfo.tpr_base)
81*51254Ssklower 		return;
8251204Ssklower 	tp_refinfo.tpr_size = N_TPREF + 1;  /* Need to start somewhere */
83*51254Ssklower 	s = sizeof(*tp_ref) * tp_refinfo.tpr_size;
84*51254Ssklower 	if ((tp_ref = (struct tp_ref *) malloc(s, M_PCB, M_NOWAIT)) == 0)
85*51254Ssklower 		panic("tp_timerinit");
8651006Ssklower 	tp_refinfo.tpr_base = tp_ref;
87*51254Ssklower 	tp_rttdiv = hz / PR_SLOWHZ;
88*51254Ssklower 	tp_rttadd = (2 * tp_rttdiv) - 1;
8936415Ssklower }
90*51254Ssklower #ifdef TP_DEBUG_TIMERS
9136415Ssklower /**********************  e timers *************************/
9236415Ssklower 
9336415Ssklower /*
9436415Ssklower  * CALLED FROM:
9536415Ssklower  *  tp.trans all over
9636415Ssklower  * FUNCTION and ARGUMENTS:
9751204Ssklower  * Set an E type timer.
9836415Ssklower  */
9936415Ssklower void
10051204Ssklower tp_etimeout(tpcb, fun, ticks)
10151204Ssklower 	register struct tp_pcb	*tpcb;
10251204Ssklower 	int 					fun; 	/* function to be called */
10351204Ssklower 	int						ticks;
10436415Ssklower {
10536415Ssklower 
10651204Ssklower 	register u_int *callp;
10736415Ssklower 	IFDEBUG(D_TIMER)
10851204Ssklower 		printf("etimeout pcb 0x%x state 0x%x\n", tpcb, tpcb->tp_state);
10936415Ssklower 	ENDDEBUG
11036415Ssklower 	IFTRACE(D_TIMER)
11151204Ssklower 		tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", tpcb->tp_lref,
11251204Ssklower 		tpcb->tp_state, ticks, tp_stat.ts_Eticks);
11336415Ssklower 	ENDTRACE
11451007Ssklower 	if (tpcb == 0)
11551007Ssklower 		return;
11636415Ssklower 	IncStat(ts_Eset);
11736415Ssklower 	if (ticks == 0)
11836415Ssklower 		ticks = 1;
11951204Ssklower 	callp = tpcb->tp_timer + fun;
12051204Ssklower 	if (*callp == 0 || *callp > ticks)
12151204Ssklower 		*callp = ticks;
12236415Ssklower }
12336415Ssklower 
12436415Ssklower /*
12536415Ssklower  * CALLED FROM:
12636415Ssklower  *  tp.trans all over
12736415Ssklower  * FUNCTION and ARGUMENTS:
12836415Ssklower  *  Cancel all occurrences of E-timer function (fun) for reference (refp)
12936415Ssklower  */
13036415Ssklower void
13151204Ssklower tp_euntimeout(tpcb, fun)
13251204Ssklower 	register struct tp_pcb	*tpcb;
13336415Ssklower 	int			  fun;
13436415Ssklower {
13536415Ssklower 	IFTRACE(D_TIMER)
13651204Ssklower 		tptrace(TPPTmisc, "tp_euntimeout ref", tpcb->tp_lref, 0, 0, 0);
13736415Ssklower 	ENDTRACE
13836415Ssklower 
13951007Ssklower 	if (tpcb)
14051204Ssklower 		tpcb->tp_timer[fun] = 0;
14136415Ssklower }
14236415Ssklower 
14336415Ssklower /****************  c timers **********************
14436415Ssklower  *
14536415Ssklower  * These are not chained together; they sit
14636415Ssklower  * in the tp_ref structure. they are the kind that
14736415Ssklower  * are typically cancelled so it's faster not to
14836415Ssklower  * mess with the chains
14936415Ssklower  */
150*51254Ssklower #endif
15136415Ssklower /*
15236415Ssklower  * CALLED FROM:
15336415Ssklower  *  the clock, every 500 ms
15436415Ssklower  * FUNCTION and ARGUMENTS:
15536415Ssklower  *  Look for open references with active timers.
15636415Ssklower  *  If they exist, call the appropriate timer routines to update
15736415Ssklower  *  the timers and possibly generate events.
15836415Ssklower  *  (The E timers are done in other procedures; the C timers are
15936415Ssklower  *  updated here, and events for them are generated here.)
16036415Ssklower  */
16136415Ssklower ProtoHook
16236415Ssklower tp_slowtimo()
16336415Ssklower {
16451204Ssklower 	register u_int 	*cp, *cpbase;
16551007Ssklower 	register struct tp_ref		*rp;
16651007Ssklower 	struct tp_pcb		*tpcb;
16736415Ssklower 	struct tp_event		E;
16851007Ssklower 	int 				s = splnet(), t;
16936415Ssklower 
17036415Ssklower 	/* check only open reference structures */
17136415Ssklower 	IncStat(ts_Cticks);
17251007Ssklower 	/* tp_ref[0] is never used */
17351007Ssklower 	for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) {
174*51254Ssklower 		if ((tpcb = rp->tpr_pcb) == 0 || tpcb->tp_refstate < REF_OPEN)
17536415Ssklower 			continue;
17651204Ssklower 		cpbase = tpcb->tp_timer;
17751204Ssklower 		t = TM_NTIMERS;
17851204Ssklower 		/* check the timers */
17951007Ssklower 		for (cp = cpbase + t; (--t, --cp) >= cpbase; ) {
18051204Ssklower 			if (*cp && --(*cp) <= 0 ) {
18151204Ssklower 				*cp = 0;
18251007Ssklower 				E.ev_number = t;
18351007Ssklower 				IFDEBUG(D_TIMER)
18451007Ssklower 					printf("C expired! type 0x%x\n", t);
18551007Ssklower 				ENDDEBUG
18651007Ssklower 				IncStat(ts_Cexpired);
18751007Ssklower 				tp_driver( rp->tpr_pcb, &E);
18851007Ssklower 				if (t == TM_reference && tpcb->tp_state == TP_CLOSED) {
18951007Ssklower 					if (tpcb->tp_notdetached) {
19051007Ssklower 						IFDEBUG(D_CONN)
19151007Ssklower 							printf("PRU_DETACH: not detached\n");
19251007Ssklower 						ENDDEBUG
19351007Ssklower 						tp_detach(tpcb);
19451007Ssklower 					}
19551007Ssklower 					/* XXX wart; where else to do it? */
19651007Ssklower 					free((caddr_t)tpcb, M_PCB);
19751007Ssklower 				}
19836415Ssklower 			}
19936415Ssklower 		}
20036415Ssklower 	}
20136415Ssklower 	splx(s);
20236415Ssklower 	return 0;
20336415Ssklower }
20436415Ssklower 
20551204Ssklower /*
20651204Ssklower  * Called From: tp.trans from tp_slowtimo() -- retransmission timer went off.
20751204Ssklower  */
20851204Ssklower tp_data_retrans(tpcb)
20951204Ssklower register struct tp_pcb *tpcb;
21051204Ssklower {
21151204Ssklower 	int rexmt, win;
21251204Ssklower 	tpcb->tp_rttemit = 0;	/* cancel current round trip time */
21351204Ssklower 	tpcb->tp_dupacks = 0;
21451204Ssklower 	tpcb->tp_sndnxt = tpcb->tp_snduna;
21551204Ssklower 	if (tpcb->tp_fcredit == 0) {
21651204Ssklower 		/*
21751204Ssklower 		 * We transmitted new data, started timing it and the window
21851204Ssklower 		 * got shrunk under us.  This can only happen if all data
21951204Ssklower 		 * that they wanted us to send got acked, so don't
22051204Ssklower 		 * bother shrinking the congestion windows, et. al.
22151204Ssklower 		 * The retransmission timer should have been reset in goodack()
22251204Ssklower 		 */
22351204Ssklower 		tpcb->tp_rxtshift = 0;
22451204Ssklower 		tpcb->tp_timer[TM_data_retrans] = 0;
22551204Ssklower 		tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks;
22651204Ssklower 	}
22751204Ssklower 	rexmt = tpcb->tp_dt_ticks << min(tpcb->tp_rxtshift, TP_MAXRXTSHIFT);
22851204Ssklower 	win = min(tpcb->tp_fcredit, (tpcb->tp_cong_win / tpcb->tp_l_tpdusize / 2));
22951204Ssklower 	win = max(win, 2);
23051204Ssklower 	tpcb->tp_cong_win = tpcb->tp_l_tpdusize;	/* slow start again. */
23151204Ssklower 	tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize;
23251204Ssklower 	/* We're losing; our srtt estimate is probably bogus.
23351204Ssklower 	 * Clobber it so we'll take the next rtt measurement as our srtt;
23451204Ssklower 	 * Maintain current rxt times until then.
23551204Ssklower 	 */
23651204Ssklower 	if (++tpcb->tp_rxtshift > TP_NRETRANS / 4) {
23751204Ssklower 		/* tpcb->tp_nlprotosw->nlp_losing(tpcb->tp_npcb) someday */
23851204Ssklower 		tpcb->tp_rtt = 0;
23951204Ssklower 	}
240*51254Ssklower 	TP_RANGESET(tpcb->tp_rxtcur, rexmt, tpcb->tp_peer_acktime, 128);
241*51254Ssklower 	tpcb->tp_timer[TM_data_retrans] = tpcb->tp_rxtcur;
24251204Ssklower 	tp_send(tpcb);
24351204Ssklower }
24451204Ssklower 
24551024Ssklower int
24651024Ssklower tp_fasttimo()
24751024Ssklower {
24851024Ssklower 	register struct tp_pcb *t;
24951024Ssklower 	int s = splnet();
25051024Ssklower 	struct tp_event		E;
25151024Ssklower 
25251024Ssklower 	E.ev_number = TM_sendack;
25351024Ssklower 	while ((t = tp_ftimeolist) != (struct tp_pcb *)&tp_ftimeolist) {
25451024Ssklower 		if (t == 0) {
25551024Ssklower 			printf("tp_fasttimeo: should panic");
25651024Ssklower 			tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist;
25751024Ssklower 		} else {
25851024Ssklower 			if (t->tp_flags & TPF_DELACK) {
25951024Ssklower 				t->tp_flags &= ~TPF_DELACK;
26051024Ssklower 				IncStat(ts_Fdelack);
26151024Ssklower 				tp_driver(t, &E);
26251204Ssklower 				t->tp_timer[TM_sendack] = t->tp_keepalive_ticks;
26351024Ssklower 			} else
26451024Ssklower 				IncStat(ts_Fpruned);
26551024Ssklower 			tp_ftimeolist = t->tp_fasttimeo;
26651024Ssklower 			t->tp_fasttimeo = 0;
26751024Ssklower 		}
26851024Ssklower 	}
26951024Ssklower 	splx(s);
27051024Ssklower }
27151024Ssklower 
272*51254Ssklower #ifdef TP_DEBUG_TIMERS
27336415Ssklower /*
27436415Ssklower  * CALLED FROM:
27536415Ssklower  *  tp.trans, tp_emit()
27636415Ssklower  * FUNCTION and ARGUMENTS:
27736415Ssklower  * 	Set a C type timer of type (which) to go off after (ticks) time.
27836415Ssklower  */
27936415Ssklower void
28051204Ssklower tp_ctimeout(tpcb, which, ticks)
28151204Ssklower 	register struct tp_pcb	*tpcb;
28236415Ssklower 	int 					which, ticks;
28336415Ssklower {
28436415Ssklower 
28536415Ssklower 	IFTRACE(D_TIMER)
28636415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active",
28751204Ssklower 			tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]);
28836415Ssklower 	ENDTRACE
28951204Ssklower 	if(tpcb->tp_timer[which])
29036415Ssklower 		IncStat(ts_Ccan_act);
29136415Ssklower 	IncStat(ts_Cset);
29251007Ssklower 	if (ticks <= 0)
29351007Ssklower 		ticks = 1;
29451204Ssklower 	tpcb->tp_timer[which] = ticks;
29536415Ssklower }
29636415Ssklower 
29736415Ssklower /*
29836415Ssklower  * CALLED FROM:
29936415Ssklower  *  tp.trans
30036415Ssklower  * FUNCTION and ARGUMENTS:
30136415Ssklower  * 	Version of tp_ctimeout that resets the C-type time if the
30236415Ssklower  * 	parameter (ticks) is > the current value of the timer.
30336415Ssklower  */
30436415Ssklower void
30551204Ssklower tp_ctimeout_MIN(tpcb, which, ticks)
30651204Ssklower 	register struct tp_pcb	*tpcb;
30736415Ssklower 	int						which, ticks;
30836415Ssklower {
30936415Ssklower 	IFTRACE(D_TIMER)
31036415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active",
31151204Ssklower 			tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]);
31236415Ssklower 	ENDTRACE
31336415Ssklower 	IncStat(ts_Cset);
31451204Ssklower 	if (tpcb->tp_timer[which])  {
31551204Ssklower 		tpcb->tp_timer[which] = MIN(ticks, tpcb->tp_timer[which]);
31651007Ssklower 		IncStat(ts_Ccan_act);
31751007Ssklower 	} else
31851204Ssklower 		tpcb->tp_timer[which] = ticks;
31936415Ssklower }
32036415Ssklower 
32136415Ssklower /*
32236415Ssklower  * CALLED FROM:
32336415Ssklower  *  tp.trans
32436415Ssklower  * FUNCTION and ARGUMENTS:
32536415Ssklower  *  Cancel the (which) timer in the ref structure indicated by (refp).
32636415Ssklower  */
32736415Ssklower void
32851204Ssklower tp_cuntimeout(tpcb, which)
32951204Ssklower 	register struct tp_pcb	*tpcb;
33036415Ssklower 	int						which;
33136415Ssklower {
33236415Ssklower 	IFDEBUG(D_TIMER)
33351204Ssklower 		printf("tp_cuntimeout(0x%x, %d) active %d\n",
33451204Ssklower 				tpcb, which, tpcb->tp_timer[which]);
33536415Ssklower 	ENDDEBUG
33636415Ssklower 
33736415Ssklower 	IFTRACE(D_TIMER)
33836415Ssklower 		tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref,
33951204Ssklower 			which, tpcb->tp_timer[which], 0);
34036415Ssklower 	ENDTRACE
34136415Ssklower 
34251204Ssklower 	if (tpcb->tp_timer[which])
34336415Ssklower 		IncStat(ts_Ccan_act);
34436415Ssklower 	else
34536415Ssklower 		IncStat(ts_Ccan_inact);
34651204Ssklower 	tpcb->tp_timer[which] = 0;
34736415Ssklower }
348*51254Ssklower #endif
349