xref: /csrg-svn/sys/netiso/tp_timer.c (revision 51204)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*51204Ssklower  *	@(#)tp_timer.c	7.10 (Berkeley) 09/26/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	tp_ref *tp_ref;
7551007Ssklower int		N_TPREF = 127;
7651006Ssklower struct	tp_refinfo tp_refinfo;
7751024Ssklower struct	tp_pcb *tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist;
7836415Ssklower 
7936415Ssklower /*
8036415Ssklower  * CALLED FROM:
8136415Ssklower  *  at autoconfig time from tp_init()
8236415Ssklower  * 	a combo of event, state, predicate
8336415Ssklower  * FUNCTION and ARGUMENTS:
8436415Ssklower  *  initialize data structures for the timers
8536415Ssklower  */
8636415Ssklower void
8736415Ssklower tp_timerinit()
8836415Ssklower {
8948752Ssklower 	register int s;
9048752Ssklower #define GETME(x, t, n) {s = (n)*sizeof(*x); x = (t) malloc(s, M_PCB, M_NOWAIT);\
9148752Ssklower if (x == 0) panic("tp_timerinit"); bzero((caddr_t)x, s);}
9236415Ssklower 	/*
9348752Ssklower 	 * Initialize storage
9436415Ssklower 	 */
95*51204Ssklower 	tp_refinfo.tpr_size = N_TPREF + 1;  /* Need to start somewhere */
96*51204Ssklower 	GETME(tp_ref, struct tp_ref *, tp_refinfo.tpr_size);
9751006Ssklower 	tp_refinfo.tpr_base = tp_ref;
9848752Ssklower #undef GETME
9936415Ssklower }
10036415Ssklower 
10136415Ssklower /**********************  e timers *************************/
10236415Ssklower 
10336415Ssklower /*
10436415Ssklower  * CALLED FROM:
10536415Ssklower  *  tp.trans all over
10636415Ssklower  * FUNCTION and ARGUMENTS:
107*51204Ssklower  * Set an E type timer.
10836415Ssklower  */
10936415Ssklower void
110*51204Ssklower tp_etimeout(tpcb, fun, ticks)
111*51204Ssklower 	register struct tp_pcb	*tpcb;
112*51204Ssklower 	int 					fun; 	/* function to be called */
113*51204Ssklower 	int						ticks;
11436415Ssklower {
11536415Ssklower 
116*51204Ssklower 	register u_int *callp;
11736415Ssklower 	IFDEBUG(D_TIMER)
118*51204Ssklower 		printf("etimeout pcb 0x%x state 0x%x\n", tpcb, tpcb->tp_state);
11936415Ssklower 	ENDDEBUG
12036415Ssklower 	IFTRACE(D_TIMER)
121*51204Ssklower 		tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", tpcb->tp_lref,
122*51204Ssklower 		tpcb->tp_state, ticks, tp_stat.ts_Eticks);
12336415Ssklower 	ENDTRACE
12451007Ssklower 	if (tpcb == 0)
12551007Ssklower 		return;
12636415Ssklower 	IncStat(ts_Eset);
12736415Ssklower 	if (ticks == 0)
12836415Ssklower 		ticks = 1;
129*51204Ssklower 	callp = tpcb->tp_timer + fun;
130*51204Ssklower 	if (*callp == 0 || *callp > ticks)
131*51204Ssklower 		*callp = ticks;
13236415Ssklower }
13336415Ssklower 
13436415Ssklower /*
13536415Ssklower  * CALLED FROM:
13636415Ssklower  *  tp.trans all over
13736415Ssklower  * FUNCTION and ARGUMENTS:
13836415Ssklower  *  Cancel all occurrences of E-timer function (fun) for reference (refp)
13936415Ssklower  */
14036415Ssklower void
141*51204Ssklower tp_euntimeout(tpcb, fun)
142*51204Ssklower 	register struct tp_pcb	*tpcb;
14336415Ssklower 	int			  fun;
14436415Ssklower {
14536415Ssklower 	IFTRACE(D_TIMER)
146*51204Ssklower 		tptrace(TPPTmisc, "tp_euntimeout ref", tpcb->tp_lref, 0, 0, 0);
14736415Ssklower 	ENDTRACE
14836415Ssklower 
14951007Ssklower 	if (tpcb)
150*51204Ssklower 		tpcb->tp_timer[fun] = 0;
15136415Ssklower }
15236415Ssklower 
15336415Ssklower /****************  c timers **********************
15436415Ssklower  *
15536415Ssklower  * These are not chained together; they sit
15636415Ssklower  * in the tp_ref structure. they are the kind that
15736415Ssklower  * are typically cancelled so it's faster not to
15836415Ssklower  * mess with the chains
15936415Ssklower  */
16036415Ssklower 
16136415Ssklower /*
16236415Ssklower  * CALLED FROM:
16336415Ssklower  *  the clock, every 500 ms
16436415Ssklower  * FUNCTION and ARGUMENTS:
16536415Ssklower  *  Look for open references with active timers.
16636415Ssklower  *  If they exist, call the appropriate timer routines to update
16736415Ssklower  *  the timers and possibly generate events.
16836415Ssklower  *  (The E timers are done in other procedures; the C timers are
16936415Ssklower  *  updated here, and events for them are generated here.)
17036415Ssklower  */
17136415Ssklower ProtoHook
17236415Ssklower tp_slowtimo()
17336415Ssklower {
174*51204Ssklower 	register u_int 	*cp, *cpbase;
17551007Ssklower 	register struct tp_ref		*rp;
17651007Ssklower 	struct tp_pcb		*tpcb;
17736415Ssklower 	struct tp_event		E;
17851007Ssklower 	int 				s = splnet(), t;
17936415Ssklower 
18036415Ssklower 	/* check only open reference structures */
18136415Ssklower 	IncStat(ts_Cticks);
18251007Ssklower 	/* tp_ref[0] is never used */
18351007Ssklower 	for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) {
18451007Ssklower 		if ((tpcb = rp->tpr_pcb) == 0 || rp->tpr_state < REF_OPEN)
18536415Ssklower 			continue;
186*51204Ssklower 		cpbase = tpcb->tp_timer;
187*51204Ssklower 		t = TM_NTIMERS;
188*51204Ssklower 		/* check the timers */
18951007Ssklower 		for (cp = cpbase + t; (--t, --cp) >= cpbase; ) {
190*51204Ssklower 			if (*cp && --(*cp) <= 0 ) {
191*51204Ssklower 				*cp = 0;
19251007Ssklower 				E.ev_number = t;
19351007Ssklower 				IFDEBUG(D_TIMER)
19451007Ssklower 					printf("C expired! type 0x%x\n", t);
19551007Ssklower 				ENDDEBUG
19651007Ssklower 				IncStat(ts_Cexpired);
19751007Ssklower 				tp_driver( rp->tpr_pcb, &E);
19851007Ssklower 				if (t == TM_reference && tpcb->tp_state == TP_CLOSED) {
19951007Ssklower 					if (tpcb->tp_notdetached) {
20051007Ssklower 						IFDEBUG(D_CONN)
20151007Ssklower 							printf("PRU_DETACH: not detached\n");
20251007Ssklower 						ENDDEBUG
20351007Ssklower 						tp_detach(tpcb);
20451007Ssklower 					}
20551007Ssklower 					/* XXX wart; where else to do it? */
20651007Ssklower 					free((caddr_t)tpcb, M_PCB);
20751007Ssklower 				}
20836415Ssklower 			}
20936415Ssklower 		}
21036415Ssklower 	}
21136415Ssklower 	splx(s);
21236415Ssklower 	return 0;
21336415Ssklower }
21436415Ssklower 
215*51204Ssklower /*
216*51204Ssklower  * Called From: tp.trans from tp_slowtimo() -- retransmission timer went off.
217*51204Ssklower  */
218*51204Ssklower tp_data_retrans(tpcb)
219*51204Ssklower register struct tp_pcb *tpcb;
220*51204Ssklower {
221*51204Ssklower 	int rexmt, win;
222*51204Ssklower 	tpcb->tp_rttemit = 0;	/* cancel current round trip time */
223*51204Ssklower 	tpcb->tp_dupacks = 0;
224*51204Ssklower 	tpcb->tp_sndnxt = tpcb->tp_snduna;
225*51204Ssklower 	if (tpcb->tp_fcredit == 0) {
226*51204Ssklower 		/*
227*51204Ssklower 		 * We transmitted new data, started timing it and the window
228*51204Ssklower 		 * got shrunk under us.  This can only happen if all data
229*51204Ssklower 		 * that they wanted us to send got acked, so don't
230*51204Ssklower 		 * bother shrinking the congestion windows, et. al.
231*51204Ssklower 		 * The retransmission timer should have been reset in goodack()
232*51204Ssklower 		 */
233*51204Ssklower 		tpcb->tp_rxtshift = 0;
234*51204Ssklower 		tpcb->tp_timer[TM_data_retrans] = 0;
235*51204Ssklower 		tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks;
236*51204Ssklower 	}
237*51204Ssklower 	rexmt = tpcb->tp_dt_ticks << min(tpcb->tp_rxtshift, TP_MAXRXTSHIFT);
238*51204Ssklower 	win = min(tpcb->tp_fcredit, (tpcb->tp_cong_win / tpcb->tp_l_tpdusize / 2));
239*51204Ssklower 	win = max(win, 2);
240*51204Ssklower 	tpcb->tp_cong_win = tpcb->tp_l_tpdusize;	/* slow start again. */
241*51204Ssklower 	tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize;
242*51204Ssklower 	/* We're losing; our srtt estimate is probably bogus.
243*51204Ssklower 	 * Clobber it so we'll take the next rtt measurement as our srtt;
244*51204Ssklower 	 * Maintain current rxt times until then.
245*51204Ssklower 	 */
246*51204Ssklower 	if (++tpcb->tp_rxtshift > TP_NRETRANS / 4) {
247*51204Ssklower 		/* tpcb->tp_nlprotosw->nlp_losing(tpcb->tp_npcb) someday */
248*51204Ssklower 		tpcb->tp_rtt = 0;
249*51204Ssklower 	}
250*51204Ssklower 	if (rexmt > 128)
251*51204Ssklower 		rexmt = 128; /* XXXX value from tcp_timer.h */
252*51204Ssklower 	tpcb->tp_timer[TM_data_retrans] = tpcb->tp_rxtcur = rexmt;
253*51204Ssklower 	tp_send(tpcb);
254*51204Ssklower }
255*51204Ssklower 
25651024Ssklower int
25751024Ssklower tp_fasttimo()
25851024Ssklower {
25951024Ssklower 	register struct tp_pcb *t;
26051024Ssklower 	int s = splnet();
26151024Ssklower 	struct tp_event		E;
26251024Ssklower 
26351024Ssklower 	E.ev_number = TM_sendack;
26451024Ssklower 	while ((t = tp_ftimeolist) != (struct tp_pcb *)&tp_ftimeolist) {
26551024Ssklower 		if (t == 0) {
26651024Ssklower 			printf("tp_fasttimeo: should panic");
26751024Ssklower 			tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist;
26851024Ssklower 		} else {
26951024Ssklower 			if (t->tp_flags & TPF_DELACK) {
27051024Ssklower 				t->tp_flags &= ~TPF_DELACK;
27151024Ssklower 				IncStat(ts_Fdelack);
27251024Ssklower 				tp_driver(t, &E);
273*51204Ssklower 				t->tp_timer[TM_sendack] = t->tp_keepalive_ticks;
27451024Ssklower 			} else
27551024Ssklower 				IncStat(ts_Fpruned);
27651024Ssklower 			tp_ftimeolist = t->tp_fasttimeo;
27751024Ssklower 			t->tp_fasttimeo = 0;
27851024Ssklower 		}
27951024Ssklower 	}
28051024Ssklower 	splx(s);
28151024Ssklower }
28251024Ssklower 
28336415Ssklower /*
28436415Ssklower  * CALLED FROM:
28536415Ssklower  *  tp.trans, tp_emit()
28636415Ssklower  * FUNCTION and ARGUMENTS:
28736415Ssklower  * 	Set a C type timer of type (which) to go off after (ticks) time.
28836415Ssklower  */
28936415Ssklower void
290*51204Ssklower tp_ctimeout(tpcb, which, ticks)
291*51204Ssklower 	register struct tp_pcb	*tpcb;
29236415Ssklower 	int 					which, ticks;
29336415Ssklower {
29436415Ssklower 
29536415Ssklower 	IFTRACE(D_TIMER)
29636415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active",
297*51204Ssklower 			tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]);
29836415Ssklower 	ENDTRACE
299*51204Ssklower 	if(tpcb->tp_timer[which])
30036415Ssklower 		IncStat(ts_Ccan_act);
30136415Ssklower 	IncStat(ts_Cset);
30251007Ssklower 	if (ticks <= 0)
30351007Ssklower 		ticks = 1;
304*51204Ssklower 	tpcb->tp_timer[which] = ticks;
30536415Ssklower }
30636415Ssklower 
30736415Ssklower /*
30836415Ssklower  * CALLED FROM:
30936415Ssklower  *  tp.trans
31036415Ssklower  * FUNCTION and ARGUMENTS:
31136415Ssklower  * 	Version of tp_ctimeout that resets the C-type time if the
31236415Ssklower  * 	parameter (ticks) is > the current value of the timer.
31336415Ssklower  */
31436415Ssklower void
315*51204Ssklower tp_ctimeout_MIN(tpcb, which, ticks)
316*51204Ssklower 	register struct tp_pcb	*tpcb;
31736415Ssklower 	int						which, ticks;
31836415Ssklower {
31936415Ssklower 	IFTRACE(D_TIMER)
32036415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active",
321*51204Ssklower 			tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]);
32236415Ssklower 	ENDTRACE
32336415Ssklower 	IncStat(ts_Cset);
324*51204Ssklower 	if (tpcb->tp_timer[which])  {
325*51204Ssklower 		tpcb->tp_timer[which] = MIN(ticks, tpcb->tp_timer[which]);
32651007Ssklower 		IncStat(ts_Ccan_act);
32751007Ssklower 	} else
328*51204Ssklower 		tpcb->tp_timer[which] = ticks;
32936415Ssklower }
33036415Ssklower 
33136415Ssklower /*
33236415Ssklower  * CALLED FROM:
33336415Ssklower  *  tp.trans
33436415Ssklower  * FUNCTION and ARGUMENTS:
33536415Ssklower  *  Cancel the (which) timer in the ref structure indicated by (refp).
33636415Ssklower  */
33736415Ssklower void
338*51204Ssklower tp_cuntimeout(tpcb, which)
339*51204Ssklower 	register struct tp_pcb	*tpcb;
34036415Ssklower 	int						which;
34136415Ssklower {
34236415Ssklower 	IFDEBUG(D_TIMER)
343*51204Ssklower 		printf("tp_cuntimeout(0x%x, %d) active %d\n",
344*51204Ssklower 				tpcb, which, tpcb->tp_timer[which]);
34536415Ssklower 	ENDDEBUG
34636415Ssklower 
34736415Ssklower 	IFTRACE(D_TIMER)
34836415Ssklower 		tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref,
349*51204Ssklower 			which, tpcb->tp_timer[which], 0);
35036415Ssklower 	ENDTRACE
35136415Ssklower 
352*51204Ssklower 	if (tpcb->tp_timer[which])
35336415Ssklower 		IncStat(ts_Ccan_act);
35436415Ssklower 	else
35536415Ssklower 		IncStat(ts_Ccan_inact);
356*51204Ssklower 	tpcb->tp_timer[which] = 0;
35736415Ssklower }
358