149268Sbostic /*-
2*63222Sbostic * Copyright (c) 1991, 1993
3*63222Sbostic * The Regents of the University of California. All rights reserved.
449268Sbostic *
549268Sbostic * %sccs.include.redist.c%
649268Sbostic *
7*63222Sbostic * @(#)tp_timer.c 8.1 (Berkeley) 06/10/93
849268Sbostic */
949268Sbostic
1036415Ssklower /***********************************************************
1136415Ssklower Copyright IBM Corporation 1987
1236415Ssklower
1336415Ssklower All Rights Reserved
1436415Ssklower
1536415Ssklower Permission to use, copy, modify, and distribute this software and its
1636415Ssklower documentation for any purpose and without fee is hereby granted,
1736415Ssklower provided that the above copyright notice appear in all copies and that
1836415Ssklower both that copyright notice and this permission notice appear in
1936415Ssklower supporting documentation, and that the name of IBM not be
2036415Ssklower used in advertising or publicity pertaining to distribution of the
2136415Ssklower software without specific, written prior permission.
2236415Ssklower
2336415Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436415Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536415Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636415Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736415Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836415Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936415Ssklower SOFTWARE.
3036415Ssklower
3136415Ssklower ******************************************************************/
3236415Ssklower
3336415Ssklower /*
3436415Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536415Ssklower */
3636415Ssklower /*
3736415Ssklower * ARGO TP
3836415Ssklower *
3936415Ssklower * $Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $
4036415Ssklower * $Source: /usr/argo/sys/netiso/RCS/tp_timer.c,v $
4136415Ssklower *
4236415Ssklower */
4336415Ssklower
4456533Sbostic #include <sys/param.h>
4556533Sbostic #include <sys/systm.h>
4656533Sbostic #include <sys/time.h>
4756533Sbostic #include <sys/malloc.h>
4856533Sbostic #include <sys/protosw.h>
4956533Sbostic #include <sys/socket.h>
5056533Sbostic #include <sys/kernel.h>
5136415Ssklower
5256533Sbostic #include <netiso/argo_debug.h>
5356533Sbostic #include <netiso/tp_param.h>
5456533Sbostic #include <netiso/tp_timer.h>
5556533Sbostic #include <netiso/tp_stat.h>
5656533Sbostic #include <netiso/tp_pcb.h>
5756533Sbostic #include <netiso/tp_tpdu.h>
5856533Sbostic #include <netiso/tp_trace.h>
5956533Sbostic #include <netiso/tp_seq.h>
6036415Ssklower
6148752Ssklower struct tp_ref *tp_ref;
6251254Ssklower int tp_rttdiv, tp_rttadd, N_TPREF = 127;
6351006Ssklower struct tp_refinfo tp_refinfo;
6451024Ssklower struct tp_pcb *tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist;
6536415Ssklower
6636415Ssklower /*
6736415Ssklower * CALLED FROM:
6836415Ssklower * at autoconfig time from tp_init()
6936415Ssklower * a combo of event, state, predicate
7036415Ssklower * FUNCTION and ARGUMENTS:
7136415Ssklower * initialize data structures for the timers
7236415Ssklower */
7336415Ssklower void
tp_timerinit()7436415Ssklower tp_timerinit()
7536415Ssklower {
7648752Ssklower register int s;
7736415Ssklower /*
7848752Ssklower * Initialize storage
7936415Ssklower */
8051254Ssklower if (tp_refinfo.tpr_base)
8151254Ssklower return;
8251204Ssklower tp_refinfo.tpr_size = N_TPREF + 1; /* Need to start somewhere */
8351254Ssklower s = sizeof(*tp_ref) * tp_refinfo.tpr_size;
8451254Ssklower if ((tp_ref = (struct tp_ref *) malloc(s, M_PCB, M_NOWAIT)) == 0)
8551254Ssklower panic("tp_timerinit");
8651340Ssklower bzero((caddr_t)tp_ref, (unsigned) s);
8751006Ssklower tp_refinfo.tpr_base = tp_ref;
8851254Ssklower tp_rttdiv = hz / PR_SLOWHZ;
8951254Ssklower tp_rttadd = (2 * tp_rttdiv) - 1;
9036415Ssklower }
9151254Ssklower #ifdef TP_DEBUG_TIMERS
9236415Ssklower /********************** e timers *************************/
9336415Ssklower
9436415Ssklower /*
9536415Ssklower * CALLED FROM:
9636415Ssklower * tp.trans all over
9736415Ssklower * FUNCTION and ARGUMENTS:
9851204Ssklower * Set an E type timer.
9936415Ssklower */
10036415Ssklower void
tp_etimeout(tpcb,fun,ticks)10151204Ssklower tp_etimeout(tpcb, fun, ticks)
10251204Ssklower register struct tp_pcb *tpcb;
10351204Ssklower int fun; /* function to be called */
10451204Ssklower int ticks;
10536415Ssklower {
10636415Ssklower
10751204Ssklower register u_int *callp;
10836415Ssklower IFDEBUG(D_TIMER)
10951204Ssklower printf("etimeout pcb 0x%x state 0x%x\n", tpcb, tpcb->tp_state);
11036415Ssklower ENDDEBUG
11136415Ssklower IFTRACE(D_TIMER)
11251204Ssklower tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", tpcb->tp_lref,
11351204Ssklower tpcb->tp_state, ticks, tp_stat.ts_Eticks);
11436415Ssklower ENDTRACE
11551007Ssklower if (tpcb == 0)
11651007Ssklower return;
11736415Ssklower IncStat(ts_Eset);
11836415Ssklower if (ticks == 0)
11936415Ssklower ticks = 1;
12051204Ssklower callp = tpcb->tp_timer + fun;
12151204Ssklower if (*callp == 0 || *callp > ticks)
12251204Ssklower *callp = ticks;
12336415Ssklower }
12436415Ssklower
12536415Ssklower /*
12636415Ssklower * CALLED FROM:
12736415Ssklower * tp.trans all over
12836415Ssklower * FUNCTION and ARGUMENTS:
12936415Ssklower * Cancel all occurrences of E-timer function (fun) for reference (refp)
13036415Ssklower */
13136415Ssklower void
tp_euntimeout(tpcb,fun)13251204Ssklower tp_euntimeout(tpcb, fun)
13351204Ssklower register struct tp_pcb *tpcb;
13436415Ssklower int fun;
13536415Ssklower {
13636415Ssklower IFTRACE(D_TIMER)
13751204Ssklower tptrace(TPPTmisc, "tp_euntimeout ref", tpcb->tp_lref, 0, 0, 0);
13836415Ssklower ENDTRACE
13936415Ssklower
14051007Ssklower if (tpcb)
14151204Ssklower tpcb->tp_timer[fun] = 0;
14236415Ssklower }
14336415Ssklower
14436415Ssklower /**************** c timers **********************
14536415Ssklower *
14636415Ssklower * These are not chained together; they sit
14736415Ssklower * in the tp_ref structure. they are the kind that
14836415Ssklower * are typically cancelled so it's faster not to
14936415Ssklower * mess with the chains
15036415Ssklower */
15151254Ssklower #endif
15236415Ssklower /*
15336415Ssklower * CALLED FROM:
15436415Ssklower * the clock, every 500 ms
15536415Ssklower * FUNCTION and ARGUMENTS:
15636415Ssklower * Look for open references with active timers.
15736415Ssklower * If they exist, call the appropriate timer routines to update
15836415Ssklower * the timers and possibly generate events.
15936415Ssklower */
16036415Ssklower ProtoHook
tp_slowtimo()16136415Ssklower tp_slowtimo()
16236415Ssklower {
16351340Ssklower register u_int *cp;
16451007Ssklower register struct tp_ref *rp;
16551007Ssklower struct tp_pcb *tpcb;
16636415Ssklower struct tp_event E;
16751007Ssklower int s = splnet(), t;
16836415Ssklower
16936415Ssklower /* check only open reference structures */
17036415Ssklower IncStat(ts_Cticks);
17151007Ssklower /* tp_ref[0] is never used */
17251007Ssklower for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) {
17351254Ssklower if ((tpcb = rp->tpr_pcb) == 0 || tpcb->tp_refstate < REF_OPEN)
17436415Ssklower continue;
17551204Ssklower /* check the timers */
17651340Ssklower for (t = 0; t < TM_NTIMERS; t++) {
17751340Ssklower cp = tpcb->tp_timer + t;
17851204Ssklower if (*cp && --(*cp) <= 0 ) {
17951204Ssklower *cp = 0;
18051007Ssklower E.ev_number = t;
18151007Ssklower IFDEBUG(D_TIMER)
18253681Ssklower printf("tp_slowtimo: pcb 0x%x t %d\n",
18353681Ssklower tpcb, t);
18451007Ssklower ENDDEBUG
18551007Ssklower IncStat(ts_Cexpired);
18651340Ssklower tp_driver(tpcb, &E);
18751007Ssklower if (t == TM_reference && tpcb->tp_state == TP_CLOSED) {
18851007Ssklower if (tpcb->tp_notdetached) {
18951007Ssklower IFDEBUG(D_CONN)
19051007Ssklower printf("PRU_DETACH: not detached\n");
19151007Ssklower ENDDEBUG
19251007Ssklower tp_detach(tpcb);
19351007Ssklower }
19451007Ssklower /* XXX wart; where else to do it? */
19551007Ssklower free((caddr_t)tpcb, M_PCB);
19651007Ssklower }
19736415Ssklower }
19836415Ssklower }
19936415Ssklower }
20036415Ssklower splx(s);
20136415Ssklower return 0;
20236415Ssklower }
20336415Ssklower
20451204Ssklower /*
20551204Ssklower * Called From: tp.trans from tp_slowtimo() -- retransmission timer went off.
20651204Ssklower */
tp_data_retrans(tpcb)20751204Ssklower tp_data_retrans(tpcb)
20851204Ssklower register struct tp_pcb *tpcb;
20951204Ssklower {
21051204Ssklower int rexmt, win;
21151204Ssklower tpcb->tp_rttemit = 0; /* cancel current round trip time */
21251204Ssklower tpcb->tp_dupacks = 0;
21351204Ssklower tpcb->tp_sndnxt = tpcb->tp_snduna;
21451204Ssklower if (tpcb->tp_fcredit == 0) {
21551204Ssklower /*
21651204Ssklower * We transmitted new data, started timing it and the window
21751204Ssklower * got shrunk under us. This can only happen if all data
21851204Ssklower * that they wanted us to send got acked, so don't
21951204Ssklower * bother shrinking the congestion windows, et. al.
22051204Ssklower * The retransmission timer should have been reset in goodack()
22151204Ssklower */
22251340Ssklower IFDEBUG(D_ACKRECV)
22351340Ssklower printf("tp_data_retrans: 0 window tpcb 0x%x una 0x%x\n",
22451340Ssklower tpcb, tpcb->tp_snduna);
22551340Ssklower ENDDEBUG
22651204Ssklower tpcb->tp_rxtshift = 0;
22751204Ssklower tpcb->tp_timer[TM_data_retrans] = 0;
22851204Ssklower tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks;
22951340Ssklower return;
23051204Ssklower }
23151204Ssklower rexmt = tpcb->tp_dt_ticks << min(tpcb->tp_rxtshift, TP_MAXRXTSHIFT);
23251204Ssklower win = min(tpcb->tp_fcredit, (tpcb->tp_cong_win / tpcb->tp_l_tpdusize / 2));
23351204Ssklower win = max(win, 2);
23451204Ssklower tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* slow start again. */
23551204Ssklower tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize;
23651204Ssklower /* We're losing; our srtt estimate is probably bogus.
23751204Ssklower * Clobber it so we'll take the next rtt measurement as our srtt;
23851204Ssklower * Maintain current rxt times until then.
23951204Ssklower */
24051204Ssklower if (++tpcb->tp_rxtshift > TP_NRETRANS / 4) {
24151204Ssklower /* tpcb->tp_nlprotosw->nlp_losing(tpcb->tp_npcb) someday */
24251204Ssklower tpcb->tp_rtt = 0;
24351204Ssklower }
24451254Ssklower TP_RANGESET(tpcb->tp_rxtcur, rexmt, tpcb->tp_peer_acktime, 128);
24551254Ssklower tpcb->tp_timer[TM_data_retrans] = tpcb->tp_rxtcur;
24651204Ssklower tp_send(tpcb);
24751204Ssklower }
24851204Ssklower
24951024Ssklower int
tp_fasttimo()25051024Ssklower tp_fasttimo()
25151024Ssklower {
25251024Ssklower register struct tp_pcb *t;
25351024Ssklower int s = splnet();
25451024Ssklower struct tp_event E;
25551024Ssklower
25651024Ssklower E.ev_number = TM_sendack;
25751024Ssklower while ((t = tp_ftimeolist) != (struct tp_pcb *)&tp_ftimeolist) {
25851024Ssklower if (t == 0) {
25951024Ssklower printf("tp_fasttimeo: should panic");
26051024Ssklower tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist;
26151024Ssklower } else {
26251024Ssklower if (t->tp_flags & TPF_DELACK) {
26351024Ssklower IncStat(ts_Fdelack);
26451024Ssklower tp_driver(t, &E);
26551340Ssklower t->tp_flags &= ~TPF_DELACK;
26651024Ssklower } else
26751024Ssklower IncStat(ts_Fpruned);
26851024Ssklower tp_ftimeolist = t->tp_fasttimeo;
26951024Ssklower t->tp_fasttimeo = 0;
27051024Ssklower }
27151024Ssklower }
27251024Ssklower splx(s);
27351024Ssklower }
27451024Ssklower
27551254Ssklower #ifdef TP_DEBUG_TIMERS
27636415Ssklower /*
27736415Ssklower * CALLED FROM:
27836415Ssklower * tp.trans, tp_emit()
27936415Ssklower * FUNCTION and ARGUMENTS:
28036415Ssklower * Set a C type timer of type (which) to go off after (ticks) time.
28136415Ssklower */
28236415Ssklower void
tp_ctimeout(tpcb,which,ticks)28351204Ssklower tp_ctimeout(tpcb, which, ticks)
28451204Ssklower register struct tp_pcb *tpcb;
28536415Ssklower int which, ticks;
28636415Ssklower {
28736415Ssklower
28836415Ssklower IFTRACE(D_TIMER)
28936415Ssklower tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active",
29051204Ssklower tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]);
29136415Ssklower ENDTRACE
29251204Ssklower if(tpcb->tp_timer[which])
29336415Ssklower IncStat(ts_Ccan_act);
29436415Ssklower IncStat(ts_Cset);
29551007Ssklower if (ticks <= 0)
29651007Ssklower ticks = 1;
29751204Ssklower tpcb->tp_timer[which] = ticks;
29836415Ssklower }
29936415Ssklower
30036415Ssklower /*
30136415Ssklower * CALLED FROM:
30236415Ssklower * tp.trans
30336415Ssklower * FUNCTION and ARGUMENTS:
30436415Ssklower * Version of tp_ctimeout that resets the C-type time if the
30536415Ssklower * parameter (ticks) is > the current value of the timer.
30636415Ssklower */
30736415Ssklower void
tp_ctimeout_MIN(tpcb,which,ticks)30851204Ssklower tp_ctimeout_MIN(tpcb, which, ticks)
30951204Ssklower register struct tp_pcb *tpcb;
31036415Ssklower int which, ticks;
31136415Ssklower {
31236415Ssklower IFTRACE(D_TIMER)
31336415Ssklower tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active",
31451204Ssklower tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]);
31536415Ssklower ENDTRACE
31636415Ssklower IncStat(ts_Cset);
31751204Ssklower if (tpcb->tp_timer[which]) {
31856306Smckusick tpcb->tp_timer[which] = min(ticks, tpcb->tp_timer[which]);
31951007Ssklower IncStat(ts_Ccan_act);
32051007Ssklower } else
32151204Ssklower tpcb->tp_timer[which] = ticks;
32236415Ssklower }
32336415Ssklower
32436415Ssklower /*
32536415Ssklower * CALLED FROM:
32636415Ssklower * tp.trans
32736415Ssklower * FUNCTION and ARGUMENTS:
32836415Ssklower * Cancel the (which) timer in the ref structure indicated by (refp).
32936415Ssklower */
33036415Ssklower void
tp_cuntimeout(tpcb,which)33151204Ssklower tp_cuntimeout(tpcb, which)
33251204Ssklower register struct tp_pcb *tpcb;
33336415Ssklower int which;
33436415Ssklower {
33536415Ssklower IFDEBUG(D_TIMER)
33651204Ssklower printf("tp_cuntimeout(0x%x, %d) active %d\n",
33751204Ssklower tpcb, which, tpcb->tp_timer[which]);
33836415Ssklower ENDDEBUG
33936415Ssklower
34036415Ssklower IFTRACE(D_TIMER)
34136415Ssklower tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref,
34251204Ssklower which, tpcb->tp_timer[which], 0);
34336415Ssklower ENDTRACE
34436415Ssklower
34551204Ssklower if (tpcb->tp_timer[which])
34636415Ssklower IncStat(ts_Ccan_act);
34736415Ssklower else
34836415Ssklower IncStat(ts_Ccan_inact);
34951204Ssklower tpcb->tp_timer[which] = 0;
35036415Ssklower }
35151254Ssklower #endif
352