xref: /csrg-svn/sys/netinet/tcp_timer.c (revision 5284)
1*5284Sroot /* tcp_timer.c 4.10 81/12/21 */
25069Swnj 
35069Swnj #include "../h/param.h"
45069Swnj #include "../h/systm.h"
55069Swnj #include "../h/mbuf.h"
65069Swnj #include "../h/socket.h"
75069Swnj #include "../h/socketvar.h"
85069Swnj #include "../h/protosw.h"
95089Swnj #include "../net/in.h"
105089Swnj #include "../net/in_pcb.h"
115089Swnj #include "../net/in_systm.h"
125069Swnj #include "../net/if.h"
135069Swnj #include "../net/ip.h"
145069Swnj #include "../net/ip_var.h"
155069Swnj #include "../net/tcp.h"
165069Swnj #include "../net/tcp_fsm.h"
175089Swnj #include "../net/tcp_seq.h"
185089Swnj #include "../net/tcp_timer.h"
195069Swnj #include "../net/tcp_var.h"
205089Swnj #include "../net/tcpip.h"
215112Swnj #include "../errno.h"
225069Swnj 
23*5284Sroot int	tcpdelack = 0;
245069Swnj /*
255069Swnj  * Fast timeout routine for processing delayed acks
265069Swnj  */
275069Swnj tcp_fasttimo()
285069Swnj {
29*5284Sroot 	register struct inpcb *inp;
30*5284Sroot 	register struct tcpcb *tp;
31*5284Sroot 	int s = splnet();
32*5284Sroot COUNT(TCP_FASTTIMO);
335069Swnj 
34*5284Sroot 	for (inp = tcb.inp_next; inp != &tcb; inp = inp->inp_next)
35*5284Sroot 		if ((tp = (struct tcpcb *)inp->inp_ppcb) &&
36*5284Sroot 		    (tp->t_flags & TF_DELACK)) {
37*5284Sroot 			tp->t_flags &= ~TF_DELACK;
38*5284Sroot 			tp->t_flags |= TF_ACKNOW;
39*5284Sroot 			(void) tcp_output(tp);
40*5284Sroot 		}
41*5284Sroot 	splx(s);
425069Swnj }
435069Swnj 
445069Swnj /*
455069Swnj  * Tcp protocol timeout routine called every 500 ms.
465069Swnj  * Updates the timers in all active tcb's and
475069Swnj  * causes finite state machine actions if timers expire.
485069Swnj  */
495069Swnj tcp_slowtimo()
505069Swnj {
515069Swnj 	register struct inpcb *ip;
525069Swnj 	register struct tcpcb *tp;
535069Swnj 	int s = splnet();
545069Swnj 	register int i;
555089Swnj COUNT(TCP_SLOWTIMO);
565069Swnj 
575069Swnj 	/*
585069Swnj 	 * Search through tcb's and update active timers.
595069Swnj 	 */
605245Sroot 	ip = tcb.inp_next;
615245Sroot 	if (ip == 0) {
625245Sroot 		splx(s);
635245Sroot 		return;
645245Sroot 	}
655245Sroot 	for (; ip != &tcb; ip = ip->inp_next) {
665069Swnj 		tp = intotcpcb(ip);
675260Swnj 		if (tp == 0)
685260Swnj 			continue;
695075Swnj 		for (i = 0; i < TCPT_NTIMERS; i++) {
705089Swnj 			if (tp->t_timer[i] && --tp->t_timer[i] == 0)
715069Swnj 				(void) tcp_usrreq(tp->t_inpcb->inp_socket,
725069Swnj 				    PRU_SLOWTIMO, (struct mbuf *)0,
735069Swnj 				    (caddr_t)i);
745069Swnj 		}
755165Swnj 		tp->t_idle++;
765165Swnj 		if (tp->t_rtt)
775165Swnj 			tp->t_rtt++;
785069Swnj 	}
795075Swnj 	tcp_iss += TCP_ISSINCR/PR_SLOWHZ;		/* increment iss */
805069Swnj 	splx(s);
815069Swnj }
825069Swnj 
835069Swnj /*
845075Swnj  * Cancel all timers for TCP tp.
855069Swnj  */
865089Swnj tcp_canceltimers(tp)
875069Swnj 	struct tcpcb *tp;
885069Swnj {
895069Swnj 	register int i;
905069Swnj 
915089Swnj COUNT(TCP_CANCELTIMERS);
925075Swnj 	for (i = 0; i < TCPT_NTIMERS; i++)
935075Swnj 		tp->t_timer[i] = 0;
945069Swnj }
955069Swnj 
965069Swnj /*
975165Swnj  * TCP timer processing.
985069Swnj  */
995075Swnj tcp_timers(tp, timer)
1005069Swnj 	register struct tcpcb *tp;
1015075Swnj 	int timer;
1025069Swnj {
1035069Swnj 
1045069Swnj COUNT(TCP_TIMERS);
1055089Swnj 	switch (timer) {
1065069Swnj 
1075165Swnj 	/*
1085165Swnj 	 * 2 MSL timeout in shutdown went off.  Delete connection
1095165Swnj 	 * control block.
1105165Swnj 	 */
1115075Swnj 	case TCPT_2MSL:
1125075Swnj 		tcp_close(tp);
1135075Swnj 		return;
1145069Swnj 
1155165Swnj 	/*
1165165Swnj 	 * Retransmission timer went off.  Message has not
1175165Swnj 	 * been acked within retransmit interval.  Back off
1185165Swnj 	 * to a longer retransmit interval and retransmit all
1195165Swnj 	 * unacknowledged messages in the window.
1205165Swnj 	 */
1215075Swnj 	case TCPT_REXMT:
1225165Swnj 		tp->t_rxtshift++;
1235165Swnj 		TCPT_RANGESET(tp->t_timer[TCPT_REXMT],
124*5284Sroot 		    ((int)(2 * tp->t_srtt)),
1255165Swnj 		    TCPTV_MIN, TCPTV_MAX);
126*5284Sroot 		TCPT_RANGESET(tp->t_timer[TCPT_REXMT],
127*5284Sroot 		    tp->t_timer[TCPT_REXMT] << tp->t_rxtshift,
128*5284Sroot 		    TCPTV_MIN, TCPTV_MAX);
129*5284Sroot 		if (tp->t_timer[TCPT_REXMT] > TCPTV_MAXIDLE / 2) {
130*5284Sroot 			tcp_drop(tp, ETIMEDOUT);
131*5284Sroot 			return;
132*5284Sroot 		}
1335276Swnj printf("rexmt set to %d\n", tp->t_timer[TCPT_REXMT]);
1345165Swnj 		tp->snd_nxt = tp->snd_una;
1355165Swnj 		/* this only transmits one segment! */
1365165Swnj 		(void) tcp_output(tp);
1375075Swnj 		return;
1385069Swnj 
1395165Swnj 	/*
1405165Swnj 	 * Persistance timer into zero window.
1415165Swnj 	 * Force a byte to be output, if possible.
1425165Swnj 	 */
1435075Swnj 	case TCPT_PERSIST:
1445165Swnj 		tp->t_force = 1;
1455165Swnj 		(void) tcp_output(tp);
1465165Swnj 		tp->t_force = 0;
1475165Swnj 		TCPT_RANGESET(tp->t_timer[TCPT_PERSIST],
1485165Swnj 		    2 * tp->t_srtt, TCPTV_PERSMIN, TCPTV_MAX);
1495089Swnj 		return;
1505069Swnj 
1515165Swnj 	/*
1525165Swnj 	 * Keep-alive timer went off; send something
1535165Swnj 	 * or drop connection if idle for too long.
1545165Swnj 	 */
1555075Swnj 	case TCPT_KEEP:
1565165Swnj 		if (tp->t_state < TCPS_ESTABLISHED ||
1575165Swnj 		    tp->t_idle >= TCPTV_MAXIDLE) {
1585165Swnj 			tcp_drop(tp, ETIMEDOUT);
1595165Swnj 			return;
1605165Swnj 		}
1615165Swnj 		tcp_respond(tp->t_template, tp->rcv_nxt, tp->snd_una-1, 0);
1625165Swnj 		tp->t_timer[TCPT_KEEP] = TCPTV_KEEP;
1635075Swnj 		return;
1645069Swnj 	}
1655069Swnj }
166