xref: /csrg-svn/sys/netiso/tp_timer.c (revision 51204)
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.10 (Berkeley) 09/26/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	tp_ref *tp_ref;
75 int		N_TPREF = 127;
76 struct	tp_refinfo tp_refinfo;
77 struct	tp_pcb *tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist;
78 
79 /*
80  * CALLED FROM:
81  *  at autoconfig time from tp_init()
82  * 	a combo of event, state, predicate
83  * FUNCTION and ARGUMENTS:
84  *  initialize data structures for the timers
85  */
86 void
87 tp_timerinit()
88 {
89 	register int s;
90 #define GETME(x, t, n) {s = (n)*sizeof(*x); x = (t) malloc(s, M_PCB, M_NOWAIT);\
91 if (x == 0) panic("tp_timerinit"); bzero((caddr_t)x, s);}
92 	/*
93 	 * Initialize storage
94 	 */
95 	tp_refinfo.tpr_size = N_TPREF + 1;  /* Need to start somewhere */
96 	GETME(tp_ref, struct tp_ref *, tp_refinfo.tpr_size);
97 	tp_refinfo.tpr_base = tp_ref;
98 #undef GETME
99 }
100 
101 /**********************  e timers *************************/
102 
103 /*
104  * CALLED FROM:
105  *  tp.trans all over
106  * FUNCTION and ARGUMENTS:
107  * Set an E type timer.
108  */
109 void
110 tp_etimeout(tpcb, fun, ticks)
111 	register struct tp_pcb	*tpcb;
112 	int 					fun; 	/* function to be called */
113 	int						ticks;
114 {
115 
116 	register u_int *callp;
117 	IFDEBUG(D_TIMER)
118 		printf("etimeout pcb 0x%x state 0x%x\n", tpcb, tpcb->tp_state);
119 	ENDDEBUG
120 	IFTRACE(D_TIMER)
121 		tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", tpcb->tp_lref,
122 		tpcb->tp_state, ticks, tp_stat.ts_Eticks);
123 	ENDTRACE
124 	if (tpcb == 0)
125 		return;
126 	IncStat(ts_Eset);
127 	if (ticks == 0)
128 		ticks = 1;
129 	callp = tpcb->tp_timer + fun;
130 	if (*callp == 0 || *callp > ticks)
131 		*callp = ticks;
132 }
133 
134 /*
135  * CALLED FROM:
136  *  tp.trans all over
137  * FUNCTION and ARGUMENTS:
138  *  Cancel all occurrences of E-timer function (fun) for reference (refp)
139  */
140 void
141 tp_euntimeout(tpcb, fun)
142 	register struct tp_pcb	*tpcb;
143 	int			  fun;
144 {
145 	IFTRACE(D_TIMER)
146 		tptrace(TPPTmisc, "tp_euntimeout ref", tpcb->tp_lref, 0, 0, 0);
147 	ENDTRACE
148 
149 	if (tpcb)
150 		tpcb->tp_timer[fun] = 0;
151 }
152 
153 /****************  c timers **********************
154  *
155  * These are not chained together; they sit
156  * in the tp_ref structure. they are the kind that
157  * are typically cancelled so it's faster not to
158  * mess with the chains
159  */
160 
161 /*
162  * CALLED FROM:
163  *  the clock, every 500 ms
164  * FUNCTION and ARGUMENTS:
165  *  Look for open references with active timers.
166  *  If they exist, call the appropriate timer routines to update
167  *  the timers and possibly generate events.
168  *  (The E timers are done in other procedures; the C timers are
169  *  updated here, and events for them are generated here.)
170  */
171 ProtoHook
172 tp_slowtimo()
173 {
174 	register u_int 	*cp, *cpbase;
175 	register struct tp_ref		*rp;
176 	struct tp_pcb		*tpcb;
177 	struct tp_event		E;
178 	int 				s = splnet(), t;
179 
180 	/* check only open reference structures */
181 	IncStat(ts_Cticks);
182 	/* tp_ref[0] is never used */
183 	for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) {
184 		if ((tpcb = rp->tpr_pcb) == 0 || rp->tpr_state < REF_OPEN)
185 			continue;
186 		cpbase = tpcb->tp_timer;
187 		t = TM_NTIMERS;
188 		/* check the timers */
189 		for (cp = cpbase + t; (--t, --cp) >= cpbase; ) {
190 			if (*cp && --(*cp) <= 0 ) {
191 				*cp = 0;
192 				E.ev_number = t;
193 				IFDEBUG(D_TIMER)
194 					printf("C expired! type 0x%x\n", t);
195 				ENDDEBUG
196 				IncStat(ts_Cexpired);
197 				tp_driver( rp->tpr_pcb, &E);
198 				if (t == TM_reference && tpcb->tp_state == TP_CLOSED) {
199 					if (tpcb->tp_notdetached) {
200 						IFDEBUG(D_CONN)
201 							printf("PRU_DETACH: not detached\n");
202 						ENDDEBUG
203 						tp_detach(tpcb);
204 					}
205 					/* XXX wart; where else to do it? */
206 					free((caddr_t)tpcb, M_PCB);
207 				}
208 			}
209 		}
210 	}
211 	splx(s);
212 	return 0;
213 }
214 
215 /*
216  * Called From: tp.trans from tp_slowtimo() -- retransmission timer went off.
217  */
218 tp_data_retrans(tpcb)
219 register struct tp_pcb *tpcb;
220 {
221 	int rexmt, win;
222 	tpcb->tp_rttemit = 0;	/* cancel current round trip time */
223 	tpcb->tp_dupacks = 0;
224 	tpcb->tp_sndnxt = tpcb->tp_snduna;
225 	if (tpcb->tp_fcredit == 0) {
226 		/*
227 		 * We transmitted new data, started timing it and the window
228 		 * got shrunk under us.  This can only happen if all data
229 		 * that they wanted us to send got acked, so don't
230 		 * bother shrinking the congestion windows, et. al.
231 		 * The retransmission timer should have been reset in goodack()
232 		 */
233 		tpcb->tp_rxtshift = 0;
234 		tpcb->tp_timer[TM_data_retrans] = 0;
235 		tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks;
236 	}
237 	rexmt = tpcb->tp_dt_ticks << min(tpcb->tp_rxtshift, TP_MAXRXTSHIFT);
238 	win = min(tpcb->tp_fcredit, (tpcb->tp_cong_win / tpcb->tp_l_tpdusize / 2));
239 	win = max(win, 2);
240 	tpcb->tp_cong_win = tpcb->tp_l_tpdusize;	/* slow start again. */
241 	tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize;
242 	/* We're losing; our srtt estimate is probably bogus.
243 	 * Clobber it so we'll take the next rtt measurement as our srtt;
244 	 * Maintain current rxt times until then.
245 	 */
246 	if (++tpcb->tp_rxtshift > TP_NRETRANS / 4) {
247 		/* tpcb->tp_nlprotosw->nlp_losing(tpcb->tp_npcb) someday */
248 		tpcb->tp_rtt = 0;
249 	}
250 	if (rexmt > 128)
251 		rexmt = 128; /* XXXX value from tcp_timer.h */
252 	tpcb->tp_timer[TM_data_retrans] = tpcb->tp_rxtcur = rexmt;
253 	tp_send(tpcb);
254 }
255 
256 int
257 tp_fasttimo()
258 {
259 	register struct tp_pcb *t;
260 	int s = splnet();
261 	struct tp_event		E;
262 
263 	E.ev_number = TM_sendack;
264 	while ((t = tp_ftimeolist) != (struct tp_pcb *)&tp_ftimeolist) {
265 		if (t == 0) {
266 			printf("tp_fasttimeo: should panic");
267 			tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist;
268 		} else {
269 			if (t->tp_flags & TPF_DELACK) {
270 				t->tp_flags &= ~TPF_DELACK;
271 				IncStat(ts_Fdelack);
272 				tp_driver(t, &E);
273 				t->tp_timer[TM_sendack] = t->tp_keepalive_ticks;
274 			} else
275 				IncStat(ts_Fpruned);
276 			tp_ftimeolist = t->tp_fasttimeo;
277 			t->tp_fasttimeo = 0;
278 		}
279 	}
280 	splx(s);
281 }
282 
283 /*
284  * CALLED FROM:
285  *  tp.trans, tp_emit()
286  * FUNCTION and ARGUMENTS:
287  * 	Set a C type timer of type (which) to go off after (ticks) time.
288  */
289 void
290 tp_ctimeout(tpcb, which, ticks)
291 	register struct tp_pcb	*tpcb;
292 	int 					which, ticks;
293 {
294 
295 	IFTRACE(D_TIMER)
296 		tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active",
297 			tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]);
298 	ENDTRACE
299 	if(tpcb->tp_timer[which])
300 		IncStat(ts_Ccan_act);
301 	IncStat(ts_Cset);
302 	if (ticks <= 0)
303 		ticks = 1;
304 	tpcb->tp_timer[which] = ticks;
305 }
306 
307 /*
308  * CALLED FROM:
309  *  tp.trans
310  * FUNCTION and ARGUMENTS:
311  * 	Version of tp_ctimeout that resets the C-type time if the
312  * 	parameter (ticks) is > the current value of the timer.
313  */
314 void
315 tp_ctimeout_MIN(tpcb, which, ticks)
316 	register struct tp_pcb	*tpcb;
317 	int						which, ticks;
318 {
319 	IFTRACE(D_TIMER)
320 		tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active",
321 			tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]);
322 	ENDTRACE
323 	IncStat(ts_Cset);
324 	if (tpcb->tp_timer[which])  {
325 		tpcb->tp_timer[which] = MIN(ticks, tpcb->tp_timer[which]);
326 		IncStat(ts_Ccan_act);
327 	} else
328 		tpcb->tp_timer[which] = ticks;
329 }
330 
331 /*
332  * CALLED FROM:
333  *  tp.trans
334  * FUNCTION and ARGUMENTS:
335  *  Cancel the (which) timer in the ref structure indicated by (refp).
336  */
337 void
338 tp_cuntimeout(tpcb, which)
339 	register struct tp_pcb	*tpcb;
340 	int						which;
341 {
342 	IFDEBUG(D_TIMER)
343 		printf("tp_cuntimeout(0x%x, %d) active %d\n",
344 				tpcb, which, tpcb->tp_timer[which]);
345 	ENDDEBUG
346 
347 	IFTRACE(D_TIMER)
348 		tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref,
349 			which, tpcb->tp_timer[which], 0);
350 	ENDTRACE
351 
352 	if (tpcb->tp_timer[which])
353 		IncStat(ts_Ccan_act);
354 	else
355 		IncStat(ts_Ccan_inact);
356 	tpcb->tp_timer[which] = 0;
357 }
358