149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*51204Ssklower * @(#)tp_timer.c 7.10 (Berkeley) 09/26/91 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 * Contains all the timer code. 4336415Ssklower * There are two sources of calls to these routines: 4436415Ssklower * the clock, and tp.trans. (ok, and tp_pcb.c calls it at init time) 4536415Ssklower * 4636415Ssklower * Timers come in two flavors - those that generally get 4736415Ssklower * cancelled (tp_ctimeout, tp_cuntimeout) 4836415Ssklower * and those that either usually expire (tp_etimeout, 4936415Ssklower * tp_euntimeout, tp_slowtimo) or may require more than one instance 5036415Ssklower * of the timer active at a time. 5136415Ssklower * 5236415Ssklower * The C timers are stored in the tp_ref structure. Their "going off" 5336415Ssklower * is manifested by a driver event of the TM_xxx form. 5436415Ssklower * 5536415Ssklower * The E timers are handled like the generic kernel callouts. 5636415Ssklower * Their "going off" is manifested by a function call w/ 3 arguments. 5736415Ssklower */ 5836415Ssklower 5936415Ssklower #include "param.h" 6036415Ssklower #include "types.h" 6136415Ssklower #include "time.h" 6237469Ssklower #include "malloc.h" 6348752Ssklower #include "socket.h" 6436415Ssklower 6537469Ssklower #include "tp_param.h" 6637469Ssklower #include "tp_timer.h" 6737469Ssklower #include "tp_stat.h" 6837469Ssklower #include "tp_pcb.h" 6937469Ssklower #include "tp_tpdu.h" 7037469Ssklower #include "argo_debug.h" 7137469Ssklower #include "tp_trace.h" 7237469Ssklower #include "tp_seq.h" 7336415Ssklower 7448752Ssklower struct tp_ref *tp_ref; 7551007Ssklower int N_TPREF = 127; 7651006Ssklower struct tp_refinfo tp_refinfo; 7751024Ssklower struct tp_pcb *tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist; 7836415Ssklower 7936415Ssklower /* 8036415Ssklower * CALLED FROM: 8136415Ssklower * at autoconfig time from tp_init() 8236415Ssklower * a combo of event, state, predicate 8336415Ssklower * FUNCTION and ARGUMENTS: 8436415Ssklower * initialize data structures for the timers 8536415Ssklower */ 8636415Ssklower void 8736415Ssklower tp_timerinit() 8836415Ssklower { 8948752Ssklower register int s; 9048752Ssklower #define GETME(x, t, n) {s = (n)*sizeof(*x); x = (t) malloc(s, M_PCB, M_NOWAIT);\ 9148752Ssklower if (x == 0) panic("tp_timerinit"); bzero((caddr_t)x, s);} 9236415Ssklower /* 9348752Ssklower * Initialize storage 9436415Ssklower */ 95*51204Ssklower tp_refinfo.tpr_size = N_TPREF + 1; /* Need to start somewhere */ 96*51204Ssklower GETME(tp_ref, struct tp_ref *, tp_refinfo.tpr_size); 9751006Ssklower tp_refinfo.tpr_base = tp_ref; 9848752Ssklower #undef GETME 9936415Ssklower } 10036415Ssklower 10136415Ssklower /********************** e timers *************************/ 10236415Ssklower 10336415Ssklower /* 10436415Ssklower * CALLED FROM: 10536415Ssklower * tp.trans all over 10636415Ssklower * FUNCTION and ARGUMENTS: 107*51204Ssklower * Set an E type timer. 10836415Ssklower */ 10936415Ssklower void 110*51204Ssklower tp_etimeout(tpcb, fun, ticks) 111*51204Ssklower register struct tp_pcb *tpcb; 112*51204Ssklower int fun; /* function to be called */ 113*51204Ssklower int ticks; 11436415Ssklower { 11536415Ssklower 116*51204Ssklower register u_int *callp; 11736415Ssklower IFDEBUG(D_TIMER) 118*51204Ssklower printf("etimeout pcb 0x%x state 0x%x\n", tpcb, tpcb->tp_state); 11936415Ssklower ENDDEBUG 12036415Ssklower IFTRACE(D_TIMER) 121*51204Ssklower tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", tpcb->tp_lref, 122*51204Ssklower tpcb->tp_state, ticks, tp_stat.ts_Eticks); 12336415Ssklower ENDTRACE 12451007Ssklower if (tpcb == 0) 12551007Ssklower return; 12636415Ssklower IncStat(ts_Eset); 12736415Ssklower if (ticks == 0) 12836415Ssklower ticks = 1; 129*51204Ssklower callp = tpcb->tp_timer + fun; 130*51204Ssklower if (*callp == 0 || *callp > ticks) 131*51204Ssklower *callp = ticks; 13236415Ssklower } 13336415Ssklower 13436415Ssklower /* 13536415Ssklower * CALLED FROM: 13636415Ssklower * tp.trans all over 13736415Ssklower * FUNCTION and ARGUMENTS: 13836415Ssklower * Cancel all occurrences of E-timer function (fun) for reference (refp) 13936415Ssklower */ 14036415Ssklower void 141*51204Ssklower tp_euntimeout(tpcb, fun) 142*51204Ssklower register struct tp_pcb *tpcb; 14336415Ssklower int fun; 14436415Ssklower { 14536415Ssklower IFTRACE(D_TIMER) 146*51204Ssklower tptrace(TPPTmisc, "tp_euntimeout ref", tpcb->tp_lref, 0, 0, 0); 14736415Ssklower ENDTRACE 14836415Ssklower 14951007Ssklower if (tpcb) 150*51204Ssklower tpcb->tp_timer[fun] = 0; 15136415Ssklower } 15236415Ssklower 15336415Ssklower /**************** c timers ********************** 15436415Ssklower * 15536415Ssklower * These are not chained together; they sit 15636415Ssklower * in the tp_ref structure. they are the kind that 15736415Ssklower * are typically cancelled so it's faster not to 15836415Ssklower * mess with the chains 15936415Ssklower */ 16036415Ssklower 16136415Ssklower /* 16236415Ssklower * CALLED FROM: 16336415Ssklower * the clock, every 500 ms 16436415Ssklower * FUNCTION and ARGUMENTS: 16536415Ssklower * Look for open references with active timers. 16636415Ssklower * If they exist, call the appropriate timer routines to update 16736415Ssklower * the timers and possibly generate events. 16836415Ssklower * (The E timers are done in other procedures; the C timers are 16936415Ssklower * updated here, and events for them are generated here.) 17036415Ssklower */ 17136415Ssklower ProtoHook 17236415Ssklower tp_slowtimo() 17336415Ssklower { 174*51204Ssklower register u_int *cp, *cpbase; 17551007Ssklower register struct tp_ref *rp; 17651007Ssklower struct tp_pcb *tpcb; 17736415Ssklower struct tp_event E; 17851007Ssklower int s = splnet(), t; 17936415Ssklower 18036415Ssklower /* check only open reference structures */ 18136415Ssklower IncStat(ts_Cticks); 18251007Ssklower /* tp_ref[0] is never used */ 18351007Ssklower for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) { 18451007Ssklower if ((tpcb = rp->tpr_pcb) == 0 || rp->tpr_state < REF_OPEN) 18536415Ssklower continue; 186*51204Ssklower cpbase = tpcb->tp_timer; 187*51204Ssklower t = TM_NTIMERS; 188*51204Ssklower /* check the timers */ 18951007Ssklower for (cp = cpbase + t; (--t, --cp) >= cpbase; ) { 190*51204Ssklower if (*cp && --(*cp) <= 0 ) { 191*51204Ssklower *cp = 0; 19251007Ssklower E.ev_number = t; 19351007Ssklower IFDEBUG(D_TIMER) 19451007Ssklower printf("C expired! type 0x%x\n", t); 19551007Ssklower ENDDEBUG 19651007Ssklower IncStat(ts_Cexpired); 19751007Ssklower tp_driver( rp->tpr_pcb, &E); 19851007Ssklower if (t == TM_reference && tpcb->tp_state == TP_CLOSED) { 19951007Ssklower if (tpcb->tp_notdetached) { 20051007Ssklower IFDEBUG(D_CONN) 20151007Ssklower printf("PRU_DETACH: not detached\n"); 20251007Ssklower ENDDEBUG 20351007Ssklower tp_detach(tpcb); 20451007Ssklower } 20551007Ssklower /* XXX wart; where else to do it? */ 20651007Ssklower free((caddr_t)tpcb, M_PCB); 20751007Ssklower } 20836415Ssklower } 20936415Ssklower } 21036415Ssklower } 21136415Ssklower splx(s); 21236415Ssklower return 0; 21336415Ssklower } 21436415Ssklower 215*51204Ssklower /* 216*51204Ssklower * Called From: tp.trans from tp_slowtimo() -- retransmission timer went off. 217*51204Ssklower */ 218*51204Ssklower tp_data_retrans(tpcb) 219*51204Ssklower register struct tp_pcb *tpcb; 220*51204Ssklower { 221*51204Ssklower int rexmt, win; 222*51204Ssklower tpcb->tp_rttemit = 0; /* cancel current round trip time */ 223*51204Ssklower tpcb->tp_dupacks = 0; 224*51204Ssklower tpcb->tp_sndnxt = tpcb->tp_snduna; 225*51204Ssklower if (tpcb->tp_fcredit == 0) { 226*51204Ssklower /* 227*51204Ssklower * We transmitted new data, started timing it and the window 228*51204Ssklower * got shrunk under us. This can only happen if all data 229*51204Ssklower * that they wanted us to send got acked, so don't 230*51204Ssklower * bother shrinking the congestion windows, et. al. 231*51204Ssklower * The retransmission timer should have been reset in goodack() 232*51204Ssklower */ 233*51204Ssklower tpcb->tp_rxtshift = 0; 234*51204Ssklower tpcb->tp_timer[TM_data_retrans] = 0; 235*51204Ssklower tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks; 236*51204Ssklower } 237*51204Ssklower rexmt = tpcb->tp_dt_ticks << min(tpcb->tp_rxtshift, TP_MAXRXTSHIFT); 238*51204Ssklower win = min(tpcb->tp_fcredit, (tpcb->tp_cong_win / tpcb->tp_l_tpdusize / 2)); 239*51204Ssklower win = max(win, 2); 240*51204Ssklower tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* slow start again. */ 241*51204Ssklower tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize; 242*51204Ssklower /* We're losing; our srtt estimate is probably bogus. 243*51204Ssklower * Clobber it so we'll take the next rtt measurement as our srtt; 244*51204Ssklower * Maintain current rxt times until then. 245*51204Ssklower */ 246*51204Ssklower if (++tpcb->tp_rxtshift > TP_NRETRANS / 4) { 247*51204Ssklower /* tpcb->tp_nlprotosw->nlp_losing(tpcb->tp_npcb) someday */ 248*51204Ssklower tpcb->tp_rtt = 0; 249*51204Ssklower } 250*51204Ssklower if (rexmt > 128) 251*51204Ssklower rexmt = 128; /* XXXX value from tcp_timer.h */ 252*51204Ssklower tpcb->tp_timer[TM_data_retrans] = tpcb->tp_rxtcur = rexmt; 253*51204Ssklower tp_send(tpcb); 254*51204Ssklower } 255*51204Ssklower 25651024Ssklower int 25751024Ssklower tp_fasttimo() 25851024Ssklower { 25951024Ssklower register struct tp_pcb *t; 26051024Ssklower int s = splnet(); 26151024Ssklower struct tp_event E; 26251024Ssklower 26351024Ssklower E.ev_number = TM_sendack; 26451024Ssklower while ((t = tp_ftimeolist) != (struct tp_pcb *)&tp_ftimeolist) { 26551024Ssklower if (t == 0) { 26651024Ssklower printf("tp_fasttimeo: should panic"); 26751024Ssklower tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist; 26851024Ssklower } else { 26951024Ssklower if (t->tp_flags & TPF_DELACK) { 27051024Ssklower t->tp_flags &= ~TPF_DELACK; 27151024Ssklower IncStat(ts_Fdelack); 27251024Ssklower tp_driver(t, &E); 273*51204Ssklower t->tp_timer[TM_sendack] = t->tp_keepalive_ticks; 27451024Ssklower } else 27551024Ssklower IncStat(ts_Fpruned); 27651024Ssklower tp_ftimeolist = t->tp_fasttimeo; 27751024Ssklower t->tp_fasttimeo = 0; 27851024Ssklower } 27951024Ssklower } 28051024Ssklower splx(s); 28151024Ssklower } 28251024Ssklower 28336415Ssklower /* 28436415Ssklower * CALLED FROM: 28536415Ssklower * tp.trans, tp_emit() 28636415Ssklower * FUNCTION and ARGUMENTS: 28736415Ssklower * Set a C type timer of type (which) to go off after (ticks) time. 28836415Ssklower */ 28936415Ssklower void 290*51204Ssklower tp_ctimeout(tpcb, which, ticks) 291*51204Ssklower register struct tp_pcb *tpcb; 29236415Ssklower int which, ticks; 29336415Ssklower { 29436415Ssklower 29536415Ssklower IFTRACE(D_TIMER) 29636415Ssklower tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active", 297*51204Ssklower tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]); 29836415Ssklower ENDTRACE 299*51204Ssklower if(tpcb->tp_timer[which]) 30036415Ssklower IncStat(ts_Ccan_act); 30136415Ssklower IncStat(ts_Cset); 30251007Ssklower if (ticks <= 0) 30351007Ssklower ticks = 1; 304*51204Ssklower tpcb->tp_timer[which] = ticks; 30536415Ssklower } 30636415Ssklower 30736415Ssklower /* 30836415Ssklower * CALLED FROM: 30936415Ssklower * tp.trans 31036415Ssklower * FUNCTION and ARGUMENTS: 31136415Ssklower * Version of tp_ctimeout that resets the C-type time if the 31236415Ssklower * parameter (ticks) is > the current value of the timer. 31336415Ssklower */ 31436415Ssklower void 315*51204Ssklower tp_ctimeout_MIN(tpcb, which, ticks) 316*51204Ssklower register struct tp_pcb *tpcb; 31736415Ssklower int which, ticks; 31836415Ssklower { 31936415Ssklower IFTRACE(D_TIMER) 32036415Ssklower tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active", 321*51204Ssklower tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]); 32236415Ssklower ENDTRACE 32336415Ssklower IncStat(ts_Cset); 324*51204Ssklower if (tpcb->tp_timer[which]) { 325*51204Ssklower tpcb->tp_timer[which] = MIN(ticks, tpcb->tp_timer[which]); 32651007Ssklower IncStat(ts_Ccan_act); 32751007Ssklower } else 328*51204Ssklower tpcb->tp_timer[which] = ticks; 32936415Ssklower } 33036415Ssklower 33136415Ssklower /* 33236415Ssklower * CALLED FROM: 33336415Ssklower * tp.trans 33436415Ssklower * FUNCTION and ARGUMENTS: 33536415Ssklower * Cancel the (which) timer in the ref structure indicated by (refp). 33636415Ssklower */ 33736415Ssklower void 338*51204Ssklower tp_cuntimeout(tpcb, which) 339*51204Ssklower register struct tp_pcb *tpcb; 34036415Ssklower int which; 34136415Ssklower { 34236415Ssklower IFDEBUG(D_TIMER) 343*51204Ssklower printf("tp_cuntimeout(0x%x, %d) active %d\n", 344*51204Ssklower tpcb, which, tpcb->tp_timer[which]); 34536415Ssklower ENDDEBUG 34636415Ssklower 34736415Ssklower IFTRACE(D_TIMER) 34836415Ssklower tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref, 349*51204Ssklower which, tpcb->tp_timer[which], 0); 35036415Ssklower ENDTRACE 35136415Ssklower 352*51204Ssklower if (tpcb->tp_timer[which]) 35336415Ssklower IncStat(ts_Ccan_act); 35436415Ssklower else 35536415Ssklower IncStat(ts_Ccan_inact); 356*51204Ssklower tpcb->tp_timer[which] = 0; 35736415Ssklower } 358