xref: /original-bsd/sys/netiso/tp_timer.c (revision 1419c09f)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)tp_timer.c	7.9 (Berkeley) 09/06/91
8  */
9 
10 /***********************************************************
11 		Copyright IBM Corporation 1987
12 
13                       All Rights Reserved
14 
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of IBM not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22 
23 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 SOFTWARE.
30 
31 ******************************************************************/
32 
33 /*
34  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
35  */
36 /*
37  * ARGO TP
38  *
39  * $Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $
40  * $Source: /usr/argo/sys/netiso/RCS/tp_timer.c,v $
41  *
42  * Contains all the timer code.
43  * There are two sources of calls to these routines:
44  * the clock, and tp.trans. (ok, and tp_pcb.c calls it at init time)
45  *
46  * Timers come in two flavors - those that generally get
47  * cancelled (tp_ctimeout, tp_cuntimeout)
48  * and those that either usually expire (tp_etimeout,
49  * tp_euntimeout, tp_slowtimo) or may require more than one instance
50  * of the timer active at a time.
51  *
52  * The C timers are stored in the tp_ref structure. Their "going off"
53  * is manifested by a driver event of the TM_xxx form.
54  *
55  * The E timers are handled like the generic kernel callouts.
56  * Their "going off" is manifested by a function call w/ 3 arguments.
57  */
58 
59 #include "param.h"
60 #include "types.h"
61 #include "time.h"
62 #include "malloc.h"
63 #include "socket.h"
64 
65 #include "tp_param.h"
66 #include "tp_timer.h"
67 #include "tp_stat.h"
68 #include "tp_pcb.h"
69 #include "tp_tpdu.h"
70 #include "argo_debug.h"
71 #include "tp_trace.h"
72 #include "tp_seq.h"
73 
74 struct	Ecallout *TP_callfree;
75 struct	Ecallout *TP_callout;
76 struct	tp_ref *tp_ref;
77 int		N_TPREF = 127;
78 struct	tp_refinfo tp_refinfo;
79 struct	tp_pcb *tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist;
80 
81 /*
82  * CALLED FROM:
83  *  at autoconfig time from tp_init()
84  * 	a combo of event, state, predicate
85  * FUNCTION and ARGUMENTS:
86  *  initialize data structures for the timers
87  */
88 void
89 tp_timerinit()
90 {
91 	register struct Ecallout *e;
92 	register int s;
93 #define GETME(x, t, n) {s = (n)*sizeof(*x); x = (t) malloc(s, M_PCB, M_NOWAIT);\
94 if (x == 0) panic("tp_timerinit"); bzero((caddr_t)x, s);}
95 	/*
96 	 * Initialize storage
97 	 */
98 	GETME(tp_ref, struct tp_ref *, 1 +  N_TPREF);
99 	tp_refinfo.tpr_base = tp_ref;
100 	tp_refinfo.tpr_size = N_TPREF + 1;  /* Need to start somewhere */
101 #undef GETME
102 }
103 
104 /**********************  e timers *************************/
105 
106 int Enoisy = 1;
107 /*
108  * CALLED FROM:
109  *  tp.trans all over
110  * FUNCTION and ARGUMENTS:
111  * Set an E type timer.  (refp) is the ref structure.
112  * Causes  fun(arg1,arg2,arg3) to be called after time t.
113  */
114 void
115 tp_etimeout(refp, fun, arg1, arg2, arg3, ticks)
116 	struct tp_ref	*refp;
117 	int 			fun; 	/* function to be called */
118 	u_int			arg1, arg2;
119 	int				arg3;
120 	register int	ticks;
121 {
122 
123 	register struct tp_pcb *tpcb = refp->tpr_pcb;
124 	register struct Ccallout *callp;
125 	IFDEBUG(D_TIMER)
126 		printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb,
127 		refp->tpr_pcb->tp_state);
128 	ENDDEBUG
129 	IFTRACE(D_TIMER)
130 		tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref,
131 		refp->tpr_state, ticks, tp_stat.ts_Eticks);
132 	ENDTRACE
133 	if (tpcb == 0)
134 		return;
135 	IncStat(ts_Eset);
136 	if (ticks == 0)
137 		ticks = 1;
138 	if (fun == TM_data_retrans) {
139 		tpcb->tp_retransargs.c_arg1 = arg1;
140 		tpcb->tp_retransargs.c_arg2 = arg2;
141 		tpcb->tp_retransargs.c_arg3 = arg3;
142 	}
143 	callp = tpcb->tp_refcallout + fun;
144 	if (Enoisy && callp->c_time)
145 		printf("E timer allready set: %d of ref %d\n", fun, tpcb->tp_lref);
146 	if (callp->c_time == 0 || callp->c_time > ticks)
147 		callp->c_time = ticks;
148 }
149 
150 /*
151  * CALLED FROM:
152  *  tp.trans all over
153  * FUNCTION and ARGUMENTS:
154  *  Cancel all occurrences of E-timer function (fun) for reference (refp)
155  */
156 void
157 tp_euntimeout(refp, fun)
158 	struct tp_ref *refp;
159 	int			  fun;
160 {
161 	register struct tp_pcb *tpcb = refp->tpr_pcb;
162 
163 	IFTRACE(D_TIMER)
164 		tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0);
165 	ENDTRACE
166 
167 	if (tpcb)
168 		tpcb->tp_refcallout[fun].c_time = 0;
169 }
170 
171 /*
172  * CALLED FROM:
173  *  tp.trans, when an incoming ACK causes things to be dropped
174  *  from the retransmission queue, and we want their associated
175  *  timers to be cancelled.
176  *  NOTE: (by sklower) only called with TM_data_retrans.
177  * FUNCTION and ARGUMENTS:
178  *  cancel all occurrences of function (fun) where (arg2) < (seq)
179  */
180 void
181 tp_euntimeout_lss(refp, fun, seq)
182 	struct tp_ref *refp;
183 	int			  fun;
184 	SeqNum		  seq;
185 {
186 	register struct tp_pcb *tpcb = refp->tpr_pcb;
187 
188 	IFTRACE(D_TIMER)
189 		tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0);
190 	ENDTRACE
191 
192 	if (tpcb == 0 || tpcb->tp_refcallout[fun].c_time == 0)
193 		return;
194 	if (SEQ_LT(tpcb, tpcb->tp_retransargs.c_arg2, seq))  {
195 			IncStat(ts_Ecan_act);
196 			tpcb->tp_refcallout[fun].c_time = 0;
197 	}
198 }
199 
200 /****************  c timers **********************
201  *
202  * These are not chained together; they sit
203  * in the tp_ref structure. they are the kind that
204  * are typically cancelled so it's faster not to
205  * mess with the chains
206  */
207 
208 /*
209  * CALLED FROM:
210  *  the clock, every 500 ms
211  * FUNCTION and ARGUMENTS:
212  *  Look for open references with active timers.
213  *  If they exist, call the appropriate timer routines to update
214  *  the timers and possibly generate events.
215  *  (The E timers are done in other procedures; the C timers are
216  *  updated here, and events for them are generated here.)
217  */
218 ProtoHook
219 tp_slowtimo()
220 {
221 	register struct Ccallout 	*cp, *cpbase;
222 	register struct tp_ref		*rp;
223 	struct tp_pcb		*tpcb;
224 	struct tp_event		E;
225 	int 				s = splnet(), t;
226 
227 	/* check only open reference structures */
228 	IncStat(ts_Cticks);
229 	/* tp_ref[0] is never used */
230 	for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) {
231 		if ((tpcb = rp->tpr_pcb) == 0 || rp->tpr_state < REF_OPEN)
232 			continue;
233 		cpbase = tpcb->tp_refcallout;
234 		t = N_CTIMERS;
235 		/* check the C-type timers */
236 		for (cp = cpbase + t; (--t, --cp) >= cpbase; ) {
237 			if (cp->c_time && --(cp->c_time) <= 0 ) {
238 				cp->c_time = 0;
239 				E.ev_number = t;
240 				if (t == TM_data_retrans) {
241 					register struct Ecallarg *p1 = &tpcb->tp_retransargs;
242 					E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1;
243 					E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2;
244 					E.ATTR(TM_data_retrans).e_retrans =  p1->c_arg3;
245 				}
246 				IFDEBUG(D_TIMER)
247 					printf("C expired! type 0x%x\n", t);
248 				ENDDEBUG
249 				IncStat(ts_Cexpired);
250 				tp_driver( rp->tpr_pcb, &E);
251 				if (t == TM_reference && tpcb->tp_state == TP_CLOSED) {
252 					if (tpcb->tp_notdetached) {
253 						IFDEBUG(D_CONN)
254 							printf("PRU_DETACH: not detached\n");
255 						ENDDEBUG
256 						tp_detach(tpcb);
257 					}
258 					/* XXX wart; where else to do it? */
259 					free((caddr_t)tpcb, M_PCB);
260 				}
261 			}
262 		}
263 	}
264 	splx(s);
265 	return 0;
266 }
267 
268 int
269 tp_fasttimo()
270 {
271 	register struct tp_pcb *t;
272 	int s = splnet();
273 	struct tp_event		E;
274 
275 	E.ev_number = TM_sendack;
276 	while ((t = tp_ftimeolist) != (struct tp_pcb *)&tp_ftimeolist) {
277 		if (t == 0) {
278 			printf("tp_fasttimeo: should panic");
279 			tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist;
280 		} else {
281 			if (t->tp_flags & TPF_DELACK) {
282 				t->tp_flags &= ~TPF_DELACK;
283 				IncStat(ts_Fdelack);
284 				tp_driver(t, &E);
285 				t->tp_refcallout[TM_sendack].c_time = t->tp_keepalive_ticks;
286 			} else
287 				IncStat(ts_Fpruned);
288 			tp_ftimeolist = t->tp_fasttimeo;
289 			t->tp_fasttimeo = 0;
290 		}
291 	}
292 	splx(s);
293 }
294 
295 /*
296  * CALLED FROM:
297  *  tp.trans, tp_emit()
298  * FUNCTION and ARGUMENTS:
299  * 	Set a C type timer of type (which) to go off after (ticks) time.
300  */
301 void
302 tp_ctimeout(refp, which, ticks)
303 	register struct tp_ref	*refp;
304 	int 					which, ticks;
305 {
306 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
307 
308 	IFTRACE(D_TIMER)
309 		tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active",
310 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_time);
311 	ENDTRACE
312 	if(cp->c_time)
313 		IncStat(ts_Ccan_act);
314 	IncStat(ts_Cset);
315 	if (ticks <= 0)
316 		ticks = 1;
317 	cp->c_time = ticks;
318 }
319 
320 /*
321  * CALLED FROM:
322  *  tp.trans
323  * FUNCTION and ARGUMENTS:
324  * 	Version of tp_ctimeout that resets the C-type time if the
325  * 	parameter (ticks) is > the current value of the timer.
326  */
327 void
328 tp_ctimeout_MIN(refp, which, ticks)
329 	register struct tp_ref	*refp;
330 	int						which, ticks;
331 {
332 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
333 
334 	IFTRACE(D_TIMER)
335 		tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active",
336 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_time);
337 	ENDTRACE
338 	IncStat(ts_Cset);
339 	if (cp->c_time)  {
340 		cp->c_time = MIN(ticks, cp->c_time);
341 		IncStat(ts_Ccan_act);
342 	} else
343 		cp->c_time = ticks;
344 }
345 
346 /*
347  * CALLED FROM:
348  *  tp.trans
349  * FUNCTION and ARGUMENTS:
350  *  Cancel the (which) timer in the ref structure indicated by (refp).
351  */
352 void
353 tp_cuntimeout(refp, which)
354 	int						which;
355 	register struct tp_ref	*refp;
356 {
357 	register struct Ccallout *cp;
358 
359 	cp = &(refp->tpr_callout[which]);
360 
361 	IFDEBUG(D_TIMER)
362 		printf("tp_cuntimeout(0x%x, %d) active %d\n", refp, which, cp->c_time);
363 	ENDDEBUG
364 
365 	IFTRACE(D_TIMER)
366 		tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref,
367 			which, cp->c_time, 0);
368 	ENDTRACE
369 
370 	if (cp->c_time)
371 		IncStat(ts_Ccan_act);
372 	else
373 		IncStat(ts_Ccan_inact);
374 	cp->c_time = 0;
375 }
376