123194Smckusick /* 2*63218Sbostic * Copyright (c) 1982, 1986, 1988, 1990, 1993 3*63218Sbostic * The Regents of the University of California. All rights reserved. 423194Smckusick * 544489Sbostic * %sccs.include.redist.c% 632789Sbostic * 7*63218Sbostic * @(#)tcp_timer.c 8.1 (Berkeley) 06/10/93 823194Smckusick */ 95069Swnj 1057947Ssklower #ifndef TUBA_INCLUDE 1156531Sbostic #include <sys/param.h> 1256531Sbostic #include <sys/systm.h> 1356531Sbostic #include <sys/malloc.h> 1456531Sbostic #include <sys/mbuf.h> 1556531Sbostic #include <sys/socket.h> 1656531Sbostic #include <sys/socketvar.h> 1756531Sbostic #include <sys/protosw.h> 1856531Sbostic #include <sys/errno.h> 198697Sroot 2056531Sbostic #include <net/if.h> 2156531Sbostic #include <net/route.h> 2210896Ssam 2356531Sbostic #include <netinet/in.h> 2456531Sbostic #include <netinet/in_systm.h> 2556531Sbostic #include <netinet/ip.h> 2656531Sbostic #include <netinet/in_pcb.h> 2756531Sbostic #include <netinet/ip_var.h> 2856531Sbostic #include <netinet/tcp.h> 2956531Sbostic #include <netinet/tcp_fsm.h> 3056531Sbostic #include <netinet/tcp_seq.h> 3156531Sbostic #include <netinet/tcp_timer.h> 3256531Sbostic #include <netinet/tcp_var.h> 3356531Sbostic #include <netinet/tcpip.h> 345069Swnj 3533746Skarels int tcp_keepidle = TCPTV_KEEP_IDLE; 3633746Skarels int tcp_keepintvl = TCPTV_KEEPINTVL; 3733746Skarels int tcp_maxidle; 3857947Ssklower #endif /* TUBA_INCLUDE */ 395069Swnj /* 405069Swnj * Fast timeout routine for processing delayed acks 415069Swnj */ 4261335Sbostic void 435069Swnj tcp_fasttimo() 445069Swnj { 455284Sroot register struct inpcb *inp; 465284Sroot register struct tcpcb *tp; 475284Sroot int s = splnet(); 485069Swnj 495691Swnj inp = tcb.inp_next; 505691Swnj if (inp) 515691Swnj for (; inp != &tcb; inp = inp->inp_next) 525284Sroot if ((tp = (struct tcpcb *)inp->inp_ppcb) && 535284Sroot (tp->t_flags & TF_DELACK)) { 545284Sroot tp->t_flags &= ~TF_DELACK; 555284Sroot tp->t_flags |= TF_ACKNOW; 5630524Skarels tcpstat.tcps_delack++; 575284Sroot (void) tcp_output(tp); 585284Sroot } 595284Sroot splx(s); 605069Swnj } 615069Swnj 625069Swnj /* 635069Swnj * Tcp protocol timeout routine called every 500 ms. 645069Swnj * Updates the timers in all active tcb's and 655069Swnj * causes finite state machine actions if timers expire. 665069Swnj */ 6761335Sbostic void 685069Swnj tcp_slowtimo() 695069Swnj { 706212Swnj register struct inpcb *ip, *ipnxt; 715069Swnj register struct tcpcb *tp; 725069Swnj int s = splnet(); 735069Swnj register int i; 745069Swnj 7533746Skarels tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; 765069Swnj /* 775069Swnj * Search through tcb's and update active timers. 785069Swnj */ 795245Sroot ip = tcb.inp_next; 805245Sroot if (ip == 0) { 815245Sroot splx(s); 825245Sroot return; 835245Sroot } 8417315Skarels for (; ip != &tcb; ip = ipnxt) { 8517315Skarels ipnxt = ip->inp_next; 865069Swnj tp = intotcpcb(ip); 875260Swnj if (tp == 0) 885260Swnj continue; 895075Swnj for (i = 0; i < TCPT_NTIMERS; i++) { 906212Swnj if (tp->t_timer[i] && --tp->t_timer[i] == 0) { 915069Swnj (void) tcp_usrreq(tp->t_inpcb->inp_socket, 925069Swnj PRU_SLOWTIMO, (struct mbuf *)0, 9312764Ssam (struct mbuf *)i, (struct mbuf *)0); 946212Swnj if (ipnxt->inp_prev != ip) 956212Swnj goto tpgone; 966212Swnj } 975069Swnj } 985165Swnj tp->t_idle++; 995165Swnj if (tp->t_rtt) 1005165Swnj tp->t_rtt++; 1016212Swnj tpgone: 10217315Skarels ; 1035069Swnj } 1045075Swnj tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ 10527059Skarels #ifdef TCP_COMPAT_42 10626118Skarels if ((int)tcp_iss < 0) 10726118Skarels tcp_iss = 0; /* XXX */ 10826118Skarels #endif 10957433Sandrew tcp_now++; /* for timestamps */ 1105069Swnj splx(s); 1115069Swnj } 11257947Ssklower #ifndef TUBA_INCLUDE 1135069Swnj 1145069Swnj /* 1155075Swnj * Cancel all timers for TCP tp. 1165069Swnj */ 11761335Sbostic void 1185089Swnj tcp_canceltimers(tp) 1195069Swnj struct tcpcb *tp; 1205069Swnj { 1215069Swnj register int i; 1225069Swnj 1235075Swnj for (i = 0; i < TCPT_NTIMERS; i++) 1245075Swnj tp->t_timer[i] = 0; 1255069Swnj } 1265069Swnj 12732034Skarels int tcp_backoff[TCP_MAXRXTSHIFT + 1] = 12832034Skarels { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 12930762Skarels 1305069Swnj /* 1315165Swnj * TCP timer processing. 1325069Swnj */ 13310396Ssam struct tcpcb * 1345075Swnj tcp_timers(tp, timer) 1355069Swnj register struct tcpcb *tp; 1365075Swnj int timer; 1375069Swnj { 13825888Skarels register int rexmt; 1395069Swnj 1405089Swnj switch (timer) { 1415069Swnj 1425165Swnj /* 14324819Skarels * 2 MSL timeout in shutdown went off. If we're closed but 14424819Skarels * still waiting for peer to close and connection has been idle 14524819Skarels * too long, or if 2MSL time is up from TIME_WAIT, delete connection 14624819Skarels * control block. Otherwise, check again in a bit. 1475165Swnj */ 1485075Swnj case TCPT_2MSL: 14924819Skarels if (tp->t_state != TCPS_TIME_WAIT && 15033746Skarels tp->t_idle <= tcp_maxidle) 15133746Skarels tp->t_timer[TCPT_2MSL] = tcp_keepintvl; 15224819Skarels else 15324819Skarels tp = tcp_close(tp); 15410396Ssam break; 1555069Swnj 1565165Swnj /* 1575165Swnj * Retransmission timer went off. Message has not 1585165Swnj * been acked within retransmit interval. Back off 15917362Skarels * to a longer retransmit interval and retransmit one segment. 1605165Swnj */ 1615075Swnj case TCPT_REXMT: 16232034Skarels if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { 16332034Skarels tp->t_rxtshift = TCP_MAXRXTSHIFT; 16430524Skarels tcpstat.tcps_timeoutdrop++; 16544379Skarels tp = tcp_drop(tp, tp->t_softerror ? 16644379Skarels tp->t_softerror : ETIMEDOUT); 16710396Ssam break; 1685691Swnj } 16930524Skarels tcpstat.tcps_rexmttimeo++; 17044379Skarels rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; 17144379Skarels TCPT_RANGESET(tp->t_rxtcur, rexmt, 17244379Skarels tp->t_rttmin, TCPTV_REXMTMAX); 17332034Skarels tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; 17426989Skarels /* 17532034Skarels * If losing, let the lower level know and try for 17632034Skarels * a better route. Also, if we backed off this far, 17732034Skarels * our srtt estimate is probably bogus. Clobber it 17832034Skarels * so we'll take the next rtt measurement as our srtt; 17932034Skarels * move the current srtt into rttvar to keep the current 18032034Skarels * retransmit times until then. 18126989Skarels */ 18232034Skarels if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { 18326989Skarels in_losing(tp->t_inpcb); 18444379Skarels tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); 18532034Skarels tp->t_srtt = 0; 18632034Skarels } 1875165Swnj tp->snd_nxt = tp->snd_una; 18817314Skarels /* 18931726Skarels * If timing a segment in this window, stop the timer. 19017314Skarels */ 19131726Skarels tp->t_rtt = 0; 19231442Skarels /* 19331442Skarels * Close the congestion window down to one segment 19431442Skarels * (we'll open it by one segment for each ack we get). 19531442Skarels * Since we probably have a window's worth of unacked 19631442Skarels * data accumulated, this "slow start" keeps us from 19731442Skarels * dumping all that data as back-to-back packets (which 19831442Skarels * might overwhelm an intermediate gateway). 19932100Skarels * 20032100Skarels * There are two phases to the opening: Initially we 20132100Skarels * open by one mss on each ack. This makes the window 20232100Skarels * size increase exponentially with time. If the 20332100Skarels * window is larger than the path can handle, this 20432100Skarels * exponential growth results in dropped packet(s) 20532100Skarels * almost immediately. To get more time between 20632100Skarels * drops but still "push" the network to take advantage 20732100Skarels * of improving conditions, we switch from exponential 20832100Skarels * to linear window opening at some threshhold size. 20932100Skarels * For a threshhold, we use half the current window 21032100Skarels * size, truncated to a multiple of the mss. 21132100Skarels * 21232100Skarels * (the minimum cwnd that will give us exponential 21332100Skarels * growth is 2 mss. We don't allow the threshhold 21432100Skarels * to go below this.) 21531442Skarels */ 21632100Skarels { 21744379Skarels u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; 21832100Skarels if (win < 2) 21932100Skarels win = 2; 22031442Skarels tp->snd_cwnd = tp->t_maxseg; 22132100Skarels tp->snd_ssthresh = win * tp->t_maxseg; 22244379Skarels tp->t_dupacks = 0; 22332100Skarels } 2245165Swnj (void) tcp_output(tp); 22510396Ssam break; 2265069Swnj 2275165Swnj /* 2285165Swnj * Persistance timer into zero window. 2295165Swnj * Force a byte to be output, if possible. 2305165Swnj */ 2315075Swnj case TCPT_PERSIST: 23230524Skarels tcpstat.tcps_persisttimeo++; 2337156Swnj tcp_setpersist(tp); 2345165Swnj tp->t_force = 1; 2355165Swnj (void) tcp_output(tp); 2365165Swnj tp->t_force = 0; 23710396Ssam break; 2385069Swnj 2395165Swnj /* 2405165Swnj * Keep-alive timer went off; send something 2415165Swnj * or drop connection if idle for too long. 2425165Swnj */ 2435075Swnj case TCPT_KEEP: 24430524Skarels tcpstat.tcps_keeptimeo++; 2456304Sroot if (tp->t_state < TCPS_ESTABLISHED) 2466304Sroot goto dropit; 24727193Skarels if (tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE && 24827193Skarels tp->t_state <= TCPS_CLOSE_WAIT) { 24933746Skarels if (tp->t_idle >= tcp_keepidle + tcp_maxidle) 2506304Sroot goto dropit; 2516267Sroot /* 25230524Skarels * Send a packet designed to force a response 25330524Skarels * if the peer is up and reachable: 25430524Skarels * either an ACK if the connection is still alive, 25530524Skarels * or an RST if the peer has closed the connection 25630524Skarels * due to timeout or reboot. 25730524Skarels * Using sequence number tp->snd_una-1 25830524Skarels * causes the transmitted zero-length segment 25930524Skarels * to lie outside the receive window; 26030524Skarels * by the protocol spec, this requires the 26130524Skarels * correspondent TCP to respond. 2626267Sroot */ 26330524Skarels tcpstat.tcps_keepprobe++; 26431727Skarels #ifdef TCP_COMPAT_42 26531727Skarels /* 26631727Skarels * The keepalive packet must have nonzero length 26731727Skarels * to get a 4.2 host to respond. 26831727Skarels */ 26937321Skarels tcp_respond(tp, tp->t_template, (struct mbuf *)NULL, 27031727Skarels tp->rcv_nxt - 1, tp->snd_una - 1, 0); 27131727Skarels #else 27237321Skarels tcp_respond(tp, tp->t_template, (struct mbuf *)NULL, 27331727Skarels tp->rcv_nxt, tp->snd_una - 1, 0); 27431727Skarels #endif 27533746Skarels tp->t_timer[TCPT_KEEP] = tcp_keepintvl; 27633746Skarels } else 27733746Skarels tp->t_timer[TCPT_KEEP] = tcp_keepidle; 27810396Ssam break; 2796304Sroot dropit: 28030524Skarels tcpstat.tcps_keepdrops++; 28110396Ssam tp = tcp_drop(tp, ETIMEDOUT); 28210396Ssam break; 2835069Swnj } 28410396Ssam return (tp); 2855069Swnj } 28657947Ssklower #endif /* TUBA_INCLUDE */ 287