1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
7 * @(#)tp_timer.c 8.1 (Berkeley) 06/10/93
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 <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/time.h>
47 #include <sys/malloc.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
50 #include <sys/kernel.h>
51
52 #include <netiso/argo_debug.h>
53 #include <netiso/tp_param.h>
54 #include <netiso/tp_timer.h>
55 #include <netiso/tp_stat.h>
56 #include <netiso/tp_pcb.h>
57 #include <netiso/tp_tpdu.h>
58 #include <netiso/tp_trace.h>
59 #include <netiso/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
tp_timerinit()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
tp_etimeout(tpcb,fun,ticks)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
tp_euntimeout(tpcb,fun)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
tp_slowtimo()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 /* check the timers */
176 for (t = 0; t < TM_NTIMERS; t++) {
177 cp = tpcb->tp_timer + t;
178 if (*cp && --(*cp) <= 0 ) {
179 *cp = 0;
180 E.ev_number = t;
181 IFDEBUG(D_TIMER)
182 printf("tp_slowtimo: pcb 0x%x t %d\n",
183 tpcb, 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 */
tp_data_retrans(tpcb)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
tp_fasttimo()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
tp_ctimeout(tpcb,which,ticks)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
tp_ctimeout_MIN(tpcb,which,ticks)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
tp_cuntimeout(tpcb,which)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