1 /* $NetBSD: tp_timer.c,v 1.18 2007/03/04 06:03:33 christos Exp $ */
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
31 * @(#)tp_timer.c 8.1 (Berkeley) 6/10/93
34 /***********************************************************
35 Copyright IBM Corporation 1987
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.
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
55 ******************************************************************/
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
61 #include <sys/cdefs.h>
62 __KERNEL_RCSID(0, "$NetBSD: tp_timer.c,v 1.18 2007/03/04 06:03:33 christos Exp $");
64 #include <sys/param.h>
65 #include <sys/systm.h>
67 #include <sys/malloc.h>
68 #include <sys/protosw.h>
69 #include <sys/socket.h>
70 #include <sys/kernel.h>
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>
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
;
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
101 if (tp_refinfo
.tpr_base
)
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;
111 #ifdef TP_DEBUG_TIMERS
112 /********************** e timers *************************/
117 * FUNCTION and ARGUMENTS:
118 * Set an E type timer.
123 int fun
, /* function to be called */
129 if (argo_debug
[D_TIMER
]) {
130 printf("etimeout pcb %p state 0x%x\n", tpcb
, tpcb
->tp_state
);
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
);
144 callp
= tpcb
->tp_timer
+ fun
;
145 if (*callp
== 0 || *callp
> ticks
)
152 * FUNCTION and ARGUMENTS:
153 * Cancel all occurrences of E-timer function (fun) for reference (refp)
156 tp_euntimeout(struct tp_pcb
*tpcb
, int fun
)
159 if (tp_traceflags
[D_TIMER
]) {
160 tptrace(TPPTmisc
, "tp_euntimeout ref", tpcb
->tp_lref
, 0, 0, 0);
165 tpcb
->tp_timer
[fun
] = 0;
168 /**************** c timers **********************
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
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.
193 mutex_enter(softnet_lock
);
194 KERNEL_LOCK(1, NULL
);
195 /* check only open reference structures */
197 /* tp_ref[0] is never used */
198 for (rp
= tp_ref
+ tp_refinfo
.tpr_maxopen
; rp
> tp_ref
; rp
--) {
199 if ((tpcb
= rp
->tpr_pcb
) == 0 || tpcb
->tp_refstate
< REF_OPEN
)
201 /* check the timers */
202 for (t
= 0; t
< TM_NTIMERS
; t
++) {
203 cp
= tpcb
->tp_timer
+ t
;
204 if (*cp
&& --(*cp
) <= 0) {
208 if (argo_debug
[D_TIMER
]) {
209 printf("tp_slowtimo: pcb %p t %d\n",
213 IncStat(ts_Cexpired
);
215 if (t
== TM_reference
&& tpcb
->tp_state
== TP_CLOSED
) {
216 if (tpcb
->tp_notdetached
) {
218 if (argo_debug
[D_CONN
]) {
219 printf("PRU_DETACH: not detached\n");
224 /* XXX wart; where else to do it? */
225 free((void *) tpcb
, M_PCB
);
231 KERNEL_UNLOCK_ONE(NULL
);
232 mutex_exit(softnet_lock
);
236 * Called From: tp.trans from tp_slowtimo() -- retransmission timer went off.
239 tp_data_retrans(struct tp_pcb
*tpcb
)
242 tpcb
->tp_rttemit
= 0; /* cancel current round trip time */
243 tpcb
->tp_dupacks
= 0;
244 tpcb
->tp_sndnxt
= tpcb
->tp_snduna
;
245 if (tpcb
->tp_fcredit
== 0) {
247 * We transmitted new data, started timing it and the window
248 * got shrunk under us. This can only happen if all data
249 * that they wanted us to send got acked, so don't
250 * bother shrinking the congestion windows, et. al.
251 * The retransmission timer should have been reset in goodack()
254 if (argo_debug
[D_ACKRECV
]) {
255 printf("tp_data_retrans: 0 window tpcb %p una 0x%x\n",
256 tpcb
, tpcb
->tp_snduna
);
259 tpcb
->tp_rxtshift
= 0;
260 tpcb
->tp_timer
[TM_data_retrans
] = 0;
261 tpcb
->tp_timer
[TM_sendack
] = tpcb
->tp_dt_ticks
;
264 rexmt
= tpcb
->tp_dt_ticks
<< min(tpcb
->tp_rxtshift
, TP_MAXRXTSHIFT
);
265 win
= min(tpcb
->tp_fcredit
, (tpcb
->tp_cong_win
/ tpcb
->tp_l_tpdusize
/ 2));
267 tpcb
->tp_cong_win
= tpcb
->tp_l_tpdusize
; /* slow start again. */
268 tpcb
->tp_ssthresh
= win
* tpcb
->tp_l_tpdusize
;
270 * We're losing; our srtt estimate is probably bogus. Clobber it so
271 * we'll take the next rtt measurement as our srtt; Maintain current
272 * rxt times until then.
274 if (++tpcb
->tp_rxtshift
> TP_NRETRANS
/ 4) {
275 /* tpcb->tp_nlprotosw->nlp_losing(tpcb->tp_npcb) someday */
278 TP_RANGESET(tpcb
->tp_rxtcur
, rexmt
, tpcb
->tp_peer_acktime
, 128);
279 tpcb
->tp_timer
[TM_data_retrans
] = tpcb
->tp_rxtcur
;
289 mutex_enter(softnet_lock
);
290 KERNEL_LOCK(1, NULL
);
291 E
.ev_number
= TM_sendack
;
292 while ((t
= tp_ftimeolist
) != (struct tp_pcb
*) & tp_ftimeolist
) {
294 printf("tp_fasttimeo: should panic");
295 tp_ftimeolist
= (struct tp_pcb
*) & tp_ftimeolist
;
297 if (t
->tp_flags
& TPF_DELACK
) {
300 t
->tp_flags
&= ~TPF_DELACK
;
303 tp_ftimeolist
= t
->tp_fasttimeo
;
307 KERNEL_UNLOCK_ONE(NULL
);
308 mutex_exit(softnet_lock
);
311 #ifdef TP_DEBUG_TIMERS
314 * tp.trans, tp_emit()
315 * FUNCTION and ARGUMENTS:
316 * Set a C type timer of type (which) to go off after (ticks) time.
319 tp_ctimeout(struct tp_pcb
*tpcb
, int which
, int ticks
)
323 if (tp_traceflags
[D_TIMER
]) {
324 tptrace(TPPTmisc
, "tp_ctimeout ref which tpcb active",
325 tpcb
->tp_lref
, which
, tpcb
, tpcb
->tp_timer
[which
]);
328 if (tpcb
->tp_timer
[which
])
329 IncStat(ts_Ccan_act
);
333 tpcb
->tp_timer
[which
] = ticks
;
339 * FUNCTION and ARGUMENTS:
340 * Version of tp_ctimeout that resets the C-type time if the
341 * parameter (ticks) is > the current value of the timer.
344 tp_ctimeout_MIN(struct tp_pcb
*tpcb
, int which
, int ticks
)
347 if (tp_traceflags
[D_TIMER
]) {
348 tptrace(TPPTmisc
, "tp_ctimeout_MIN ref which tpcb active",
349 tpcb
->tp_lref
, which
, tpcb
, tpcb
->tp_timer
[which
]);
353 if (tpcb
->tp_timer
[which
]) {
354 tpcb
->tp_timer
[which
] = min(ticks
, tpcb
->tp_timer
[which
]);
355 IncStat(ts_Ccan_act
);
357 tpcb
->tp_timer
[which
] = ticks
;
363 * FUNCTION and ARGUMENTS:
364 * Cancel the (which) timer in the ref structure indicated by (refp).
367 tp_cuntimeout(struct tp_pcb
*tpcb
, int which
)
370 if (argo_debug
[D_TIMER
]) {
371 printf("tp_cuntimeout(%p, %d) active %d\n",
372 tpcb
, which
, tpcb
->tp_timer
[which
]);
377 if (tp_traceflags
[D_TIMER
]) {
378 tptrace(TPPTmisc
, "tp_cuntimeout ref which, active", refp
- tp_ref
,
379 which
, tpcb
->tp_timer
[which
], 0);
383 if (tpcb
->tp_timer
[which
])
384 IncStat(ts_Ccan_act
);
386 IncStat(ts_Ccan_inact
);
387 tpcb
->tp_timer
[which
] = 0;