149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*56533Sbostic * @(#)tp_timer.c 7.16 (Berkeley) 10/11/92 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 44*56533Sbostic #include <sys/param.h> 45*56533Sbostic #include <sys/systm.h> 46*56533Sbostic #include <sys/time.h> 47*56533Sbostic #include <sys/malloc.h> 48*56533Sbostic #include <sys/protosw.h> 49*56533Sbostic #include <sys/socket.h> 50*56533Sbostic #include <sys/kernel.h> 5136415Ssklower 52*56533Sbostic #include <netiso/argo_debug.h> 53*56533Sbostic #include <netiso/tp_param.h> 54*56533Sbostic #include <netiso/tp_timer.h> 55*56533Sbostic #include <netiso/tp_stat.h> 56*56533Sbostic #include <netiso/tp_pcb.h> 57*56533Sbostic #include <netiso/tp_tpdu.h> 58*56533Sbostic #include <netiso/tp_trace.h> 59*56533Sbostic #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 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 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 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 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 */ 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 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 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 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 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