1: /* 2: * Copyright (c) 1982, 1986 Regents of the University of California. 3: * All rights reserved. 4: * 5: * Redistribution and use in source and binary forms are permitted 6: * provided that this notice is preserved and that due credit is given 7: * to the University of California at Berkeley. The name of the University 8: * may not be used to endorse or promote products derived from this 9: * software without specific prior written permission. This software 10: * is provided ``as is'' without express or implied warranty. 11: * 12: * @(#)tcp_timer.c 7.11.1.2 (Berkeley) 3/16/88 13: */ 14: 15: #include "param.h" 16: #include "systm.h" 17: #include "mbuf.h" 18: #include "socket.h" 19: #include "socketvar.h" 20: #include "protosw.h" 21: #include "errno.h" 22: 23: #include "../net/if.h" 24: #include "../net/route.h" 25: 26: #include "domain.h" 27: #include "in.h" 28: #include "in_pcb.h" 29: #include "in_systm.h" 30: #include "ip.h" 31: #include "ip_var.h" 32: #include "tcp.h" 33: #include "tcp_fsm.h" 34: #include "tcp_seq.h" 35: #include "tcp_timer.h" 36: #include "tcp_var.h" 37: #include "tcpip.h" 38: 39: int tcpnodelack = 0; 40: int tcp_keepidle = TCPTV_KEEP_IDLE; 41: int tcp_keepintvl = TCPTV_KEEPINTVL; 42: int tcp_maxidle; 43: /* 44: * Fast timeout routine for processing delayed acks 45: */ 46: tcp_fasttimo() 47: { 48: register struct inpcb *inp; 49: register struct tcpcb *tp; 50: int s = splnet(); 51: 52: inp = tcb.inp_next; 53: if (inp) 54: for (; inp != &tcb; inp = inp->inp_next) 55: if ((tp = (struct tcpcb *)inp->inp_ppcb) && 56: (tp->t_flags & TF_DELACK)) { 57: tp->t_flags &= ~TF_DELACK; 58: tp->t_flags |= TF_ACKNOW; 59: tcpstat.tcps_delack++; 60: (void) tcp_output(tp); 61: } 62: splx(s); 63: } 64: 65: /* 66: * Tcp protocol timeout routine called every 500 ms. 67: * Updates the timers in all active tcb's and 68: * causes finite state machine actions if timers expire. 69: */ 70: tcp_slowtimo() 71: { 72: register struct inpcb *ip, *ipnxt; 73: register struct tcpcb *tp; 74: int s = splnet(); 75: register int i; 76: 77: tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; 78: /* 79: * Search through tcb's and update active timers. 80: */ 81: ip = tcb.inp_next; 82: if (ip == 0) { 83: splx(s); 84: return; 85: } 86: for (; ip != &tcb; ip = ipnxt) { 87: ipnxt = ip->inp_next; 88: tp = intotcpcb(ip); 89: if (tp == 0) 90: continue; 91: for (i = 0; i < TCPT_NTIMERS; i++) { 92: if (tp->t_timer[i] && --tp->t_timer[i] == 0) { 93: (void) tcp_usrreq(tp->t_inpcb->inp_socket, 94: PRU_SLOWTIMO, (struct mbuf *)0, 95: (struct mbuf *)i, (struct mbuf *)0); 96: if (ipnxt->inp_prev != ip) 97: goto tpgone; 98: } 99: } 100: tp->t_idle++; 101: if (tp->t_rtt) 102: tp->t_rtt++; 103: tpgone: 104: ; 105: } 106: tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ 107: #ifdef TCP_COMPAT_42 108: if ((long)tcp_iss < 0) 109: tcp_iss = 0; /* XXX */ 110: #endif 111: splx(s); 112: } 113: 114: /* 115: * Cancel all timers for TCP tp. 116: */ 117: tcp_canceltimers(tp) 118: struct tcpcb *tp; 119: { 120: register int i; 121: 122: for (i = 0; i < TCPT_NTIMERS; i++) 123: tp->t_timer[i] = 0; 124: } 125: 126: int tcp_backoff[TCP_MAXRXTSHIFT + 1] = 127: { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 128: 129: /* 130: * TCP timer processing. 131: */ 132: struct tcpcb * 133: tcp_timers(tp, timer) 134: register struct tcpcb *tp; 135: int timer; 136: { 137: register int rexmt; 138: 139: switch (timer) { 140: 141: /* 142: * 2 MSL timeout in shutdown went off. If we're closed but 143: * still waiting for peer to close and connection has been idle 144: * too long, or if 2MSL time is up from TIME_WAIT, delete connection 145: * control block. Otherwise, check again in a bit. 146: */ 147: case TCPT_2MSL: 148: if (tp->t_state != TCPS_TIME_WAIT && 149: tp->t_idle <= tcp_maxidle) 150: tp->t_timer[TCPT_2MSL] = tcp_keepintvl; 151: else 152: tp = tcp_close(tp); 153: break; 154: 155: /* 156: * Retransmission timer went off. Message has not 157: * been acked within retransmit interval. Back off 158: * to a longer retransmit interval and retransmit one segment. 159: */ 160: case TCPT_REXMT: 161: if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { 162: tp->t_rxtshift = TCP_MAXRXTSHIFT; 163: tcpstat.tcps_timeoutdrop++; 164: tp = tcp_drop(tp, ETIMEDOUT); 165: break; 166: } 167: tcpstat.tcps_rexmttimeo++; 168: rexmt = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; 169: rexmt *= tcp_backoff[tp->t_rxtshift]; 170: TCPT_RANGESET(tp->t_rxtcur, rexmt, TCPTV_MIN, TCPTV_REXMTMAX); 171: tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; 172: /* 173: * If losing, let the lower level know and try for 174: * a better route. Also, if we backed off this far, 175: * our srtt estimate is probably bogus. Clobber it 176: * so we'll take the next rtt measurement as our srtt; 177: * move the current srtt into rttvar to keep the current 178: * retransmit times until then. 179: */ 180: if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { 181: #if BSD>=43 182: in_losing(tp->t_inpcb); 183: #endif 184: tp->t_rttvar += (tp->t_srtt >> 2); 185: tp->t_srtt = 0; 186: } 187: tp->snd_nxt = tp->snd_una; 188: /* 189: * If timing a segment in this window, stop the timer. 190: */ 191: tp->t_rtt = 0; 192: /* 193: * Close the congestion window down to one segment 194: * (we'll open it by one segment for each ack we get). 195: * Since we probably have a window's worth of unacked 196: * data accumulated, this "slow start" keeps us from 197: * dumping all that data as back-to-back packets (which 198: * might overwhelm an intermediate gateway). 199: * 200: * There are two phases to the opening: Initially we 201: * open by one mss on each ack. This makes the window 202: * size increase exponentially with time. If the 203: * window is larger than the path can handle, this 204: * exponential growth results in dropped packet(s) 205: * almost immediately. To get more time between 206: * drops but still "push" the network to take advantage 207: * of improving conditions, we switch from exponential 208: * to linear window opening at some threshhold size. 209: * For a threshhold, we use half the current window 210: * size, truncated to a multiple of the mss. 211: * 212: * (the minimum cwnd that will give us exponential 213: * growth is 2 mss. We don't allow the threshhold 214: * to go below this.) 215: */ 216: { 217: u_int win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; 218: if (win < 2) 219: win = 2; 220: tp->snd_cwnd = tp->t_maxseg; 221: tp->snd_ssthresh = win * tp->t_maxseg; 222: } 223: (void) tcp_output(tp); 224: break; 225: 226: /* 227: * Persistance timer into zero window. 228: * Force a byte to be output, if possible. 229: */ 230: case TCPT_PERSIST: 231: tcpstat.tcps_persisttimeo++; 232: tcp_setpersist(tp); 233: tp->t_force = 1; 234: (void) tcp_output(tp); 235: tp->t_force = 0; 236: break; 237: 238: /* 239: * Keep-alive timer went off; send something 240: * or drop connection if idle for too long. 241: */ 242: case TCPT_KEEP: 243: tcpstat.tcps_keeptimeo++; 244: if (tp->t_state < TCPS_ESTABLISHED) 245: goto dropit; 246: if (tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE && 247: tp->t_state <= TCPS_CLOSE_WAIT) { 248: if (tp->t_idle >= tcp_keepidle + tcp_maxidle) 249: goto dropit; 250: /* 251: * Send a packet designed to force a response 252: * if the peer is up and reachable: 253: * either an ACK if the connection is still alive, 254: * or an RST if the peer has closed the connection 255: * due to timeout or reboot. 256: * Using sequence number tp->snd_una-1 257: * causes the transmitted zero-length segment 258: * to lie outside the receive window; 259: * by the protocol spec, this requires the 260: * correspondent TCP to respond. 261: */ 262: tcpstat.tcps_keepprobe++; 263: #ifdef TCP_COMPAT_42 264: /* 265: * The keepalive packet must have nonzero length 266: * to get a 4.2 host to respond. 267: */ 268: tcp_respond(tp, tp->t_template, 269: tp->rcv_nxt - 1, tp->snd_una - 1, 0); 270: #else 271: tcp_respond(tp, tp->t_template, 272: tp->rcv_nxt, tp->snd_una - 1, 0); 273: #endif 274: tp->t_timer[TCPT_KEEP] = tcp_keepintvl; 275: } else 276: tp->t_timer[TCPT_KEEP] = tcp_keepidle; 277: break; 278: dropit: 279: tcpstat.tcps_keepdrops++; 280: tp = tcp_drop(tp, ETIMEDOUT); 281: break; 282: } 283: return (tp); 284: }