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