123194Smckusick /* 244379Skarels * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. 332789Sbostic * All rights reserved. 423194Smckusick * 544489Sbostic * %sccs.include.redist.c% 632789Sbostic * 7*56531Sbostic * @(#)tcp_timer.c 7.19 (Berkeley) 10/11/92 823194Smckusick */ 95069Swnj 10*56531Sbostic #include <sys/param.h> 11*56531Sbostic #include <sys/systm.h> 12*56531Sbostic #include <sys/malloc.h> 13*56531Sbostic #include <sys/mbuf.h> 14*56531Sbostic #include <sys/socket.h> 15*56531Sbostic #include <sys/socketvar.h> 16*56531Sbostic #include <sys/protosw.h> 17*56531Sbostic #include <sys/errno.h> 188697Sroot 19*56531Sbostic #include <net/if.h> 20*56531Sbostic #include <net/route.h> 2110896Ssam 22*56531Sbostic #include <netinet/in.h> 23*56531Sbostic #include <netinet/in_systm.h> 24*56531Sbostic #include <netinet/ip.h> 25*56531Sbostic #include <netinet/in_pcb.h> 26*56531Sbostic #include <netinet/ip_var.h> 27*56531Sbostic #include <netinet/tcp.h> 28*56531Sbostic #include <netinet/tcp_fsm.h> 29*56531Sbostic #include <netinet/tcp_seq.h> 30*56531Sbostic #include <netinet/tcp_timer.h> 31*56531Sbostic #include <netinet/tcp_var.h> 32*56531Sbostic #include <netinet/tcpip.h> 335069Swnj 3433746Skarels int tcp_keepidle = TCPTV_KEEP_IDLE; 3533746Skarels int tcp_keepintvl = TCPTV_KEEPINTVL; 3633746Skarels int tcp_maxidle; 375069Swnj /* 385069Swnj * Fast timeout routine for processing delayed acks 395069Swnj */ 405069Swnj tcp_fasttimo() 415069Swnj { 425284Sroot register struct inpcb *inp; 435284Sroot register struct tcpcb *tp; 445284Sroot int s = splnet(); 455069Swnj 465691Swnj inp = tcb.inp_next; 475691Swnj if (inp) 485691Swnj for (; inp != &tcb; inp = inp->inp_next) 495284Sroot if ((tp = (struct tcpcb *)inp->inp_ppcb) && 505284Sroot (tp->t_flags & TF_DELACK)) { 515284Sroot tp->t_flags &= ~TF_DELACK; 525284Sroot tp->t_flags |= TF_ACKNOW; 5330524Skarels tcpstat.tcps_delack++; 545284Sroot (void) tcp_output(tp); 555284Sroot } 565284Sroot splx(s); 575069Swnj } 585069Swnj 595069Swnj /* 605069Swnj * Tcp protocol timeout routine called every 500 ms. 615069Swnj * Updates the timers in all active tcb's and 625069Swnj * causes finite state machine actions if timers expire. 635069Swnj */ 645069Swnj tcp_slowtimo() 655069Swnj { 666212Swnj register struct inpcb *ip, *ipnxt; 675069Swnj register struct tcpcb *tp; 685069Swnj int s = splnet(); 695069Swnj register int i; 705069Swnj 7133746Skarels tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; 725069Swnj /* 735069Swnj * Search through tcb's and update active timers. 745069Swnj */ 755245Sroot ip = tcb.inp_next; 765245Sroot if (ip == 0) { 775245Sroot splx(s); 785245Sroot return; 795245Sroot } 8017315Skarels for (; ip != &tcb; ip = ipnxt) { 8117315Skarels ipnxt = ip->inp_next; 825069Swnj tp = intotcpcb(ip); 835260Swnj if (tp == 0) 845260Swnj continue; 855075Swnj for (i = 0; i < TCPT_NTIMERS; i++) { 866212Swnj if (tp->t_timer[i] && --tp->t_timer[i] == 0) { 875069Swnj (void) tcp_usrreq(tp->t_inpcb->inp_socket, 885069Swnj PRU_SLOWTIMO, (struct mbuf *)0, 8912764Ssam (struct mbuf *)i, (struct mbuf *)0); 906212Swnj if (ipnxt->inp_prev != ip) 916212Swnj goto tpgone; 926212Swnj } 935069Swnj } 945165Swnj tp->t_idle++; 955165Swnj if (tp->t_rtt) 965165Swnj tp->t_rtt++; 976212Swnj tpgone: 9817315Skarels ; 995069Swnj } 1005075Swnj tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ 10127059Skarels #ifdef TCP_COMPAT_42 10226118Skarels if ((int)tcp_iss < 0) 10326118Skarels tcp_iss = 0; /* XXX */ 10426118Skarels #endif 1055069Swnj splx(s); 1065069Swnj } 1075069Swnj 1085069Swnj /* 1095075Swnj * Cancel all timers for TCP tp. 1105069Swnj */ 1115089Swnj tcp_canceltimers(tp) 1125069Swnj struct tcpcb *tp; 1135069Swnj { 1145069Swnj register int i; 1155069Swnj 1165075Swnj for (i = 0; i < TCPT_NTIMERS; i++) 1175075Swnj tp->t_timer[i] = 0; 1185069Swnj } 1195069Swnj 12032034Skarels int tcp_backoff[TCP_MAXRXTSHIFT + 1] = 12132034Skarels { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 12230762Skarels 1235069Swnj /* 1245165Swnj * TCP timer processing. 1255069Swnj */ 12610396Ssam struct tcpcb * 1275075Swnj tcp_timers(tp, timer) 1285069Swnj register struct tcpcb *tp; 1295075Swnj int timer; 1305069Swnj { 13125888Skarels register int rexmt; 1325069Swnj 1335089Swnj switch (timer) { 1345069Swnj 1355165Swnj /* 13624819Skarels * 2 MSL timeout in shutdown went off. If we're closed but 13724819Skarels * still waiting for peer to close and connection has been idle 13824819Skarels * too long, or if 2MSL time is up from TIME_WAIT, delete connection 13924819Skarels * control block. Otherwise, check again in a bit. 1405165Swnj */ 1415075Swnj case TCPT_2MSL: 14224819Skarels if (tp->t_state != TCPS_TIME_WAIT && 14333746Skarels tp->t_idle <= tcp_maxidle) 14433746Skarels tp->t_timer[TCPT_2MSL] = tcp_keepintvl; 14524819Skarels else 14624819Skarels tp = tcp_close(tp); 14710396Ssam break; 1485069Swnj 1495165Swnj /* 1505165Swnj * Retransmission timer went off. Message has not 1515165Swnj * been acked within retransmit interval. Back off 15217362Skarels * to a longer retransmit interval and retransmit one segment. 1535165Swnj */ 1545075Swnj case TCPT_REXMT: 15532034Skarels if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { 15632034Skarels tp->t_rxtshift = TCP_MAXRXTSHIFT; 15730524Skarels tcpstat.tcps_timeoutdrop++; 15844379Skarels tp = tcp_drop(tp, tp->t_softerror ? 15944379Skarels tp->t_softerror : ETIMEDOUT); 16010396Ssam break; 1615691Swnj } 16230524Skarels tcpstat.tcps_rexmttimeo++; 16344379Skarels rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; 16444379Skarels TCPT_RANGESET(tp->t_rxtcur, rexmt, 16544379Skarels tp->t_rttmin, TCPTV_REXMTMAX); 16632034Skarels tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; 16726989Skarels /* 16832034Skarels * If losing, let the lower level know and try for 16932034Skarels * a better route. Also, if we backed off this far, 17032034Skarels * our srtt estimate is probably bogus. Clobber it 17132034Skarels * so we'll take the next rtt measurement as our srtt; 17232034Skarels * move the current srtt into rttvar to keep the current 17332034Skarels * retransmit times until then. 17426989Skarels */ 17532034Skarels if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { 17626989Skarels in_losing(tp->t_inpcb); 17744379Skarels tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); 17832034Skarels tp->t_srtt = 0; 17932034Skarels } 1805165Swnj tp->snd_nxt = tp->snd_una; 18117314Skarels /* 18231726Skarels * If timing a segment in this window, stop the timer. 18317314Skarels */ 18431726Skarels tp->t_rtt = 0; 18531442Skarels /* 18631442Skarels * Close the congestion window down to one segment 18731442Skarels * (we'll open it by one segment for each ack we get). 18831442Skarels * Since we probably have a window's worth of unacked 18931442Skarels * data accumulated, this "slow start" keeps us from 19031442Skarels * dumping all that data as back-to-back packets (which 19131442Skarels * might overwhelm an intermediate gateway). 19232100Skarels * 19332100Skarels * There are two phases to the opening: Initially we 19432100Skarels * open by one mss on each ack. This makes the window 19532100Skarels * size increase exponentially with time. If the 19632100Skarels * window is larger than the path can handle, this 19732100Skarels * exponential growth results in dropped packet(s) 19832100Skarels * almost immediately. To get more time between 19932100Skarels * drops but still "push" the network to take advantage 20032100Skarels * of improving conditions, we switch from exponential 20132100Skarels * to linear window opening at some threshhold size. 20232100Skarels * For a threshhold, we use half the current window 20332100Skarels * size, truncated to a multiple of the mss. 20432100Skarels * 20532100Skarels * (the minimum cwnd that will give us exponential 20632100Skarels * growth is 2 mss. We don't allow the threshhold 20732100Skarels * to go below this.) 20831442Skarels */ 20932100Skarels { 21044379Skarels u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; 21132100Skarels if (win < 2) 21232100Skarels win = 2; 21331442Skarels tp->snd_cwnd = tp->t_maxseg; 21432100Skarels tp->snd_ssthresh = win * tp->t_maxseg; 21544379Skarels tp->t_dupacks = 0; 21632100Skarels } 2175165Swnj (void) tcp_output(tp); 21810396Ssam break; 2195069Swnj 2205165Swnj /* 2215165Swnj * Persistance timer into zero window. 2225165Swnj * Force a byte to be output, if possible. 2235165Swnj */ 2245075Swnj case TCPT_PERSIST: 22530524Skarels tcpstat.tcps_persisttimeo++; 2267156Swnj tcp_setpersist(tp); 2275165Swnj tp->t_force = 1; 2285165Swnj (void) tcp_output(tp); 2295165Swnj tp->t_force = 0; 23010396Ssam break; 2315069Swnj 2325165Swnj /* 2335165Swnj * Keep-alive timer went off; send something 2345165Swnj * or drop connection if idle for too long. 2355165Swnj */ 2365075Swnj case TCPT_KEEP: 23730524Skarels tcpstat.tcps_keeptimeo++; 2386304Sroot if (tp->t_state < TCPS_ESTABLISHED) 2396304Sroot goto dropit; 24027193Skarels if (tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE && 24127193Skarels tp->t_state <= TCPS_CLOSE_WAIT) { 24233746Skarels if (tp->t_idle >= tcp_keepidle + tcp_maxidle) 2436304Sroot goto dropit; 2446267Sroot /* 24530524Skarels * Send a packet designed to force a response 24630524Skarels * if the peer is up and reachable: 24730524Skarels * either an ACK if the connection is still alive, 24830524Skarels * or an RST if the peer has closed the connection 24930524Skarels * due to timeout or reboot. 25030524Skarels * Using sequence number tp->snd_una-1 25130524Skarels * causes the transmitted zero-length segment 25230524Skarels * to lie outside the receive window; 25330524Skarels * by the protocol spec, this requires the 25430524Skarels * correspondent TCP to respond. 2556267Sroot */ 25630524Skarels tcpstat.tcps_keepprobe++; 25731727Skarels #ifdef TCP_COMPAT_42 25831727Skarels /* 25931727Skarels * The keepalive packet must have nonzero length 26031727Skarels * to get a 4.2 host to respond. 26131727Skarels */ 26237321Skarels tcp_respond(tp, tp->t_template, (struct mbuf *)NULL, 26331727Skarels tp->rcv_nxt - 1, tp->snd_una - 1, 0); 26431727Skarels #else 26537321Skarels tcp_respond(tp, tp->t_template, (struct mbuf *)NULL, 26631727Skarels tp->rcv_nxt, tp->snd_una - 1, 0); 26731727Skarels #endif 26833746Skarels tp->t_timer[TCPT_KEEP] = tcp_keepintvl; 26933746Skarels } else 27033746Skarels tp->t_timer[TCPT_KEEP] = tcp_keepidle; 27110396Ssam break; 2726304Sroot dropit: 27330524Skarels tcpstat.tcps_keepdrops++; 27410396Ssam tp = tcp_drop(tp, ETIMEDOUT); 27510396Ssam break; 2765069Swnj } 27710396Ssam return (tp); 2785069Swnj } 279