1/* $NetBSD: tp_timer.c,v 1.18 2007/03/04 06:03:33 christos Exp $ */ 2 3/*- 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 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. 18 * 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 29 * SUCH DAMAGE. 30 * 31 * @(#)tp_timer.c 8.1 (Berkeley) 6/10/93 32 */ 33 34/*********************************************************** 35 Copyright IBM Corporation 1987 36 37 All Rights Reserved 38 39Permission to use, copy, modify, and distribute this software and its 40documentation for any purpose and without fee is hereby granted, 41provided that the above copyright notice appear in all copies and that 42both that copyright notice and this permission notice appear in 43supporting documentation, and that the name of IBM not be 44used in advertising or publicity pertaining to distribution of the 45software without specific, written prior permission. 46 47IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 48ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 49IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 50ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 51WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 52ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 53SOFTWARE. 54 55******************************************************************/ 56 57/* 58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 59 */ 60 61#include <sys/cdefs.h> 62__KERNEL_RCSID(0, "$NetBSD: tp_timer.c,v 1.18 2007/03/04 06:03:33 christos Exp $"); 63 64#include <sys/param.h> 65#include <sys/systm.h> 66#include <sys/time.h> 67#include <sys/malloc.h> 68#include <sys/protosw.h> 69#include <sys/socket.h> 70#include <sys/kernel.h> 71 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> 81 82struct tp_ref *tp_ref; 83int tp_rttdiv, tp_rttadd, N_TPREF = 127; 84struct tp_refinfo tp_refinfo; 85struct tp_pcb *tp_ftimeolist = (struct tp_pcb *) & tp_ftimeolist; 86 87/* 88 * CALLED FROM: 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 93 */ 94void 95tp_timerinit(void) 96{ 97 int s; 98 /* 99 * Initialize storage 100 */ 101 if (tp_refinfo.tpr_base) 102 return; 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; 110} 111#ifdef TP_DEBUG_TIMERS 112/********************** e timers *************************/ 113 114/* 115 * CALLED FROM: 116 * tp.trans all over 117 * FUNCTION and ARGUMENTS: 118 * Set an E type timer. 119 */ 120void 121tp_etimeout( 122 struct tp_pcb *tpcb, 123 int fun, /* function to be called */ 124 int ticks) 125{ 126 127 u_int *callp; 128#ifdef ARGO_DEBUG 129 if (argo_debug[D_TIMER]) { 130 printf("etimeout pcb %p state 0x%x\n", tpcb, tpcb->tp_state); 131 } 132#endif 133#ifdef TPPT 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); 137 } 138#endif 139 if (tpcb == 0) 140 return; 141 IncStat(ts_Eset); 142 if (ticks == 0) 143 ticks = 1; 144 callp = tpcb->tp_timer + fun; 145 if (*callp == 0 || *callp > ticks) 146 *callp = ticks; 147} 148 149/* 150 * CALLED FROM: 151 * tp.trans all over 152 * FUNCTION and ARGUMENTS: 153 * Cancel all occurrences of E-timer function (fun) for reference (refp) 154 */ 155void 156tp_euntimeout(struct tp_pcb *tpcb, int fun) 157{ 158#ifdef TPPT 159 if (tp_traceflags[D_TIMER]) { 160 tptrace(TPPTmisc, "tp_euntimeout ref", tpcb->tp_lref, 0, 0, 0); 161 } 162#endif 163 164 if (tpcb) 165 tpcb->tp_timer[fun] = 0; 166} 167 168/**************** c timers ********************** 169 * 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 174 */ 175#endif 176/* 177 * CALLED FROM: 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. 183 */ 184void 185tp_slowtimo(void) 186{ 187 u_int *cp; 188 struct tp_ref *rp; 189 struct tp_pcb *tpcb; 190 struct tp_event E; 191 int t; 192 193 mutex_enter(softnet_lock); 194 KERNEL_LOCK(1, NULL); 195 /* check only open reference structures */ 196 IncStat(ts_Cticks); 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) 200 continue; 201 /* check the timers */ 202 for (t = 0; t < TM_NTIMERS; t++) { 203 cp = tpcb->tp_timer + t; 204 if (*cp && --(*cp) <= 0) { 205 *cp = 0; 206 E.ev_number = t; 207#ifdef ARGO_DEBUG 208 if (argo_debug[D_TIMER]) { 209 printf("tp_slowtimo: pcb %p t %d\n", 210 tpcb, t); 211 } 212#endif 213 IncStat(ts_Cexpired); 214 tp_driver(tpcb, &E); 215 if (t == TM_reference && tpcb->tp_state == TP_CLOSED) { 216 if (tpcb->tp_notdetached) { 217#ifdef ARGO_DEBUG 218 if (argo_debug[D_CONN]) { 219 printf("PRU_DETACH: not detached\n"); 220 } 221#endif 222 tp_detach(tpcb); 223 } 224 /* XXX wart; where else to do it? */ 225 free((void *) tpcb, M_PCB); 226 break; 227 } 228 } 229 } 230 } 231 KERNEL_UNLOCK_ONE(NULL); 232 mutex_exit(softnet_lock); 233} 234 235/* 236 * Called From: tp.trans from tp_slowtimo() -- retransmission timer went off. 237 */ 238void 239tp_data_retrans(struct tp_pcb *tpcb) 240{ 241 int rexmt, win; 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) { 246 /* 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() 252 */ 253#ifdef ARGO_DEBUG 254 if (argo_debug[D_ACKRECV]) { 255 printf("tp_data_retrans: 0 window tpcb %p una 0x%x\n", 256 tpcb, tpcb->tp_snduna); 257 } 258#endif 259 tpcb->tp_rxtshift = 0; 260 tpcb->tp_timer[TM_data_retrans] = 0; 261 tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks; 262 return; 263 } 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)); 266 win = max(win, 2); 267 tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* slow start again. */ 268 tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize; 269 /* 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. 273 */ 274 if (++tpcb->tp_rxtshift > TP_NRETRANS / 4) { 275 /* tpcb->tp_nlprotosw->nlp_losing(tpcb->tp_npcb) someday */ 276 tpcb->tp_rtt = 0; 277 } 278 TP_RANGESET(tpcb->tp_rxtcur, rexmt, tpcb->tp_peer_acktime, 128); 279 tpcb->tp_timer[TM_data_retrans] = tpcb->tp_rxtcur; 280 tp_send(tpcb); 281} 282 283void 284tp_fasttimo(void) 285{ 286 struct tp_pcb *t; 287 struct tp_event E; 288 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) { 293 if (t == 0) { 294 printf("tp_fasttimeo: should panic"); 295 tp_ftimeolist = (struct tp_pcb *) & tp_ftimeolist; 296 } else { 297 if (t->tp_flags & TPF_DELACK) { 298 IncStat(ts_Fdelack); 299 tp_driver(t, &E); 300 t->tp_flags &= ~TPF_DELACK; 301 } else 302 IncStat(ts_Fpruned); 303 tp_ftimeolist = t->tp_fasttimeo; 304 t->tp_fasttimeo = 0; 305 } 306 } 307 KERNEL_UNLOCK_ONE(NULL); 308 mutex_exit(softnet_lock); 309} 310 311#ifdef TP_DEBUG_TIMERS 312/* 313 * CALLED FROM: 314 * tp.trans, tp_emit() 315 * FUNCTION and ARGUMENTS: 316 * Set a C type timer of type (which) to go off after (ticks) time. 317 */ 318void 319tp_ctimeout(struct tp_pcb *tpcb, int which, int ticks) 320{ 321 322#ifdef TPPT 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]); 326 } 327#endif 328 if (tpcb->tp_timer[which]) 329 IncStat(ts_Ccan_act); 330 IncStat(ts_Cset); 331 if (ticks <= 0) 332 ticks = 1; 333 tpcb->tp_timer[which] = ticks; 334} 335 336/* 337 * CALLED FROM: 338 * tp.trans 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. 342 */ 343void 344tp_ctimeout_MIN(struct tp_pcb *tpcb, int which, int ticks) 345{ 346#ifdef TPPT 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]); 350 } 351#endif 352 IncStat(ts_Cset); 353 if (tpcb->tp_timer[which]) { 354 tpcb->tp_timer[which] = min(ticks, tpcb->tp_timer[which]); 355 IncStat(ts_Ccan_act); 356 } else 357 tpcb->tp_timer[which] = ticks; 358} 359 360/* 361 * CALLED FROM: 362 * tp.trans 363 * FUNCTION and ARGUMENTS: 364 * Cancel the (which) timer in the ref structure indicated by (refp). 365 */ 366void 367tp_cuntimeout(struct tp_pcb *tpcb, int which) 368{ 369#ifdef ARGO_DEBUG 370 if (argo_debug[D_TIMER]) { 371 printf("tp_cuntimeout(%p, %d) active %d\n", 372 tpcb, which, tpcb->tp_timer[which]); 373 } 374#endif 375 376#ifdef TPPT 377 if (tp_traceflags[D_TIMER]) { 378 tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp - tp_ref, 379 which, tpcb->tp_timer[which], 0); 380 } 381#endif 382 383 if (tpcb->tp_timer[which]) 384 IncStat(ts_Ccan_act); 385 else 386 IncStat(ts_Ccan_inact); 387 tpcb->tp_timer[which] = 0; 388} 389#endif 390