xref: /csrg-svn/sys/netiso/tp_timer.c (revision 51007)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*51007Ssklower  *	@(#)tp_timer.c	7.8 (Berkeley) 09/05/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;
77*51007Ssklower int		N_TPREF = 127;
7851006Ssklower struct	tp_refinfo tp_refinfo;
7936415Ssklower 
8036415Ssklower /*
8136415Ssklower  * CALLED FROM:
8236415Ssklower  *  at autoconfig time from tp_init()
8336415Ssklower  * 	a combo of event, state, predicate
8436415Ssklower  * FUNCTION and ARGUMENTS:
8536415Ssklower  *  initialize data structures for the timers
8636415Ssklower  */
8736415Ssklower void
8836415Ssklower tp_timerinit()
8936415Ssklower {
9048752Ssklower 	register struct Ecallout *e;
9148752Ssklower 	register int s;
9248752Ssklower #define GETME(x, t, n) {s = (n)*sizeof(*x); x = (t) malloc(s, M_PCB, M_NOWAIT);\
9348752Ssklower if (x == 0) panic("tp_timerinit"); bzero((caddr_t)x, s);}
9436415Ssklower 	/*
9548752Ssklower 	 * Initialize storage
9636415Ssklower 	 */
9748752Ssklower 	GETME(tp_ref, struct tp_ref *, 1 +  N_TPREF);
9851006Ssklower 	tp_refinfo.tpr_base = tp_ref;
99*51007Ssklower 	tp_refinfo.tpr_size = N_TPREF + 1;  /* Need to start somewhere */
10048752Ssklower #undef GETME
10136415Ssklower }
10236415Ssklower 
10336415Ssklower /**********************  e timers *************************/
10436415Ssklower 
105*51007Ssklower int Enoisy = 1;
10636415Ssklower /*
10736415Ssklower  * CALLED FROM:
10836415Ssklower  *  tp.trans all over
10936415Ssklower  * FUNCTION and ARGUMENTS:
11036415Ssklower  * Set an E type timer.  (refp) is the ref structure.
11136415Ssklower  * Causes  fun(arg1,arg2,arg3) to be called after time t.
11236415Ssklower  */
11336415Ssklower void
11436415Ssklower tp_etimeout(refp, fun, arg1, arg2, arg3, ticks)
11536415Ssklower 	struct tp_ref	*refp;
11636415Ssklower 	int 			fun; 	/* function to be called */
11736415Ssklower 	u_int			arg1, arg2;
11836415Ssklower 	int				arg3;
11936415Ssklower 	register int	ticks;
12036415Ssklower {
12136415Ssklower 
122*51007Ssklower 	register struct tp_pcb *tpcb = refp->tpr_pcb;
123*51007Ssklower 	register struct Ccallout *callp;
12436415Ssklower 	IFDEBUG(D_TIMER)
12536415Ssklower 		printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb,
12636415Ssklower 		refp->tpr_pcb->tp_state);
12736415Ssklower 	ENDDEBUG
12836415Ssklower 	IFTRACE(D_TIMER)
12936415Ssklower 		tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref,
13036415Ssklower 		refp->tpr_state, ticks, tp_stat.ts_Eticks);
13136415Ssklower 	ENDTRACE
132*51007Ssklower 	if (tpcb == 0)
133*51007Ssklower 		return;
13436415Ssklower 	IncStat(ts_Eset);
13536415Ssklower 	if (ticks == 0)
13636415Ssklower 		ticks = 1;
137*51007Ssklower 	if (fun == TM_data_retrans) {
138*51007Ssklower 		tpcb->tp_retransargs.c_arg1 = arg1;
139*51007Ssklower 		tpcb->tp_retransargs.c_arg2 = arg2;
140*51007Ssklower 		tpcb->tp_retransargs.c_arg3 = arg3;
141*51007Ssklower 	}
142*51007Ssklower 	callp = tpcb->tp_refcallout + fun;
143*51007Ssklower 	if (Enoisy && callp->c_time)
144*51007Ssklower 		printf("E timer allready set: %d of ref %d\n", fun, tpcb->tp_lref);
145*51007Ssklower 	if (callp->c_time == 0 || callp->c_time > ticks)
146*51007Ssklower 		callp->c_time = ticks;
14736415Ssklower }
14836415Ssklower 
14936415Ssklower /*
15036415Ssklower  * CALLED FROM:
15136415Ssklower  *  tp.trans all over
15236415Ssklower  * FUNCTION and ARGUMENTS:
15336415Ssklower  *  Cancel all occurrences of E-timer function (fun) for reference (refp)
15436415Ssklower  */
15536415Ssklower void
15636415Ssklower tp_euntimeout(refp, fun)
15736415Ssklower 	struct tp_ref *refp;
15836415Ssklower 	int			  fun;
15936415Ssklower {
160*51007Ssklower 	register struct tp_pcb *tpcb = refp->tpr_pcb;
16136415Ssklower 
16236415Ssklower 	IFTRACE(D_TIMER)
16336415Ssklower 		tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0);
16436415Ssklower 	ENDTRACE
16536415Ssklower 
166*51007Ssklower 	if (tpcb)
167*51007Ssklower 		tpcb->tp_refcallout[fun].c_time = 0;
16836415Ssklower }
16936415Ssklower 
17036415Ssklower /*
17136415Ssklower  * CALLED FROM:
17236415Ssklower  *  tp.trans, when an incoming ACK causes things to be dropped
17336415Ssklower  *  from the retransmission queue, and we want their associated
17436415Ssklower  *  timers to be cancelled.
175*51007Ssklower  *  NOTE: (by sklower) only called with TM_data_retrans.
17636415Ssklower  * FUNCTION and ARGUMENTS:
17736415Ssklower  *  cancel all occurrences of function (fun) where (arg2) < (seq)
17836415Ssklower  */
17936415Ssklower void
18036415Ssklower tp_euntimeout_lss(refp, fun, seq)
18136415Ssklower 	struct tp_ref *refp;
18236415Ssklower 	int			  fun;
18336415Ssklower 	SeqNum		  seq;
18436415Ssklower {
185*51007Ssklower 	register struct tp_pcb *tpcb = refp->tpr_pcb;
18636415Ssklower 
18736415Ssklower 	IFTRACE(D_TIMER)
18836415Ssklower 		tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0);
18936415Ssklower 	ENDTRACE
19036415Ssklower 
191*51007Ssklower 	if (tpcb == 0 || tpcb->tp_refcallout[fun].c_time == 0)
192*51007Ssklower 		return;
193*51007Ssklower 	if (SEQ_LT(tpcb, tpcb->tp_retransargs.c_arg2, seq))  {
19436415Ssklower 			IncStat(ts_Ecan_act);
195*51007Ssklower 			tpcb->tp_refcallout[fun].c_time = 0;
19636415Ssklower 	}
19736415Ssklower }
19836415Ssklower 
19936415Ssklower /****************  c timers **********************
20036415Ssklower  *
20136415Ssklower  * These are not chained together; they sit
20236415Ssklower  * in the tp_ref structure. they are the kind that
20336415Ssklower  * are typically cancelled so it's faster not to
20436415Ssklower  * mess with the chains
20536415Ssklower  */
20636415Ssklower 
20736415Ssklower /*
20836415Ssklower  * CALLED FROM:
20936415Ssklower  *  the clock, every 500 ms
21036415Ssklower  * FUNCTION and ARGUMENTS:
21136415Ssklower  *  Look for open references with active timers.
21236415Ssklower  *  If they exist, call the appropriate timer routines to update
21336415Ssklower  *  the timers and possibly generate events.
21436415Ssklower  *  (The E timers are done in other procedures; the C timers are
21536415Ssklower  *  updated here, and events for them are generated here.)
21636415Ssklower  */
21736415Ssklower ProtoHook
21836415Ssklower tp_slowtimo()
21936415Ssklower {
220*51007Ssklower 	register struct Ccallout 	*cp, *cpbase;
221*51007Ssklower 	register struct tp_ref		*rp;
222*51007Ssklower 	struct tp_pcb		*tpcb;
22336415Ssklower 	struct tp_event		E;
224*51007Ssklower 	int 				s = splnet(), t;
22536415Ssklower 
22636415Ssklower 	/* check only open reference structures */
22736415Ssklower 	IncStat(ts_Cticks);
228*51007Ssklower 	/* tp_ref[0] is never used */
229*51007Ssklower 	for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) {
230*51007Ssklower 		if ((tpcb = rp->tpr_pcb) == 0 || rp->tpr_state < REF_OPEN)
23136415Ssklower 			continue;
232*51007Ssklower 		cpbase = tpcb->tp_refcallout;
233*51007Ssklower 		t = N_CTIMERS;
23436415Ssklower 		/* check the C-type timers */
235*51007Ssklower 		for (cp = cpbase + t; (--t, --cp) >= cpbase; ) {
236*51007Ssklower 			if (cp->c_time && --(cp->c_time) <= 0 ) {
237*51007Ssklower 				cp->c_time = 0;
238*51007Ssklower 				E.ev_number = t;
239*51007Ssklower 				if (t == TM_data_retrans) {
240*51007Ssklower 					register struct Ecallarg *p1 = &tpcb->tp_retransargs;
241*51007Ssklower 					E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1;
242*51007Ssklower 					E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2;
243*51007Ssklower 					E.ATTR(TM_data_retrans).e_retrans =  p1->c_arg3;
24436415Ssklower 				}
245*51007Ssklower 				IFDEBUG(D_TIMER)
246*51007Ssklower 					printf("C expired! type 0x%x\n", t);
247*51007Ssklower 				ENDDEBUG
248*51007Ssklower 				IncStat(ts_Cexpired);
249*51007Ssklower 				tp_driver( rp->tpr_pcb, &E);
250*51007Ssklower 				if (t == TM_reference && tpcb->tp_state == TP_CLOSED) {
251*51007Ssklower 					if (tpcb->tp_notdetached) {
252*51007Ssklower 						IFDEBUG(D_CONN)
253*51007Ssklower 							printf("PRU_DETACH: not detached\n");
254*51007Ssklower 						ENDDEBUG
255*51007Ssklower 						tp_detach(tpcb);
256*51007Ssklower 					}
257*51007Ssklower 					/* XXX wart; where else to do it? */
258*51007Ssklower 					free((caddr_t)tpcb, M_PCB);
259*51007Ssklower 				}
26036415Ssklower 			}
26136415Ssklower 		}
26236415Ssklower 	}
26336415Ssklower 	splx(s);
26436415Ssklower 	return 0;
26536415Ssklower }
26636415Ssklower 
26736415Ssklower /*
26836415Ssklower  * CALLED FROM:
26936415Ssklower  *  tp.trans, tp_emit()
27036415Ssklower  * FUNCTION and ARGUMENTS:
27136415Ssklower  * 	Set a C type timer of type (which) to go off after (ticks) time.
27236415Ssklower  */
27336415Ssklower void
27436415Ssklower tp_ctimeout(refp, which, ticks)
27536415Ssklower 	register struct tp_ref	*refp;
27636415Ssklower 	int 					which, ticks;
27736415Ssklower {
27836415Ssklower 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
27936415Ssklower 
28036415Ssklower 	IFTRACE(D_TIMER)
28136415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active",
282*51007Ssklower 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_time);
28336415Ssklower 	ENDTRACE
284*51007Ssklower 	if(cp->c_time)
28536415Ssklower 		IncStat(ts_Ccan_act);
28636415Ssklower 	IncStat(ts_Cset);
287*51007Ssklower 	if (ticks <= 0)
288*51007Ssklower 		ticks = 1;
28936415Ssklower 	cp->c_time = ticks;
29036415Ssklower }
29136415Ssklower 
29236415Ssklower /*
29336415Ssklower  * CALLED FROM:
29436415Ssklower  *  tp.trans
29536415Ssklower  * FUNCTION and ARGUMENTS:
29636415Ssklower  * 	Version of tp_ctimeout that resets the C-type time if the
29736415Ssklower  * 	parameter (ticks) is > the current value of the timer.
29836415Ssklower  */
29936415Ssklower void
30036415Ssklower tp_ctimeout_MIN(refp, which, ticks)
30136415Ssklower 	register struct tp_ref	*refp;
30236415Ssklower 	int						which, ticks;
30336415Ssklower {
30436415Ssklower 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
30536415Ssklower 
30636415Ssklower 	IFTRACE(D_TIMER)
30736415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active",
308*51007Ssklower 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_time);
30936415Ssklower 	ENDTRACE
31036415Ssklower 	IncStat(ts_Cset);
311*51007Ssklower 	if (cp->c_time)  {
31236415Ssklower 		cp->c_time = MIN(ticks, cp->c_time);
313*51007Ssklower 		IncStat(ts_Ccan_act);
314*51007Ssklower 	} else
31536415Ssklower 		cp->c_time = ticks;
31636415Ssklower }
31736415Ssklower 
31836415Ssklower /*
31936415Ssklower  * CALLED FROM:
32036415Ssklower  *  tp.trans
32136415Ssklower  * FUNCTION and ARGUMENTS:
32236415Ssklower  *  Cancel the (which) timer in the ref structure indicated by (refp).
32336415Ssklower  */
32436415Ssklower void
32536415Ssklower tp_cuntimeout(refp, which)
32636415Ssklower 	int						which;
32736415Ssklower 	register struct tp_ref	*refp;
32836415Ssklower {
32936415Ssklower 	register struct Ccallout *cp;
33036415Ssklower 
33136415Ssklower 	cp = &(refp->tpr_callout[which]);
33236415Ssklower 
33336415Ssklower 	IFDEBUG(D_TIMER)
334*51007Ssklower 		printf("tp_cuntimeout(0x%x, %d) active %d\n", refp, which, cp->c_time);
33536415Ssklower 	ENDDEBUG
33636415Ssklower 
33736415Ssklower 	IFTRACE(D_TIMER)
33836415Ssklower 		tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref,
339*51007Ssklower 			which, cp->c_time, 0);
34036415Ssklower 	ENDTRACE
34136415Ssklower 
342*51007Ssklower 	if (cp->c_time)
34336415Ssklower 		IncStat(ts_Ccan_act);
34436415Ssklower 	else
34536415Ssklower 		IncStat(ts_Ccan_inact);
346*51007Ssklower 	cp->c_time = 0;
34736415Ssklower }
348