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