123194Smckusick /* 223194Smckusick * Copyright (c) 1982 Regents of the University of California. 323194Smckusick * All rights reserved. The Berkeley software License Agreement 423194Smckusick * specifies the terms and conditions for redistribution. 523194Smckusick * 6*26118Skarels * @(#)tcp_timer.c 6.11 (Berkeley) 02/08/86 723194Smckusick */ 85069Swnj 917064Sbloom #include "param.h" 1017064Sbloom #include "systm.h" 1117064Sbloom #include "mbuf.h" 1217064Sbloom #include "socket.h" 1317064Sbloom #include "socketvar.h" 1417064Sbloom #include "protosw.h" 1517064Sbloom #include "errno.h" 168697Sroot 178697Sroot #include "../net/if.h" 188697Sroot #include "../net/route.h" 1910896Ssam 2017064Sbloom #include "in.h" 2117064Sbloom #include "in_pcb.h" 2217064Sbloom #include "in_systm.h" 2317064Sbloom #include "ip.h" 2417064Sbloom #include "ip_var.h" 2517064Sbloom #include "tcp.h" 2617064Sbloom #include "tcp_fsm.h" 2717064Sbloom #include "tcp_seq.h" 2817064Sbloom #include "tcp_timer.h" 2917064Sbloom #include "tcp_var.h" 3017064Sbloom #include "tcpip.h" 315069Swnj 325442Swnj int tcpnodelack = 0; 335069Swnj /* 345069Swnj * Fast timeout routine for processing delayed acks 355069Swnj */ 365069Swnj tcp_fasttimo() 375069Swnj { 385284Sroot register struct inpcb *inp; 395284Sroot register struct tcpcb *tp; 405284Sroot int s = splnet(); 415069Swnj 425691Swnj inp = tcb.inp_next; 435691Swnj if (inp) 445691Swnj for (; inp != &tcb; inp = inp->inp_next) 455284Sroot if ((tp = (struct tcpcb *)inp->inp_ppcb) && 465284Sroot (tp->t_flags & TF_DELACK)) { 475284Sroot tp->t_flags &= ~TF_DELACK; 485284Sroot tp->t_flags |= TF_ACKNOW; 495284Sroot (void) tcp_output(tp); 505284Sroot } 515284Sroot splx(s); 525069Swnj } 535069Swnj 545069Swnj /* 555069Swnj * Tcp protocol timeout routine called every 500 ms. 565069Swnj * Updates the timers in all active tcb's and 575069Swnj * causes finite state machine actions if timers expire. 585069Swnj */ 595069Swnj tcp_slowtimo() 605069Swnj { 616212Swnj register struct inpcb *ip, *ipnxt; 625069Swnj register struct tcpcb *tp; 635069Swnj int s = splnet(); 645069Swnj register int i; 655069Swnj 665069Swnj /* 675069Swnj * Search through tcb's and update active timers. 685069Swnj */ 695245Sroot ip = tcb.inp_next; 705245Sroot if (ip == 0) { 715245Sroot splx(s); 725245Sroot return; 735245Sroot } 7417315Skarels for (; ip != &tcb; ip = ipnxt) { 7517315Skarels ipnxt = ip->inp_next; 765069Swnj tp = intotcpcb(ip); 775260Swnj if (tp == 0) 785260Swnj continue; 795075Swnj for (i = 0; i < TCPT_NTIMERS; i++) { 806212Swnj if (tp->t_timer[i] && --tp->t_timer[i] == 0) { 815069Swnj (void) tcp_usrreq(tp->t_inpcb->inp_socket, 825069Swnj PRU_SLOWTIMO, (struct mbuf *)0, 8312764Ssam (struct mbuf *)i, (struct mbuf *)0); 846212Swnj if (ipnxt->inp_prev != ip) 856212Swnj goto tpgone; 866212Swnj } 875069Swnj } 885165Swnj tp->t_idle++; 895165Swnj if (tp->t_rtt) 905165Swnj tp->t_rtt++; 916212Swnj tpgone: 9217315Skarels ; 935069Swnj } 945075Swnj tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ 95*26118Skarels #ifdef COMPAT_42 96*26118Skarels if ((int)tcp_iss < 0) 97*26118Skarels tcp_iss = 0; /* XXX */ 98*26118Skarels #endif 995069Swnj splx(s); 1005069Swnj } 1015069Swnj 1025069Swnj /* 1035075Swnj * Cancel all timers for TCP tp. 1045069Swnj */ 1055089Swnj tcp_canceltimers(tp) 1065069Swnj struct tcpcb *tp; 1075069Swnj { 1085069Swnj register int i; 1095069Swnj 1105075Swnj for (i = 0; i < TCPT_NTIMERS; i++) 1115075Swnj tp->t_timer[i] = 0; 1125069Swnj } 1135069Swnj 11425888Skarels int tcp_backoff[TCP_MAXRXTSHIFT+1] = 11525888Skarels { 1, 2, 4, 6, 8, 10, 15, 20, 30, 30, 30, 30, 30 }; 1165069Swnj /* 1175165Swnj * TCP timer processing. 1185069Swnj */ 11910396Ssam struct tcpcb * 1205075Swnj tcp_timers(tp, timer) 1215069Swnj register struct tcpcb *tp; 1225075Swnj int timer; 1235069Swnj { 12425888Skarels register int rexmt; 1255069Swnj 1265089Swnj switch (timer) { 1275069Swnj 1285165Swnj /* 12924819Skarels * 2 MSL timeout in shutdown went off. If we're closed but 13024819Skarels * still waiting for peer to close and connection has been idle 13124819Skarels * too long, or if 2MSL time is up from TIME_WAIT, delete connection 13224819Skarels * control block. Otherwise, check again in a bit. 1335165Swnj */ 1345075Swnj case TCPT_2MSL: 13524819Skarels if (tp->t_state != TCPS_TIME_WAIT && 13624819Skarels tp->t_idle <= TCPTV_MAXIDLE) 13724819Skarels tp->t_timer[TCPT_2MSL] = TCPTV_KEEP; 13824819Skarels else 13924819Skarels tp = tcp_close(tp); 14010396Ssam break; 1415069Swnj 1425165Swnj /* 1435165Swnj * Retransmission timer went off. Message has not 1445165Swnj * been acked within retransmit interval. Back off 14517362Skarels * to a longer retransmit interval and retransmit one segment. 1465165Swnj */ 1475075Swnj case TCPT_REXMT: 1485165Swnj tp->t_rxtshift++; 1495691Swnj if (tp->t_rxtshift > TCP_MAXRXTSHIFT) { 15010396Ssam tp = tcp_drop(tp, ETIMEDOUT); 15110396Ssam break; 1525691Swnj } 15317362Skarels /* 15417362Skarels * If losing, let the lower level know 15517362Skarels * and try for a better route. 15617362Skarels */ 15724819Skarels if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 3) 15825509Skarels in_losing(tp->t_inpcb); 15925888Skarels if (tp->t_srtt == 0) 16025888Skarels rexmt = tcp_beta * TCPTV_SRTTDFLT; 16125888Skarels else 16225888Skarels rexmt = (int)(tcp_beta * tp->t_srtt); 16325888Skarels rexmt *= tcp_backoff[tp->t_rxtshift - 1]; 16425888Skarels TCPT_RANGESET(tp->t_timer[TCPT_REXMT], rexmt, 1656474Sroot TCPTV_MIN, TCPTV_MAX); 1665165Swnj tp->snd_nxt = tp->snd_una; 16717314Skarels /* 16821120Skarels * If timing a segment in this window, 16921120Skarels * and we have already gotten some timing estimate, 17021120Skarels * stop the timer. 17117314Skarels */ 17221120Skarels if (tp->t_rtt && tp->t_srtt) 17317314Skarels tp->t_rtt = 0; 1745165Swnj (void) tcp_output(tp); 17510396Ssam break; 1765069Swnj 1775165Swnj /* 1785165Swnj * Persistance timer into zero window. 1795165Swnj * Force a byte to be output, if possible. 1805165Swnj */ 1815075Swnj case TCPT_PERSIST: 1827156Swnj tcp_setpersist(tp); 1835165Swnj tp->t_force = 1; 1845165Swnj (void) tcp_output(tp); 1855165Swnj tp->t_force = 0; 18610396Ssam break; 1875069Swnj 1885165Swnj /* 1895165Swnj * Keep-alive timer went off; send something 1905165Swnj * or drop connection if idle for too long. 1915165Swnj */ 1925075Swnj case TCPT_KEEP: 1936304Sroot if (tp->t_state < TCPS_ESTABLISHED) 1946304Sroot goto dropit; 1956267Sroot if (tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE) { 1966304Sroot if (tp->t_idle >= TCPTV_MAXIDLE) 1976304Sroot goto dropit; 1986267Sroot /* 1996267Sroot * Saying tp->rcv_nxt-1 lies about what 2006267Sroot * we have received, and by the protocol spec 2016267Sroot * requires the correspondent TCP to respond. 2026267Sroot * Saying tp->snd_una-1 causes the transmitted 2036267Sroot * byte to lie outside the receive window; this 2046267Sroot * is important because we don't necessarily 2056267Sroot * have a byte in the window to send (consider 2066267Sroot * a one-way stream!) 2076267Sroot */ 2085392Swnj tcp_respond(tp, 2096267Sroot tp->t_template, tp->rcv_nxt-1, tp->snd_una-1, 0); 2106267Sroot } else 2116212Swnj tp->t_idle = 0; 2125165Swnj tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; 21310396Ssam break; 2146304Sroot dropit: 21510396Ssam tp = tcp_drop(tp, ETIMEDOUT); 21610396Ssam break; 2175069Swnj } 21810396Ssam return (tp); 2195069Swnj } 220