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