/* TCP timeout routines
 * Copyright 1991 Phil Karn, KA9Q
 */
#include <stdio.h>
#include "global.h"
#include "mbuf.h"
#include "timer.h"
#include "netuser.h"
#include "internet.h"
#include "tcp.h"

int tcptimertype;       /* default backoff to binary exponential */
int Tcp_blimit = 31;

/* Timer timeout */
void
tcp_timeout(p)
void *p;
{
	register struct tcb *tcb;

	tcb = p;
	if(tcb == NULLTCB)
		return;

	/* Make sure the timer has stopped (we might have been kicked) */
	stop_timer(&tcb->timer);

	switch(tcb->state){
	case TCP_TIME_WAIT:	/* 2MSL timer has expired */
		close_self(tcb,NORMAL);
		break;
	default:		/* Retransmission timer has expired */
		tcb->flags.retran = 1;	/* Indicate > 1  transmission */
        if( !Tcp_retries || tcb->backoff < Tcp_retries) {
			tcb->backoff++;
			tcb->snd.ptr = tcb->snd.una;
			/* Reduce slowstart threshold to half current window */
			tcb->ssthresh = tcb->cwind / 2;
			tcb->ssthresh = max(tcb->ssthresh,tcb->mss);
			/* Shrink congestion window to 1 packet */
			tcb->cwind = tcb->mss;
			tcp_output(tcb);
        } else reset_tcp(tcb);
	}
}

/* Backoff function - the subject of much research */
int32
backoff(n)
int n;
{
	if(tcptimertype) {	/* Linear */
		if(n >= Tcp_blimit)		/* At backoff limit -- N1BEE */
			n = Tcp_blimit;
		else
			++n;
		return (int32) n;     /* Linear backoff for sensible values! */
	} else {		/* Binary exponential */
		if(n > min(31,Tcp_blimit))
			n = min(31,Tcp_blimit);
				/* Prevent truncation to zero */
		return 1L << n;	/* Binary exponential back off */
	}
}

