123194Smckusick /* 229153Smckusick * Copyright (c) 1982, 1986 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*32100Skarels * @(#)tcp_timer.c 7.10 (Berkeley) 09/04/87 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; 4930524Skarels tcpstat.tcps_delack++; 505284Sroot (void) tcp_output(tp); 515284Sroot } 525284Sroot splx(s); 535069Swnj } 545069Swnj 555069Swnj /* 565069Swnj * Tcp protocol timeout routine called every 500 ms. 575069Swnj * Updates the timers in all active tcb's and 585069Swnj * causes finite state machine actions if timers expire. 595069Swnj */ 605069Swnj tcp_slowtimo() 615069Swnj { 626212Swnj register struct inpcb *ip, *ipnxt; 635069Swnj register struct tcpcb *tp; 645069Swnj int s = splnet(); 655069Swnj register int i; 665069Swnj 675069Swnj /* 685069Swnj * Search through tcb's and update active timers. 695069Swnj */ 705245Sroot ip = tcb.inp_next; 715245Sroot if (ip == 0) { 725245Sroot splx(s); 735245Sroot return; 745245Sroot } 7517315Skarels for (; ip != &tcb; ip = ipnxt) { 7617315Skarels ipnxt = ip->inp_next; 775069Swnj tp = intotcpcb(ip); 785260Swnj if (tp == 0) 795260Swnj continue; 805075Swnj for (i = 0; i < TCPT_NTIMERS; i++) { 816212Swnj if (tp->t_timer[i] && --tp->t_timer[i] == 0) { 825069Swnj (void) tcp_usrreq(tp->t_inpcb->inp_socket, 835069Swnj PRU_SLOWTIMO, (struct mbuf *)0, 8412764Ssam (struct mbuf *)i, (struct mbuf *)0); 856212Swnj if (ipnxt->inp_prev != ip) 866212Swnj goto tpgone; 876212Swnj } 885069Swnj } 895165Swnj tp->t_idle++; 905165Swnj if (tp->t_rtt) 915165Swnj tp->t_rtt++; 926212Swnj tpgone: 9317315Skarels ; 945069Swnj } 955075Swnj tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ 9627059Skarels #ifdef TCP_COMPAT_42 9726118Skarels if ((int)tcp_iss < 0) 9826118Skarels tcp_iss = 0; /* XXX */ 9926118Skarels #endif 1005069Swnj splx(s); 1015069Swnj } 1025069Swnj 1035069Swnj /* 1045075Swnj * Cancel all timers for TCP tp. 1055069Swnj */ 1065089Swnj tcp_canceltimers(tp) 1075069Swnj struct tcpcb *tp; 1085069Swnj { 1095069Swnj register int i; 1105069Swnj 1115075Swnj for (i = 0; i < TCPT_NTIMERS; i++) 1125075Swnj tp->t_timer[i] = 0; 1135069Swnj } 1145069Swnj 11532034Skarels int tcp_backoff[TCP_MAXRXTSHIFT + 1] = 11632034Skarels { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 11730762Skarels 1185069Swnj /* 1195165Swnj * TCP timer processing. 1205069Swnj */ 12110396Ssam struct tcpcb * 1225075Swnj tcp_timers(tp, timer) 1235069Swnj register struct tcpcb *tp; 1245075Swnj int timer; 1255069Swnj { 12625888Skarels register int rexmt; 1275069Swnj 1285089Swnj switch (timer) { 1295069Swnj 1305165Swnj /* 13124819Skarels * 2 MSL timeout in shutdown went off. If we're closed but 13224819Skarels * still waiting for peer to close and connection has been idle 13324819Skarels * too long, or if 2MSL time is up from TIME_WAIT, delete connection 13424819Skarels * control block. Otherwise, check again in a bit. 1355165Swnj */ 1365075Swnj case TCPT_2MSL: 13724819Skarels if (tp->t_state != TCPS_TIME_WAIT && 13824819Skarels tp->t_idle <= TCPTV_MAXIDLE) 13924819Skarels tp->t_timer[TCPT_2MSL] = TCPTV_KEEP; 14024819Skarels else 14124819Skarels tp = tcp_close(tp); 14210396Ssam break; 1435069Swnj 1445165Swnj /* 1455165Swnj * Retransmission timer went off. Message has not 1465165Swnj * been acked within retransmit interval. Back off 14717362Skarels * to a longer retransmit interval and retransmit one segment. 1485165Swnj */ 1495075Swnj case TCPT_REXMT: 15032034Skarels if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { 15132034Skarels tp->t_rxtshift = TCP_MAXRXTSHIFT; 15230524Skarels tcpstat.tcps_timeoutdrop++; 15310396Ssam tp = tcp_drop(tp, ETIMEDOUT); 15410396Ssam break; 1555691Swnj } 15630524Skarels tcpstat.tcps_rexmttimeo++; 15731726Skarels rexmt = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; 15831726Skarels rexmt *= tcp_backoff[tp->t_rxtshift]; 15932034Skarels TCPT_RANGESET(tp->t_rxtcur, rexmt, TCPTV_MIN, TCPTV_REXMTMAX); 16032034Skarels tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; 16126989Skarels /* 16232034Skarels * If losing, let the lower level know and try for 16332034Skarels * a better route. Also, if we backed off this far, 16432034Skarels * our srtt estimate is probably bogus. Clobber it 16532034Skarels * so we'll take the next rtt measurement as our srtt; 16632034Skarels * move the current srtt into rttvar to keep the current 16732034Skarels * retransmit times until then. 16826989Skarels */ 16932034Skarels if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { 17026989Skarels in_losing(tp->t_inpcb); 17132034Skarels tp->t_rttvar += (tp->t_srtt >> 2); 17232034Skarels tp->t_srtt = 0; 17332034Skarels } 1745165Swnj tp->snd_nxt = tp->snd_una; 17517314Skarels /* 17631726Skarels * If timing a segment in this window, stop the timer. 17717314Skarels */ 17831726Skarels tp->t_rtt = 0; 17931442Skarels /* 18031442Skarels * Close the congestion window down to one segment 18131442Skarels * (we'll open it by one segment for each ack we get). 18231442Skarels * Since we probably have a window's worth of unacked 18331442Skarels * data accumulated, this "slow start" keeps us from 18431442Skarels * dumping all that data as back-to-back packets (which 18531442Skarels * might overwhelm an intermediate gateway). 186*32100Skarels * 187*32100Skarels * There are two phases to the opening: Initially we 188*32100Skarels * open by one mss on each ack. This makes the window 189*32100Skarels * size increase exponentially with time. If the 190*32100Skarels * window is larger than the path can handle, this 191*32100Skarels * exponential growth results in dropped packet(s) 192*32100Skarels * almost immediately. To get more time between 193*32100Skarels * drops but still "push" the network to take advantage 194*32100Skarels * of improving conditions, we switch from exponential 195*32100Skarels * to linear window opening at some threshhold size. 196*32100Skarels * For a threshhold, we use half the current window 197*32100Skarels * size, truncated to a multiple of the mss. 198*32100Skarels * 199*32100Skarels * (the minimum cwnd that will give us exponential 200*32100Skarels * growth is 2 mss. We don't allow the threshhold 201*32100Skarels * to go below this.) 20231442Skarels */ 203*32100Skarels { 204*32100Skarels u_int win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; 205*32100Skarels if (win < 2) 206*32100Skarels win = 2; 20731442Skarels tp->snd_cwnd = tp->t_maxseg; 208*32100Skarels tp->snd_ssthresh = win * tp->t_maxseg; 209*32100Skarels } 2105165Swnj (void) tcp_output(tp); 21110396Ssam break; 2125069Swnj 2135165Swnj /* 2145165Swnj * Persistance timer into zero window. 2155165Swnj * Force a byte to be output, if possible. 2165165Swnj */ 2175075Swnj case TCPT_PERSIST: 21830524Skarels tcpstat.tcps_persisttimeo++; 2197156Swnj tcp_setpersist(tp); 2205165Swnj tp->t_force = 1; 2215165Swnj (void) tcp_output(tp); 2225165Swnj tp->t_force = 0; 22310396Ssam break; 2245069Swnj 2255165Swnj /* 2265165Swnj * Keep-alive timer went off; send something 2275165Swnj * or drop connection if idle for too long. 2285165Swnj */ 2295075Swnj case TCPT_KEEP: 23030524Skarels tcpstat.tcps_keeptimeo++; 2316304Sroot if (tp->t_state < TCPS_ESTABLISHED) 2326304Sroot goto dropit; 23327193Skarels if (tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE && 23427193Skarels tp->t_state <= TCPS_CLOSE_WAIT) { 2356304Sroot if (tp->t_idle >= TCPTV_MAXIDLE) 2366304Sroot goto dropit; 2376267Sroot /* 23830524Skarels * Send a packet designed to force a response 23930524Skarels * if the peer is up and reachable: 24030524Skarels * either an ACK if the connection is still alive, 24130524Skarels * or an RST if the peer has closed the connection 24230524Skarels * due to timeout or reboot. 24330524Skarels * Using sequence number tp->snd_una-1 24430524Skarels * causes the transmitted zero-length segment 24530524Skarels * to lie outside the receive window; 24630524Skarels * by the protocol spec, this requires the 24730524Skarels * correspondent TCP to respond. 2486267Sroot */ 24930524Skarels tcpstat.tcps_keepprobe++; 25031727Skarels #ifdef TCP_COMPAT_42 25131727Skarels /* 25231727Skarels * The keepalive packet must have nonzero length 25331727Skarels * to get a 4.2 host to respond. 25431727Skarels */ 25530762Skarels tcp_respond(tp, tp->t_template, 25631727Skarels tp->rcv_nxt - 1, tp->snd_una - 1, 0); 25731727Skarels #else 25831727Skarels tcp_respond(tp, tp->t_template, 25931727Skarels tp->rcv_nxt, tp->snd_una - 1, 0); 26031727Skarels #endif 26127193Skarels } 2625165Swnj tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; 26310396Ssam break; 2646304Sroot dropit: 26530524Skarels tcpstat.tcps_keepdrops++; 26610396Ssam tp = tcp_drop(tp, ETIMEDOUT); 26710396Ssam break; 2685069Swnj } 26910396Ssam return (tp); 2705069Swnj } 271