xref: /csrg-svn/sys/netiso/tp_timer.c (revision 51024)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*51024Ssklower  *	@(#)tp_timer.c	7.9 (Berkeley) 09/06/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  * Contains all the timer code.
4336415Ssklower  * There are two sources of calls to these routines:
4436415Ssklower  * the clock, and tp.trans. (ok, and tp_pcb.c calls it at init time)
4536415Ssklower  *
4636415Ssklower  * Timers come in two flavors - those that generally get
4736415Ssklower  * cancelled (tp_ctimeout, tp_cuntimeout)
4836415Ssklower  * and those that either usually expire (tp_etimeout,
4936415Ssklower  * tp_euntimeout, tp_slowtimo) or may require more than one instance
5036415Ssklower  * of the timer active at a time.
5136415Ssklower  *
5236415Ssklower  * The C timers are stored in the tp_ref structure. Their "going off"
5336415Ssklower  * is manifested by a driver event of the TM_xxx form.
5436415Ssklower  *
5536415Ssklower  * The E timers are handled like the generic kernel callouts.
5636415Ssklower  * Their "going off" is manifested by a function call w/ 3 arguments.
5736415Ssklower  */
5836415Ssklower 
5936415Ssklower #include "param.h"
6036415Ssklower #include "types.h"
6136415Ssklower #include "time.h"
6237469Ssklower #include "malloc.h"
6348752Ssklower #include "socket.h"
6436415Ssklower 
6537469Ssklower #include "tp_param.h"
6637469Ssklower #include "tp_timer.h"
6737469Ssklower #include "tp_stat.h"
6837469Ssklower #include "tp_pcb.h"
6937469Ssklower #include "tp_tpdu.h"
7037469Ssklower #include "argo_debug.h"
7137469Ssklower #include "tp_trace.h"
7237469Ssklower #include "tp_seq.h"
7336415Ssklower 
7448752Ssklower struct	Ecallout *TP_callfree;
7548752Ssklower struct	Ecallout *TP_callout;
7648752Ssklower struct	tp_ref *tp_ref;
7751007Ssklower int		N_TPREF = 127;
7851006Ssklower struct	tp_refinfo tp_refinfo;
79*51024Ssklower struct	tp_pcb *tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist;
8036415Ssklower 
8136415Ssklower /*
8236415Ssklower  * CALLED FROM:
8336415Ssklower  *  at autoconfig time from tp_init()
8436415Ssklower  * 	a combo of event, state, predicate
8536415Ssklower  * FUNCTION and ARGUMENTS:
8636415Ssklower  *  initialize data structures for the timers
8736415Ssklower  */
8836415Ssklower void
8936415Ssklower tp_timerinit()
9036415Ssklower {
9148752Ssklower 	register struct Ecallout *e;
9248752Ssklower 	register int s;
9348752Ssklower #define GETME(x, t, n) {s = (n)*sizeof(*x); x = (t) malloc(s, M_PCB, M_NOWAIT);\
9448752Ssklower if (x == 0) panic("tp_timerinit"); bzero((caddr_t)x, s);}
9536415Ssklower 	/*
9648752Ssklower 	 * Initialize storage
9736415Ssklower 	 */
9848752Ssklower 	GETME(tp_ref, struct tp_ref *, 1 +  N_TPREF);
9951006Ssklower 	tp_refinfo.tpr_base = tp_ref;
10051007Ssklower 	tp_refinfo.tpr_size = N_TPREF + 1;  /* Need to start somewhere */
10148752Ssklower #undef GETME
10236415Ssklower }
10336415Ssklower 
10436415Ssklower /**********************  e timers *************************/
10536415Ssklower 
10651007Ssklower int Enoisy = 1;
10736415Ssklower /*
10836415Ssklower  * CALLED FROM:
10936415Ssklower  *  tp.trans all over
11036415Ssklower  * FUNCTION and ARGUMENTS:
11136415Ssklower  * Set an E type timer.  (refp) is the ref structure.
11236415Ssklower  * Causes  fun(arg1,arg2,arg3) to be called after time t.
11336415Ssklower  */
11436415Ssklower void
11536415Ssklower tp_etimeout(refp, fun, arg1, arg2, arg3, ticks)
11636415Ssklower 	struct tp_ref	*refp;
11736415Ssklower 	int 			fun; 	/* function to be called */
11836415Ssklower 	u_int			arg1, arg2;
11936415Ssklower 	int				arg3;
12036415Ssklower 	register int	ticks;
12136415Ssklower {
12236415Ssklower 
12351007Ssklower 	register struct tp_pcb *tpcb = refp->tpr_pcb;
12451007Ssklower 	register struct Ccallout *callp;
12536415Ssklower 	IFDEBUG(D_TIMER)
12636415Ssklower 		printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb,
12736415Ssklower 		refp->tpr_pcb->tp_state);
12836415Ssklower 	ENDDEBUG
12936415Ssklower 	IFTRACE(D_TIMER)
13036415Ssklower 		tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref,
13136415Ssklower 		refp->tpr_state, ticks, tp_stat.ts_Eticks);
13236415Ssklower 	ENDTRACE
13351007Ssklower 	if (tpcb == 0)
13451007Ssklower 		return;
13536415Ssklower 	IncStat(ts_Eset);
13636415Ssklower 	if (ticks == 0)
13736415Ssklower 		ticks = 1;
13851007Ssklower 	if (fun == TM_data_retrans) {
13951007Ssklower 		tpcb->tp_retransargs.c_arg1 = arg1;
14051007Ssklower 		tpcb->tp_retransargs.c_arg2 = arg2;
14151007Ssklower 		tpcb->tp_retransargs.c_arg3 = arg3;
14251007Ssklower 	}
14351007Ssklower 	callp = tpcb->tp_refcallout + fun;
14451007Ssklower 	if (Enoisy && callp->c_time)
14551007Ssklower 		printf("E timer allready set: %d of ref %d\n", fun, tpcb->tp_lref);
14651007Ssklower 	if (callp->c_time == 0 || callp->c_time > ticks)
14751007Ssklower 		callp->c_time = ticks;
14836415Ssklower }
14936415Ssklower 
15036415Ssklower /*
15136415Ssklower  * CALLED FROM:
15236415Ssklower  *  tp.trans all over
15336415Ssklower  * FUNCTION and ARGUMENTS:
15436415Ssklower  *  Cancel all occurrences of E-timer function (fun) for reference (refp)
15536415Ssklower  */
15636415Ssklower void
15736415Ssklower tp_euntimeout(refp, fun)
15836415Ssklower 	struct tp_ref *refp;
15936415Ssklower 	int			  fun;
16036415Ssklower {
16151007Ssklower 	register struct tp_pcb *tpcb = refp->tpr_pcb;
16236415Ssklower 
16336415Ssklower 	IFTRACE(D_TIMER)
16436415Ssklower 		tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0);
16536415Ssklower 	ENDTRACE
16636415Ssklower 
16751007Ssklower 	if (tpcb)
16851007Ssklower 		tpcb->tp_refcallout[fun].c_time = 0;
16936415Ssklower }
17036415Ssklower 
17136415Ssklower /*
17236415Ssklower  * CALLED FROM:
17336415Ssklower  *  tp.trans, when an incoming ACK causes things to be dropped
17436415Ssklower  *  from the retransmission queue, and we want their associated
17536415Ssklower  *  timers to be cancelled.
17651007Ssklower  *  NOTE: (by sklower) only called with TM_data_retrans.
17736415Ssklower  * FUNCTION and ARGUMENTS:
17836415Ssklower  *  cancel all occurrences of function (fun) where (arg2) < (seq)
17936415Ssklower  */
18036415Ssklower void
18136415Ssklower tp_euntimeout_lss(refp, fun, seq)
18236415Ssklower 	struct tp_ref *refp;
18336415Ssklower 	int			  fun;
18436415Ssklower 	SeqNum		  seq;
18536415Ssklower {
18651007Ssklower 	register struct tp_pcb *tpcb = refp->tpr_pcb;
18736415Ssklower 
18836415Ssklower 	IFTRACE(D_TIMER)
18936415Ssklower 		tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0);
19036415Ssklower 	ENDTRACE
19136415Ssklower 
19251007Ssklower 	if (tpcb == 0 || tpcb->tp_refcallout[fun].c_time == 0)
19351007Ssklower 		return;
19451007Ssklower 	if (SEQ_LT(tpcb, tpcb->tp_retransargs.c_arg2, seq))  {
19536415Ssklower 			IncStat(ts_Ecan_act);
19651007Ssklower 			tpcb->tp_refcallout[fun].c_time = 0;
19736415Ssklower 	}
19836415Ssklower }
19936415Ssklower 
20036415Ssklower /****************  c timers **********************
20136415Ssklower  *
20236415Ssklower  * These are not chained together; they sit
20336415Ssklower  * in the tp_ref structure. they are the kind that
20436415Ssklower  * are typically cancelled so it's faster not to
20536415Ssklower  * mess with the chains
20636415Ssklower  */
20736415Ssklower 
20836415Ssklower /*
20936415Ssklower  * CALLED FROM:
21036415Ssklower  *  the clock, every 500 ms
21136415Ssklower  * FUNCTION and ARGUMENTS:
21236415Ssklower  *  Look for open references with active timers.
21336415Ssklower  *  If they exist, call the appropriate timer routines to update
21436415Ssklower  *  the timers and possibly generate events.
21536415Ssklower  *  (The E timers are done in other procedures; the C timers are
21636415Ssklower  *  updated here, and events for them are generated here.)
21736415Ssklower  */
21836415Ssklower ProtoHook
21936415Ssklower tp_slowtimo()
22036415Ssklower {
22151007Ssklower 	register struct Ccallout 	*cp, *cpbase;
22251007Ssklower 	register struct tp_ref		*rp;
22351007Ssklower 	struct tp_pcb		*tpcb;
22436415Ssklower 	struct tp_event		E;
22551007Ssklower 	int 				s = splnet(), t;
22636415Ssklower 
22736415Ssklower 	/* check only open reference structures */
22836415Ssklower 	IncStat(ts_Cticks);
22951007Ssklower 	/* tp_ref[0] is never used */
23051007Ssklower 	for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) {
23151007Ssklower 		if ((tpcb = rp->tpr_pcb) == 0 || rp->tpr_state < REF_OPEN)
23236415Ssklower 			continue;
23351007Ssklower 		cpbase = tpcb->tp_refcallout;
23451007Ssklower 		t = N_CTIMERS;
23536415Ssklower 		/* check the C-type timers */
23651007Ssklower 		for (cp = cpbase + t; (--t, --cp) >= cpbase; ) {
23751007Ssklower 			if (cp->c_time && --(cp->c_time) <= 0 ) {
23851007Ssklower 				cp->c_time = 0;
23951007Ssklower 				E.ev_number = t;
24051007Ssklower 				if (t == TM_data_retrans) {
24151007Ssklower 					register struct Ecallarg *p1 = &tpcb->tp_retransargs;
24251007Ssklower 					E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1;
24351007Ssklower 					E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2;
24451007Ssklower 					E.ATTR(TM_data_retrans).e_retrans =  p1->c_arg3;
24536415Ssklower 				}
24651007Ssklower 				IFDEBUG(D_TIMER)
24751007Ssklower 					printf("C expired! type 0x%x\n", t);
24851007Ssklower 				ENDDEBUG
24951007Ssklower 				IncStat(ts_Cexpired);
25051007Ssklower 				tp_driver( rp->tpr_pcb, &E);
25151007Ssklower 				if (t == TM_reference && tpcb->tp_state == TP_CLOSED) {
25251007Ssklower 					if (tpcb->tp_notdetached) {
25351007Ssklower 						IFDEBUG(D_CONN)
25451007Ssklower 							printf("PRU_DETACH: not detached\n");
25551007Ssklower 						ENDDEBUG
25651007Ssklower 						tp_detach(tpcb);
25751007Ssklower 					}
25851007Ssklower 					/* XXX wart; where else to do it? */
25951007Ssklower 					free((caddr_t)tpcb, M_PCB);
26051007Ssklower 				}
26136415Ssklower 			}
26236415Ssklower 		}
26336415Ssklower 	}
26436415Ssklower 	splx(s);
26536415Ssklower 	return 0;
26636415Ssklower }
26736415Ssklower 
268*51024Ssklower int
269*51024Ssklower tp_fasttimo()
270*51024Ssklower {
271*51024Ssklower 	register struct tp_pcb *t;
272*51024Ssklower 	int s = splnet();
273*51024Ssklower 	struct tp_event		E;
274*51024Ssklower 
275*51024Ssklower 	E.ev_number = TM_sendack;
276*51024Ssklower 	while ((t = tp_ftimeolist) != (struct tp_pcb *)&tp_ftimeolist) {
277*51024Ssklower 		if (t == 0) {
278*51024Ssklower 			printf("tp_fasttimeo: should panic");
279*51024Ssklower 			tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist;
280*51024Ssklower 		} else {
281*51024Ssklower 			if (t->tp_flags & TPF_DELACK) {
282*51024Ssklower 				t->tp_flags &= ~TPF_DELACK;
283*51024Ssklower 				IncStat(ts_Fdelack);
284*51024Ssklower 				tp_driver(t, &E);
285*51024Ssklower 				t->tp_refcallout[TM_sendack].c_time = t->tp_keepalive_ticks;
286*51024Ssklower 			} else
287*51024Ssklower 				IncStat(ts_Fpruned);
288*51024Ssklower 			tp_ftimeolist = t->tp_fasttimeo;
289*51024Ssklower 			t->tp_fasttimeo = 0;
290*51024Ssklower 		}
291*51024Ssklower 	}
292*51024Ssklower 	splx(s);
293*51024Ssklower }
294*51024Ssklower 
29536415Ssklower /*
29636415Ssklower  * CALLED FROM:
29736415Ssklower  *  tp.trans, tp_emit()
29836415Ssklower  * FUNCTION and ARGUMENTS:
29936415Ssklower  * 	Set a C type timer of type (which) to go off after (ticks) time.
30036415Ssklower  */
30136415Ssklower void
30236415Ssklower tp_ctimeout(refp, which, ticks)
30336415Ssklower 	register struct tp_ref	*refp;
30436415Ssklower 	int 					which, ticks;
30536415Ssklower {
30636415Ssklower 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
30736415Ssklower 
30836415Ssklower 	IFTRACE(D_TIMER)
30936415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active",
31051007Ssklower 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_time);
31136415Ssklower 	ENDTRACE
31251007Ssklower 	if(cp->c_time)
31336415Ssklower 		IncStat(ts_Ccan_act);
31436415Ssklower 	IncStat(ts_Cset);
31551007Ssklower 	if (ticks <= 0)
31651007Ssklower 		ticks = 1;
31736415Ssklower 	cp->c_time = ticks;
31836415Ssklower }
31936415Ssklower 
32036415Ssklower /*
32136415Ssklower  * CALLED FROM:
32236415Ssklower  *  tp.trans
32336415Ssklower  * FUNCTION and ARGUMENTS:
32436415Ssklower  * 	Version of tp_ctimeout that resets the C-type time if the
32536415Ssklower  * 	parameter (ticks) is > the current value of the timer.
32636415Ssklower  */
32736415Ssklower void
32836415Ssklower tp_ctimeout_MIN(refp, which, ticks)
32936415Ssklower 	register struct tp_ref	*refp;
33036415Ssklower 	int						which, ticks;
33136415Ssklower {
33236415Ssklower 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
33336415Ssklower 
33436415Ssklower 	IFTRACE(D_TIMER)
33536415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active",
33651007Ssklower 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_time);
33736415Ssklower 	ENDTRACE
33836415Ssklower 	IncStat(ts_Cset);
33951007Ssklower 	if (cp->c_time)  {
34036415Ssklower 		cp->c_time = MIN(ticks, cp->c_time);
34151007Ssklower 		IncStat(ts_Ccan_act);
34251007Ssklower 	} else
34336415Ssklower 		cp->c_time = ticks;
34436415Ssklower }
34536415Ssklower 
34636415Ssklower /*
34736415Ssklower  * CALLED FROM:
34836415Ssklower  *  tp.trans
34936415Ssklower  * FUNCTION and ARGUMENTS:
35036415Ssklower  *  Cancel the (which) timer in the ref structure indicated by (refp).
35136415Ssklower  */
35236415Ssklower void
35336415Ssklower tp_cuntimeout(refp, which)
35436415Ssklower 	int						which;
35536415Ssklower 	register struct tp_ref	*refp;
35636415Ssklower {
35736415Ssklower 	register struct Ccallout *cp;
35836415Ssklower 
35936415Ssklower 	cp = &(refp->tpr_callout[which]);
36036415Ssklower 
36136415Ssklower 	IFDEBUG(D_TIMER)
36251007Ssklower 		printf("tp_cuntimeout(0x%x, %d) active %d\n", refp, which, cp->c_time);
36336415Ssklower 	ENDDEBUG
36436415Ssklower 
36536415Ssklower 	IFTRACE(D_TIMER)
36636415Ssklower 		tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref,
36751007Ssklower 			which, cp->c_time, 0);
36836415Ssklower 	ENDTRACE
36936415Ssklower 
37051007Ssklower 	if (cp->c_time)
37136415Ssklower 		IncStat(ts_Ccan_act);
37236415Ssklower 	else
37336415Ssklower 		IncStat(ts_Ccan_inact);
37451007Ssklower 	cp->c_time = 0;
37536415Ssklower }
376