123194Smckusick /* 2*37321Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 332789Sbostic * All rights reserved. 423194Smckusick * 532789Sbostic * Redistribution and use in source and binary forms are permitted 634855Sbostic * provided that the above copyright notice and this paragraph are 734855Sbostic * duplicated in all such forms and that any documentation, 834855Sbostic * advertising materials, and other materials related to such 934855Sbostic * distribution and use acknowledge that the software was developed 1034855Sbostic * by the University of California, Berkeley. The name of the 1134855Sbostic * University may not be used to endorse or promote products derived 1234855Sbostic * from this software without specific prior written permission. 1334855Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434855Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534855Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1632789Sbostic * 17*37321Skarels * @(#)tcp_timer.c 7.15 (Berkeley) 04/08/89 1823194Smckusick */ 195069Swnj 2017064Sbloom #include "param.h" 2117064Sbloom #include "systm.h" 22*37321Skarels #include "malloc.h" 2317064Sbloom #include "mbuf.h" 2417064Sbloom #include "socket.h" 2517064Sbloom #include "socketvar.h" 2617064Sbloom #include "protosw.h" 2717064Sbloom #include "errno.h" 288697Sroot 298697Sroot #include "../net/if.h" 308697Sroot #include "../net/route.h" 3110896Ssam 3217064Sbloom #include "in.h" 3317064Sbloom #include "in_pcb.h" 3417064Sbloom #include "in_systm.h" 3517064Sbloom #include "ip.h" 3617064Sbloom #include "ip_var.h" 3717064Sbloom #include "tcp.h" 3817064Sbloom #include "tcp_fsm.h" 3917064Sbloom #include "tcp_seq.h" 4017064Sbloom #include "tcp_timer.h" 4117064Sbloom #include "tcp_var.h" 4217064Sbloom #include "tcpip.h" 435069Swnj 4433746Skarels int tcp_keepidle = TCPTV_KEEP_IDLE; 4533746Skarels int tcp_keepintvl = TCPTV_KEEPINTVL; 4633746Skarels int tcp_maxidle; 475069Swnj /* 485069Swnj * Fast timeout routine for processing delayed acks 495069Swnj */ 505069Swnj tcp_fasttimo() 515069Swnj { 525284Sroot register struct inpcb *inp; 535284Sroot register struct tcpcb *tp; 545284Sroot int s = splnet(); 555069Swnj 565691Swnj inp = tcb.inp_next; 575691Swnj if (inp) 585691Swnj for (; inp != &tcb; inp = inp->inp_next) 595284Sroot if ((tp = (struct tcpcb *)inp->inp_ppcb) && 605284Sroot (tp->t_flags & TF_DELACK)) { 615284Sroot tp->t_flags &= ~TF_DELACK; 625284Sroot tp->t_flags |= TF_ACKNOW; 6330524Skarels tcpstat.tcps_delack++; 645284Sroot (void) tcp_output(tp); 655284Sroot } 665284Sroot splx(s); 675069Swnj } 685069Swnj 695069Swnj /* 705069Swnj * Tcp protocol timeout routine called every 500 ms. 715069Swnj * Updates the timers in all active tcb's and 725069Swnj * causes finite state machine actions if timers expire. 735069Swnj */ 745069Swnj tcp_slowtimo() 755069Swnj { 766212Swnj register struct inpcb *ip, *ipnxt; 775069Swnj register struct tcpcb *tp; 785069Swnj int s = splnet(); 795069Swnj register int i; 805069Swnj 8133746Skarels tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; 825069Swnj /* 835069Swnj * Search through tcb's and update active timers. 845069Swnj */ 855245Sroot ip = tcb.inp_next; 865245Sroot if (ip == 0) { 875245Sroot splx(s); 885245Sroot return; 895245Sroot } 9017315Skarels for (; ip != &tcb; ip = ipnxt) { 9117315Skarels ipnxt = ip->inp_next; 925069Swnj tp = intotcpcb(ip); 935260Swnj if (tp == 0) 945260Swnj continue; 955075Swnj for (i = 0; i < TCPT_NTIMERS; i++) { 966212Swnj if (tp->t_timer[i] && --tp->t_timer[i] == 0) { 975069Swnj (void) tcp_usrreq(tp->t_inpcb->inp_socket, 985069Swnj PRU_SLOWTIMO, (struct mbuf *)0, 9912764Ssam (struct mbuf *)i, (struct mbuf *)0); 1006212Swnj if (ipnxt->inp_prev != ip) 1016212Swnj goto tpgone; 1026212Swnj } 1035069Swnj } 1045165Swnj tp->t_idle++; 1055165Swnj if (tp->t_rtt) 1065165Swnj tp->t_rtt++; 1076212Swnj tpgone: 10817315Skarels ; 1095069Swnj } 1105075Swnj tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ 11127059Skarels #ifdef TCP_COMPAT_42 11226118Skarels if ((int)tcp_iss < 0) 11326118Skarels tcp_iss = 0; /* XXX */ 11426118Skarels #endif 1155069Swnj splx(s); 1165069Swnj } 1175069Swnj 1185069Swnj /* 1195075Swnj * Cancel all timers for TCP tp. 1205069Swnj */ 1215089Swnj tcp_canceltimers(tp) 1225069Swnj struct tcpcb *tp; 1235069Swnj { 1245069Swnj register int i; 1255069Swnj 1265075Swnj for (i = 0; i < TCPT_NTIMERS; i++) 1275075Swnj tp->t_timer[i] = 0; 1285069Swnj } 1295069Swnj 13032034Skarels int tcp_backoff[TCP_MAXRXTSHIFT + 1] = 13132034Skarels { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 13230762Skarels 1335069Swnj /* 1345165Swnj * TCP timer processing. 1355069Swnj */ 13610396Ssam struct tcpcb * 1375075Swnj tcp_timers(tp, timer) 1385069Swnj register struct tcpcb *tp; 1395075Swnj int timer; 1405069Swnj { 14125888Skarels register int rexmt; 1425069Swnj 1435089Swnj switch (timer) { 1445069Swnj 1455165Swnj /* 14624819Skarels * 2 MSL timeout in shutdown went off. If we're closed but 14724819Skarels * still waiting for peer to close and connection has been idle 14824819Skarels * too long, or if 2MSL time is up from TIME_WAIT, delete connection 14924819Skarels * control block. Otherwise, check again in a bit. 1505165Swnj */ 1515075Swnj case TCPT_2MSL: 15224819Skarels if (tp->t_state != TCPS_TIME_WAIT && 15333746Skarels tp->t_idle <= tcp_maxidle) 15433746Skarels tp->t_timer[TCPT_2MSL] = tcp_keepintvl; 15524819Skarels else 15624819Skarels tp = tcp_close(tp); 15710396Ssam break; 1585069Swnj 1595165Swnj /* 1605165Swnj * Retransmission timer went off. Message has not 1615165Swnj * been acked within retransmit interval. Back off 16217362Skarels * to a longer retransmit interval and retransmit one segment. 1635165Swnj */ 1645075Swnj case TCPT_REXMT: 16532034Skarels if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { 16632034Skarels tp->t_rxtshift = TCP_MAXRXTSHIFT; 16730524Skarels tcpstat.tcps_timeoutdrop++; 16810396Ssam tp = tcp_drop(tp, ETIMEDOUT); 16910396Ssam break; 1705691Swnj } 17130524Skarels tcpstat.tcps_rexmttimeo++; 17231726Skarels rexmt = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; 17331726Skarels rexmt *= tcp_backoff[tp->t_rxtshift]; 17432034Skarels TCPT_RANGESET(tp->t_rxtcur, rexmt, TCPTV_MIN, TCPTV_REXMTMAX); 17532034Skarels tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; 17626989Skarels /* 17732034Skarels * If losing, let the lower level know and try for 17832034Skarels * a better route. Also, if we backed off this far, 17932034Skarels * our srtt estimate is probably bogus. Clobber it 18032034Skarels * so we'll take the next rtt measurement as our srtt; 18132034Skarels * move the current srtt into rttvar to keep the current 18232034Skarels * retransmit times until then. 18326989Skarels */ 18432034Skarels if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { 18526989Skarels in_losing(tp->t_inpcb); 18632034Skarels tp->t_rttvar += (tp->t_srtt >> 2); 18732034Skarels tp->t_srtt = 0; 18832034Skarels } 1895165Swnj tp->snd_nxt = tp->snd_una; 19017314Skarels /* 19131726Skarels * If timing a segment in this window, stop the timer. 19217314Skarels */ 19331726Skarels tp->t_rtt = 0; 19431442Skarels /* 19531442Skarels * Close the congestion window down to one segment 19631442Skarels * (we'll open it by one segment for each ack we get). 19731442Skarels * Since we probably have a window's worth of unacked 19831442Skarels * data accumulated, this "slow start" keeps us from 19931442Skarels * dumping all that data as back-to-back packets (which 20031442Skarels * might overwhelm an intermediate gateway). 20132100Skarels * 20232100Skarels * There are two phases to the opening: Initially we 20332100Skarels * open by one mss on each ack. This makes the window 20432100Skarels * size increase exponentially with time. If the 20532100Skarels * window is larger than the path can handle, this 20632100Skarels * exponential growth results in dropped packet(s) 20732100Skarels * almost immediately. To get more time between 20832100Skarels * drops but still "push" the network to take advantage 20932100Skarels * of improving conditions, we switch from exponential 21032100Skarels * to linear window opening at some threshhold size. 21132100Skarels * For a threshhold, we use half the current window 21232100Skarels * size, truncated to a multiple of the mss. 21332100Skarels * 21432100Skarels * (the minimum cwnd that will give us exponential 21532100Skarels * growth is 2 mss. We don't allow the threshhold 21632100Skarels * to go below this.) 21731442Skarels */ 21832100Skarels { 21932100Skarels u_int win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; 22032100Skarels if (win < 2) 22132100Skarels win = 2; 22231442Skarels tp->snd_cwnd = tp->t_maxseg; 22332100Skarels tp->snd_ssthresh = win * tp->t_maxseg; 22432100Skarels } 2255165Swnj (void) tcp_output(tp); 22610396Ssam break; 2275069Swnj 2285165Swnj /* 2295165Swnj * Persistance timer into zero window. 2305165Swnj * Force a byte to be output, if possible. 2315165Swnj */ 2325075Swnj case TCPT_PERSIST: 23330524Skarels tcpstat.tcps_persisttimeo++; 2347156Swnj tcp_setpersist(tp); 2355165Swnj tp->t_force = 1; 2365165Swnj (void) tcp_output(tp); 2375165Swnj tp->t_force = 0; 23810396Ssam break; 2395069Swnj 2405165Swnj /* 2415165Swnj * Keep-alive timer went off; send something 2425165Swnj * or drop connection if idle for too long. 2435165Swnj */ 2445075Swnj case TCPT_KEEP: 24530524Skarels tcpstat.tcps_keeptimeo++; 2466304Sroot if (tp->t_state < TCPS_ESTABLISHED) 2476304Sroot goto dropit; 24827193Skarels if (tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE && 24927193Skarels tp->t_state <= TCPS_CLOSE_WAIT) { 25033746Skarels if (tp->t_idle >= tcp_keepidle + tcp_maxidle) 2516304Sroot goto dropit; 2526267Sroot /* 25330524Skarels * Send a packet designed to force a response 25430524Skarels * if the peer is up and reachable: 25530524Skarels * either an ACK if the connection is still alive, 25630524Skarels * or an RST if the peer has closed the connection 25730524Skarels * due to timeout or reboot. 25830524Skarels * Using sequence number tp->snd_una-1 25930524Skarels * causes the transmitted zero-length segment 26030524Skarels * to lie outside the receive window; 26130524Skarels * by the protocol spec, this requires the 26230524Skarels * correspondent TCP to respond. 2636267Sroot */ 26430524Skarels tcpstat.tcps_keepprobe++; 26531727Skarels #ifdef TCP_COMPAT_42 26631727Skarels /* 26731727Skarels * The keepalive packet must have nonzero length 26831727Skarels * to get a 4.2 host to respond. 26931727Skarels */ 270*37321Skarels tcp_respond(tp, tp->t_template, (struct mbuf *)NULL, 27131727Skarels tp->rcv_nxt - 1, tp->snd_una - 1, 0); 27231727Skarels #else 273*37321Skarels tcp_respond(tp, tp->t_template, (struct mbuf *)NULL, 27431727Skarels tp->rcv_nxt, tp->snd_una - 1, 0); 27531727Skarels #endif 27633746Skarels tp->t_timer[TCPT_KEEP] = tcp_keepintvl; 27733746Skarels } else 27833746Skarels tp->t_timer[TCPT_KEEP] = tcp_keepidle; 27910396Ssam break; 2806304Sroot dropit: 28130524Skarels tcpstat.tcps_keepdrops++; 28210396Ssam tp = tcp_drop(tp, ETIMEDOUT); 28310396Ssam break; 2845069Swnj } 28510396Ssam return (tp); 2865069Swnj } 287