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