123194Smckusick /* 229153Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 332789Sbostic * All rights reserved. 423194Smckusick * 532789Sbostic * Redistribution and use in source and binary forms are permitted 632789Sbostic * provided that this notice is preserved and that due credit is given 732789Sbostic * to the University of California at Berkeley. The name of the University 832789Sbostic * may not be used to endorse or promote products derived from this 932789Sbostic * software without specific prior written permission. This software 1032789Sbostic * is provided ``as is'' without express or implied warranty. 1132789Sbostic * 12*33746Skarels * @(#)tcp_timer.c 7.12 (Berkeley) 03/16/88 1323194Smckusick */ 145069Swnj 1517064Sbloom #include "param.h" 1617064Sbloom #include "systm.h" 1717064Sbloom #include "mbuf.h" 1817064Sbloom #include "socket.h" 1917064Sbloom #include "socketvar.h" 2017064Sbloom #include "protosw.h" 2117064Sbloom #include "errno.h" 228697Sroot 238697Sroot #include "../net/if.h" 248697Sroot #include "../net/route.h" 2510896Ssam 2617064Sbloom #include "in.h" 2717064Sbloom #include "in_pcb.h" 2817064Sbloom #include "in_systm.h" 2917064Sbloom #include "ip.h" 3017064Sbloom #include "ip_var.h" 3117064Sbloom #include "tcp.h" 3217064Sbloom #include "tcp_fsm.h" 3317064Sbloom #include "tcp_seq.h" 3417064Sbloom #include "tcp_timer.h" 3517064Sbloom #include "tcp_var.h" 3617064Sbloom #include "tcpip.h" 375069Swnj 385442Swnj int tcpnodelack = 0; 39*33746Skarels int tcp_keepidle = TCPTV_KEEP_IDLE; 40*33746Skarels int tcp_keepintvl = TCPTV_KEEPINTVL; 41*33746Skarels int tcp_maxidle; 425069Swnj /* 435069Swnj * Fast timeout routine for processing delayed acks 445069Swnj */ 455069Swnj tcp_fasttimo() 465069Swnj { 475284Sroot register struct inpcb *inp; 485284Sroot register struct tcpcb *tp; 495284Sroot int s = splnet(); 505069Swnj 515691Swnj inp = tcb.inp_next; 525691Swnj if (inp) 535691Swnj for (; inp != &tcb; inp = inp->inp_next) 545284Sroot if ((tp = (struct tcpcb *)inp->inp_ppcb) && 555284Sroot (tp->t_flags & TF_DELACK)) { 565284Sroot tp->t_flags &= ~TF_DELACK; 575284Sroot tp->t_flags |= TF_ACKNOW; 5830524Skarels tcpstat.tcps_delack++; 595284Sroot (void) tcp_output(tp); 605284Sroot } 615284Sroot splx(s); 625069Swnj } 635069Swnj 645069Swnj /* 655069Swnj * Tcp protocol timeout routine called every 500 ms. 665069Swnj * Updates the timers in all active tcb's and 675069Swnj * causes finite state machine actions if timers expire. 685069Swnj */ 695069Swnj tcp_slowtimo() 705069Swnj { 716212Swnj register struct inpcb *ip, *ipnxt; 725069Swnj register struct tcpcb *tp; 735069Swnj int s = splnet(); 745069Swnj register int i; 755069Swnj 76*33746Skarels tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; 775069Swnj /* 785069Swnj * Search through tcb's and update active timers. 795069Swnj */ 805245Sroot ip = tcb.inp_next; 815245Sroot if (ip == 0) { 825245Sroot splx(s); 835245Sroot return; 845245Sroot } 8517315Skarels for (; ip != &tcb; ip = ipnxt) { 8617315Skarels ipnxt = ip->inp_next; 875069Swnj tp = intotcpcb(ip); 885260Swnj if (tp == 0) 895260Swnj continue; 905075Swnj for (i = 0; i < TCPT_NTIMERS; i++) { 916212Swnj if (tp->t_timer[i] && --tp->t_timer[i] == 0) { 925069Swnj (void) tcp_usrreq(tp->t_inpcb->inp_socket, 935069Swnj PRU_SLOWTIMO, (struct mbuf *)0, 9412764Ssam (struct mbuf *)i, (struct mbuf *)0); 956212Swnj if (ipnxt->inp_prev != ip) 966212Swnj goto tpgone; 976212Swnj } 985069Swnj } 995165Swnj tp->t_idle++; 1005165Swnj if (tp->t_rtt) 1015165Swnj tp->t_rtt++; 1026212Swnj tpgone: 10317315Skarels ; 1045069Swnj } 1055075Swnj tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ 10627059Skarels #ifdef TCP_COMPAT_42 10726118Skarels if ((int)tcp_iss < 0) 10826118Skarels tcp_iss = 0; /* XXX */ 10926118Skarels #endif 1105069Swnj splx(s); 1115069Swnj } 1125069Swnj 1135069Swnj /* 1145075Swnj * Cancel all timers for TCP tp. 1155069Swnj */ 1165089Swnj tcp_canceltimers(tp) 1175069Swnj struct tcpcb *tp; 1185069Swnj { 1195069Swnj register int i; 1205069Swnj 1215075Swnj for (i = 0; i < TCPT_NTIMERS; i++) 1225075Swnj tp->t_timer[i] = 0; 1235069Swnj } 1245069Swnj 12532034Skarels int tcp_backoff[TCP_MAXRXTSHIFT + 1] = 12632034Skarels { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 12730762Skarels 1285069Swnj /* 1295165Swnj * TCP timer processing. 1305069Swnj */ 13110396Ssam struct tcpcb * 1325075Swnj tcp_timers(tp, timer) 1335069Swnj register struct tcpcb *tp; 1345075Swnj int timer; 1355069Swnj { 13625888Skarels register int rexmt; 1375069Swnj 1385089Swnj switch (timer) { 1395069Swnj 1405165Swnj /* 14124819Skarels * 2 MSL timeout in shutdown went off. If we're closed but 14224819Skarels * still waiting for peer to close and connection has been idle 14324819Skarels * too long, or if 2MSL time is up from TIME_WAIT, delete connection 14424819Skarels * control block. Otherwise, check again in a bit. 1455165Swnj */ 1465075Swnj case TCPT_2MSL: 14724819Skarels if (tp->t_state != TCPS_TIME_WAIT && 148*33746Skarels tp->t_idle <= tcp_maxidle) 149*33746Skarels tp->t_timer[TCPT_2MSL] = tcp_keepintvl; 15024819Skarels else 15124819Skarels tp = tcp_close(tp); 15210396Ssam break; 1535069Swnj 1545165Swnj /* 1555165Swnj * Retransmission timer went off. Message has not 1565165Swnj * been acked within retransmit interval. Back off 15717362Skarels * to a longer retransmit interval and retransmit one segment. 1585165Swnj */ 1595075Swnj case TCPT_REXMT: 16032034Skarels if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { 16132034Skarels tp->t_rxtshift = TCP_MAXRXTSHIFT; 16230524Skarels tcpstat.tcps_timeoutdrop++; 16310396Ssam tp = tcp_drop(tp, ETIMEDOUT); 16410396Ssam break; 1655691Swnj } 16630524Skarels tcpstat.tcps_rexmttimeo++; 16731726Skarels rexmt = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; 16831726Skarels rexmt *= tcp_backoff[tp->t_rxtshift]; 16932034Skarels TCPT_RANGESET(tp->t_rxtcur, rexmt, TCPTV_MIN, TCPTV_REXMTMAX); 17032034Skarels tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; 17126989Skarels /* 17232034Skarels * If losing, let the lower level know and try for 17332034Skarels * a better route. Also, if we backed off this far, 17432034Skarels * our srtt estimate is probably bogus. Clobber it 17532034Skarels * so we'll take the next rtt measurement as our srtt; 17632034Skarels * move the current srtt into rttvar to keep the current 17732034Skarels * retransmit times until then. 17826989Skarels */ 17932034Skarels if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { 18026989Skarels in_losing(tp->t_inpcb); 18132034Skarels tp->t_rttvar += (tp->t_srtt >> 2); 18232034Skarels tp->t_srtt = 0; 18332034Skarels } 1845165Swnj tp->snd_nxt = tp->snd_una; 18517314Skarels /* 18631726Skarels * If timing a segment in this window, stop the timer. 18717314Skarels */ 18831726Skarels tp->t_rtt = 0; 18931442Skarels /* 19031442Skarels * Close the congestion window down to one segment 19131442Skarels * (we'll open it by one segment for each ack we get). 19231442Skarels * Since we probably have a window's worth of unacked 19331442Skarels * data accumulated, this "slow start" keeps us from 19431442Skarels * dumping all that data as back-to-back packets (which 19531442Skarels * might overwhelm an intermediate gateway). 19632100Skarels * 19732100Skarels * There are two phases to the opening: Initially we 19832100Skarels * open by one mss on each ack. This makes the window 19932100Skarels * size increase exponentially with time. If the 20032100Skarels * window is larger than the path can handle, this 20132100Skarels * exponential growth results in dropped packet(s) 20232100Skarels * almost immediately. To get more time between 20332100Skarels * drops but still "push" the network to take advantage 20432100Skarels * of improving conditions, we switch from exponential 20532100Skarels * to linear window opening at some threshhold size. 20632100Skarels * For a threshhold, we use half the current window 20732100Skarels * size, truncated to a multiple of the mss. 20832100Skarels * 20932100Skarels * (the minimum cwnd that will give us exponential 21032100Skarels * growth is 2 mss. We don't allow the threshhold 21132100Skarels * to go below this.) 21231442Skarels */ 21332100Skarels { 21432100Skarels u_int win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; 21532100Skarels if (win < 2) 21632100Skarels win = 2; 21731442Skarels tp->snd_cwnd = tp->t_maxseg; 21832100Skarels tp->snd_ssthresh = win * tp->t_maxseg; 21932100Skarels } 2205165Swnj (void) tcp_output(tp); 22110396Ssam break; 2225069Swnj 2235165Swnj /* 2245165Swnj * Persistance timer into zero window. 2255165Swnj * Force a byte to be output, if possible. 2265165Swnj */ 2275075Swnj case TCPT_PERSIST: 22830524Skarels tcpstat.tcps_persisttimeo++; 2297156Swnj tcp_setpersist(tp); 2305165Swnj tp->t_force = 1; 2315165Swnj (void) tcp_output(tp); 2325165Swnj tp->t_force = 0; 23310396Ssam break; 2345069Swnj 2355165Swnj /* 2365165Swnj * Keep-alive timer went off; send something 2375165Swnj * or drop connection if idle for too long. 2385165Swnj */ 2395075Swnj case TCPT_KEEP: 24030524Skarels tcpstat.tcps_keeptimeo++; 2416304Sroot if (tp->t_state < TCPS_ESTABLISHED) 2426304Sroot goto dropit; 24327193Skarels if (tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE && 24427193Skarels tp->t_state <= TCPS_CLOSE_WAIT) { 245*33746Skarels if (tp->t_idle >= tcp_keepidle + tcp_maxidle) 2466304Sroot goto dropit; 2476267Sroot /* 24830524Skarels * Send a packet designed to force a response 24930524Skarels * if the peer is up and reachable: 25030524Skarels * either an ACK if the connection is still alive, 25130524Skarels * or an RST if the peer has closed the connection 25230524Skarels * due to timeout or reboot. 25330524Skarels * Using sequence number tp->snd_una-1 25430524Skarels * causes the transmitted zero-length segment 25530524Skarels * to lie outside the receive window; 25630524Skarels * by the protocol spec, this requires the 25730524Skarels * correspondent TCP to respond. 2586267Sroot */ 25930524Skarels tcpstat.tcps_keepprobe++; 26031727Skarels #ifdef TCP_COMPAT_42 26131727Skarels /* 26231727Skarels * The keepalive packet must have nonzero length 26331727Skarels * to get a 4.2 host to respond. 26431727Skarels */ 26530762Skarels tcp_respond(tp, tp->t_template, 26631727Skarels tp->rcv_nxt - 1, tp->snd_una - 1, 0); 26731727Skarels #else 26831727Skarels tcp_respond(tp, tp->t_template, 26931727Skarels tp->rcv_nxt, tp->snd_una - 1, 0); 27031727Skarels #endif 271*33746Skarels tp->t_timer[TCPT_KEEP] = tcp_keepintvl; 272*33746Skarels } else 273*33746Skarels tp->t_timer[TCPT_KEEP] = tcp_keepidle; 27410396Ssam break; 2756304Sroot dropit: 27630524Skarels tcpstat.tcps_keepdrops++; 27710396Ssam tp = tcp_drop(tp, ETIMEDOUT); 27810396Ssam break; 2795069Swnj } 28010396Ssam return (tp); 2815069Swnj } 282