FreeBSD/Linux Kernel Cross Reference
sys/netiso/tp_timer.c
1 /* $NetBSD: tp_timer.c,v 1.17 2005/12/11 12:25:12 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * @(#)tp_timer.c 8.1 (Berkeley) 6/10/93
32 */
33
34 /***********************************************************
35 Copyright IBM Corporation 1987
36
37 All Rights Reserved
38
39 Permission to use, copy, modify, and distribute this software and its
40 documentation for any purpose and without fee is hereby granted,
41 provided that the above copyright notice appear in all copies and that
42 both that copyright notice and this permission notice appear in
43 supporting documentation, and that the name of IBM not be
44 used in advertising or publicity pertaining to distribution of the
45 software without specific, written prior permission.
46
47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53 SOFTWARE.
54
55 ******************************************************************/
56
57 /*
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
59 */
60
61 #include <sys/cdefs.h>
62 __KERNEL_RCSID(0, "$NetBSD: tp_timer.c,v 1.17 2005/12/11 12:25:12 christos Exp $");
63
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/time.h>
67 #include <sys/malloc.h>
68 #include <sys/protosw.h>
69 #include <sys/socket.h>
70 #include <sys/kernel.h>
71
72 #include <netiso/argo_debug.h>
73 #include <netiso/tp_param.h>
74 #include <netiso/tp_timer.h>
75 #include <netiso/tp_stat.h>
76 #include <netiso/tp_pcb.h>
77 #include <netiso/tp_tpdu.h>
78 #include <netiso/tp_trace.h>
79 #include <netiso/tp_seq.h>
80 #include <netiso/tp_var.h>
81
82 struct tp_ref *tp_ref;
83 int tp_rttdiv, tp_rttadd, N_TPREF = 127;
84 struct tp_refinfo tp_refinfo;
85 struct tp_pcb *tp_ftimeolist = (struct tp_pcb *) & tp_ftimeolist;
86
87 /*
88 * CALLED FROM:
89 * at autoconfig time from tp_init()
90 * a combo of event, state, predicate
91 * FUNCTION and ARGUMENTS:
92 * initialize data structures for the timers
93 */
94 void
95 tp_timerinit(void)
96 {
97 int s;
98 /*
99 * Initialize storage
100 */
101 if (tp_refinfo.tpr_base)
102 return;
103 tp_refinfo.tpr_size = N_TPREF + 1; /* Need to start somewhere */
104 s = sizeof(*tp_ref) * tp_refinfo.tpr_size;
105 if ((tp_ref = (struct tp_ref *) malloc(s, M_PCB, M_NOWAIT|M_ZERO)) == 0)
106 panic("tp_timerinit");
107 tp_refinfo.tpr_base = tp_ref;
108 tp_rttdiv = hz / PR_SLOWHZ;
109 tp_rttadd = (2 * tp_rttdiv) - 1;
110 }
111 #ifdef TP_DEBUG_TIMERS
112 /********************** e timers *************************/
113
114 /*
115 * CALLED FROM:
116 * tp.trans all over
117 * FUNCTION and ARGUMENTS:
118 * Set an E type timer.
119 */
120 void
121 tp_etimeout(
122 struct tp_pcb *tpcb,
123 int fun, /* function to be called */
124 int ticks)
125 {
126
127 u_int *callp;
128 #ifdef ARGO_DEBUG
129 if (argo_debug[D_TIMER]) {
130 printf("etimeout pcb %p state 0x%x\n", tpcb, tpcb->tp_state);
131 }
132 #endif
133 #ifdef TPPT
134 if (tp_traceflags[D_TIMER]) {
135 tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", tpcb->tp_lref,
136 tpcb->tp_state, ticks, tp_stat.ts_Eticks);
137 }
138 #endif
139 if (tpcb == 0)
140 return;
141 IncStat(ts_Eset);
142 if (ticks == 0)
143 ticks = 1;
144 callp = tpcb->tp_timer + fun;
145 if (*callp == 0 || *callp > ticks)
146 *callp = ticks;
147 }
148
149 /*
150 * CALLED FROM:
151 * tp.trans all over
152 * FUNCTION and ARGUMENTS:
153 * Cancel all occurrences of E-timer function (fun) for reference (refp)
154 */
155 void
156 tp_euntimeout(struct tp_pcb *tpcb, int fun)
157 {
158 #ifdef TPPT
159 if (tp_traceflags[D_TIMER]) {
160 tptrace(TPPTmisc, "tp_euntimeout ref", tpcb->tp_lref, 0, 0, 0);
161 }
162 #endif
163
164 if (tpcb)
165 tpcb->tp_timer[fun] = 0;
166 }
167
168 /**************** c timers **********************
169 *
170 * These are not chained together; they sit
171 * in the tp_ref structure. they are the kind that
172 * are typically cancelled so it's faster not to
173 * mess with the chains
174 */
175 #endif
176 /*
177 * CALLED FROM:
178 * the clock, every 500 ms
179 * FUNCTION and ARGUMENTS:
180 * Look for open references with active timers.
181 * If they exist, call the appropriate timer routines to update
182 * the timers and possibly generate events.
183 */
184 void
185 tp_slowtimo(void)
186 {
187 u_int *cp;
188 struct tp_ref *rp;
189 struct tp_pcb *tpcb;
190 struct tp_event E;
191 int s = splsoftnet(), t;
192
193 /* check only open reference structures */
194 IncStat(ts_Cticks);
195 /* tp_ref[0] is never used */
196 for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) {
197 if ((tpcb = rp->tpr_pcb) == 0 || tpcb->tp_refstate < REF_OPEN)
198 continue;
199 /* check the timers */
200 for (t = 0; t < TM_NTIMERS; t++) {
201 cp = tpcb->tp_timer + t;
202 if (*cp && --(*cp) <= 0) {
203 *cp = 0;
204 E.ev_number = t;
205 #ifdef ARGO_DEBUG
206 if (argo_debug[D_TIMER]) {
207 printf("tp_slowtimo: pcb %p t %d\n",
208 tpcb, t);
209 }
210 #endif
211 IncStat(ts_Cexpired);
212 tp_driver(tpcb, &E);
213 if (t == TM_reference && tpcb->tp_state == TP_CLOSED) {
214 if (tpcb->tp_notdetached) {
215 #ifdef ARGO_DEBUG
216 if (argo_debug[D_CONN]) {
217 printf("PRU_DETACH: not detached\n");
218 }
219 #endif
220 tp_detach(tpcb);
221 }
222 /* XXX wart; where else to do it? */
223 free((caddr_t) tpcb, M_PCB);
224 break;
225 }
226 }
227 }
228 }
229 splx(s);
230 }
231
232 /*
233 * Called From: tp.trans from tp_slowtimo() -- retransmission timer went off.
234 */
235 void
236 tp_data_retrans(struct tp_pcb *tpcb)
237 {
238 int rexmt, win;
239 tpcb->tp_rttemit = 0; /* cancel current round trip time */
240 tpcb->tp_dupacks = 0;
241 tpcb->tp_sndnxt = tpcb->tp_snduna;
242 if (tpcb->tp_fcredit == 0) {
243 /*
244 * We transmitted new data, started timing it and the window
245 * got shrunk under us. This can only happen if all data
246 * that they wanted us to send got acked, so don't
247 * bother shrinking the congestion windows, et. al.
248 * The retransmission timer should have been reset in goodack()
249 */
250 #ifdef ARGO_DEBUG
251 if (argo_debug[D_ACKRECV]) {
252 printf("tp_data_retrans: 0 window tpcb %p una 0x%x\n",
253 tpcb, tpcb->tp_snduna);
254 }
255 #endif
256 tpcb->tp_rxtshift = 0;
257 tpcb->tp_timer[TM_data_retrans] = 0;
258 tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks;
259 return;
260 }
261 rexmt = tpcb->tp_dt_ticks << min(tpcb->tp_rxtshift, TP_MAXRXTSHIFT);
262 win = min(tpcb->tp_fcredit, (tpcb->tp_cong_win / tpcb->tp_l_tpdusize / 2));
263 win = max(win, 2);
264 tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* slow start again. */
265 tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize;
266 /*
267 * We're losing; our srtt estimate is probably bogus. Clobber it so
268 * we'll take the next rtt measurement as our srtt; Maintain current
269 * rxt times until then.
270 */
271 if (++tpcb->tp_rxtshift > TP_NRETRANS / 4) {
272 /* tpcb->tp_nlprotosw->nlp_losing(tpcb->tp_npcb) someday */
273 tpcb->tp_rtt = 0;
274 }
275 TP_RANGESET(tpcb->tp_rxtcur, rexmt, tpcb->tp_peer_acktime, 128);
276 tpcb->tp_timer[TM_data_retrans] = tpcb->tp_rxtcur;
277 tp_send(tpcb);
278 }
279
280 void
281 tp_fasttimo(void)
282 {
283 struct tp_pcb *t;
284 int s = splsoftnet();
285 struct tp_event E;
286
287 E.ev_number = TM_sendack;
288 while ((t = tp_ftimeolist) != (struct tp_pcb *) & tp_ftimeolist) {
289 if (t == 0) {
290 printf("tp_fasttimeo: should panic");
291 tp_ftimeolist = (struct tp_pcb *) & tp_ftimeolist;
292 } else {
293 if (t->tp_flags & TPF_DELACK) {
294 IncStat(ts_Fdelack);
295 tp_driver(t, &E);
296 t->tp_flags &= ~TPF_DELACK;
297 } else
298 IncStat(ts_Fpruned);
299 tp_ftimeolist = t->tp_fasttimeo;
300 t->tp_fasttimeo = 0;
301 }
302 }
303 splx(s);
304 }
305
306 #ifdef TP_DEBUG_TIMERS
307 /*
308 * CALLED FROM:
309 * tp.trans, tp_emit()
310 * FUNCTION and ARGUMENTS:
311 * Set a C type timer of type (which) to go off after (ticks) time.
312 */
313 void
314 tp_ctimeout(struct tp_pcb *tpcb, int which, int ticks)
315 {
316
317 #ifdef TPPT
318 if (tp_traceflags[D_TIMER]) {
319 tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active",
320 tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]);
321 }
322 #endif
323 if (tpcb->tp_timer[which])
324 IncStat(ts_Ccan_act);
325 IncStat(ts_Cset);
326 if (ticks <= 0)
327 ticks = 1;
328 tpcb->tp_timer[which] = ticks;
329 }
330
331 /*
332 * CALLED FROM:
333 * tp.trans
334 * FUNCTION and ARGUMENTS:
335 * Version of tp_ctimeout that resets the C-type time if the
336 * parameter (ticks) is > the current value of the timer.
337 */
338 void
339 tp_ctimeout_MIN(struct tp_pcb *tpcb, int which, int ticks)
340 {
341 #ifdef TPPT
342 if (tp_traceflags[D_TIMER]) {
343 tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active",
344 tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]);
345 }
346 #endif
347 IncStat(ts_Cset);
348 if (tpcb->tp_timer[which]) {
349 tpcb->tp_timer[which] = min(ticks, tpcb->tp_timer[which]);
350 IncStat(ts_Ccan_act);
351 } else
352 tpcb->tp_timer[which] = ticks;
353 }
354
355 /*
356 * CALLED FROM:
357 * tp.trans
358 * FUNCTION and ARGUMENTS:
359 * Cancel the (which) timer in the ref structure indicated by (refp).
360 */
361 void
362 tp_cuntimeout(struct tp_pcb *tpcb, int which)
363 {
364 #ifdef ARGO_DEBUG
365 if (argo_debug[D_TIMER]) {
366 printf("tp_cuntimeout(%p, %d) active %d\n",
367 tpcb, which, tpcb->tp_timer[which]);
368 }
369 #endif
370
371 #ifdef TPPT
372 if (tp_traceflags[D_TIMER]) {
373 tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp - tp_ref,
374 which, tpcb->tp_timer[which], 0);
375 }
376 #endif
377
378 if (tpcb->tp_timer[which])
379 IncStat(ts_Ccan_act);
380 else
381 IncStat(ts_Ccan_inact);
382 tpcb->tp_timer[which] = 0;
383 }
384 #endif
Cache object: c57891ba79448a96527e7fac1c0af234
|