/*
 *	This file contains definitions and prototypes for the structures
 *	and functions used throughout TCP.
 *
 *	04/17/94, Kay Roemer.
 */

#ifndef _TCP_H
#define _TCP_H

#include "inet.h"
#include "timer.h"
#include "iov.h"
#include "buf.h"

#define TCP_MSS		536		/* maximum segment size */

#define TCP_MSL		(60000/EVTGRAN)	/* max segment lifetime, 1 minute */
#define TCP_MINRETRANS	(  200/EVTGRAN)	/* min time before retrans, 200 ms */
#define TCP_MAXRETRANS	(2*TCP_MSL)	/* max time before retrans, 120 s */
#define TCP_MAXPROBE	(30000/EVTGRAN) /* max time before probing, 30 s */
#define TCP_MAXRETRY	15		/* max 15 retrans before error */

#define TCP_REXMITHRESH	3		/* dupack threshhold */

#define TCP_RESERVE	140
#define TCP_MINLEN	(sizeof (struct tcp_dgram))

#define TCP_DATA(th)	((char *)(th) + (th)->hdrlen * 4)

/* TCP datagram header */
struct tcp_dgram {
	unsigned short	srcport;	/* source port */
	unsigned short	dstport;	/* destination port */
	long		seq;		/* sequence number */
	long		ack;		/* acknowledge number */
	unsigned short	hdrlen:4;	/* TCP header len in longs */
	unsigned short	flags:12;	/* segment flags */
#define TCPF_URG	0x020		/* segment contains urgent data */
#define TCPF_ACK	0x010		/* segment contains acknowledgement */
#define TCPF_PSH	0x008		/* push function */
#define TCPF_RST	0x004		/* reset connection */
#define TCPF_SYN	0x002		/* syncronice sequence numbers */
#define TCPF_FIN	0x001		/* finish connection */
#define TCPF_FREEME	0x800
	unsigned short	window;		/* window size */
	short		chksum;		/* checksum */
	unsigned short	urgptr;		/* urgent data offset rel to seq */
	char		data[0];	/* options/user data */
};

/* TCP options */
#define TCPOPT_EOL	0	/* end of option list */
#define TCPOPT_NOP	1	/* no operation */
#define TCPOPT_MSS	2	/* maximum segment size */

/* TCP setsockopt options */
#define TCP_NODELAY	1	/* disable Nagle algorithm */

/* Sequence space comparators */
#define SEQEQ(x, y)	((long)(x) == (long)(y))	/* (x == y) mod 2^32 */
#define SEQNE(x, y)	((long)(x) != (long)(y))	/* (x != y) mod 2^32 */
#define SEQLT(x, y)	((long)(x) - (long)(y) <  0)	/* (x <  y) mod 2^32 */
#define SEQLE(x, y)	((long)(x) - (long)(y) <= 0)	/* (x <= y) mod 2^32 */
#define SEQGT(x, y)	((long)(x) - (long)(y) >  0)	/* (x >  y) mod 2^32 */
#define SEQGE(x, y)	((long)(x) - (long)(y) >= 0)	/* (x >= y) mod 2^32 */

/* TCB states */
#define TCBS_CLOSED		0
#define TCBS_LISTEN		1
#define TCBS_SYNSENT		2
#define TCBS_SYNRCVD		3
#define TCBS_ESTABLISHED	4
#define TCBS_FINWAIT1		5
#define TCBS_FINWAIT2		6
#define TCBS_CLOSEWAIT		7
#define TCBS_LASTACK		8
#define TCBS_CLOSING		9
#define TCBS_TIMEWAIT		10

/* TCB output states */
#define TCBOS_IDLE		0
#define TCBOS_RETRANS		1
#define TCBOS_PERSIST		2
#define TCBOS_XMIT		3

/* TCB output events */
#define TCBOE_SEND		0
#define TCBOE_ACKRCVD		1
#define TCBOE_WNDOPEN		2
#define TCBOE_WNDCLOSE		3
#define TCBOE_TIMEOUT		4
#define TCBOE_DUPACK		5

#define TCB_OSTATE(t, e)	((*tcb_ostate[(t)->ostate]) (t, e))

/* TCP control block */
struct tcb {
	struct in_data	*data;		/* backlink to inet socket */
	short		state;		/* TCB state, TCBS_* */
	short		ostate;		/* TCB output state, TCBOS_* */
	short		flags;		/* misc flags */
#define TCBF_PSH	0x01		/* PUSH seen */
#define TCBF_FIN	0x02		/* FIN seen */
#define TCBF_PASSIVE	0x04		/* tcb is forked off a server */
#define TCBF_DORTT	0x08		/* measuring RTT */
#define TCBF_NDELAY	0x10		/* disable nagle algorithm */

	long		snd_isn;	/* initial send sequence number */
	long		snd_una;	/* oldest unacknowledged seq number */
	long		snd_nxt;	/* next seq number to send */
	long		snd_wnd;	/* send window size */
	long		snd_cwnd;	/* congestion window size */
	long		snd_thresh;	/* cong. window threshold */
	long		snd_wndseq;	/* seq number of last window update */
	long		snd_wndack;	/* ack number of last window update */
	long		snd_mss;	/* send max segment size */
	long		snd_urg;	/* send urgent pointer */

	long		rcv_isn;	/* initial recv sequence number */
	long		rcv_nxt;	/* next seq number to recv */
	long		rcv_wnd;	/* receive window size */
	long		rcv_mss;	/* recv max segment size */
	long		rcv_urg;	/* receive urgent pointer */

	long		seq_psh;	/* sequence number of PUSH */
	long		seq_fin;	/* sequence number of FIN */
	long		seq_read;	/* sequence of next byte to read() */
	long		seq_uread;	/* sequence of next urg byte to read */
	long		seq_write;	/* sequence of next byte to write */

	long		rttseq;		/* calc RTT when this gets acked */
	long		rtt;		/* estimated round trip time */
	long		rttdev;		/* deviation in round trip time */
	short		backoff;	/* timer backoff */

	short		dupacks;	/* # of duplicate acks */

	short		nretrans;	/* number of retransmits */
	long		retrans_tmo;	/* retransmit timeout value */
	long		persist_tmo;	/* persist timeout value */
	struct event	timer_evt;	/* persist/retransmit timer event */

	long		keep_tmo;	/* keepalive timeout value */
	struct event	keep_evt;	/* keepalive timer event */

	struct event	delete_evt;	/* tcb deletion timer event */
};

#ifndef NOEXTERNS
extern void		(*tcb_state[])	(struct tcb *, BUF *);
extern void		(*tcb_ostate[])	(struct tcb *, short);

extern struct tcb	*tcb_alloc	(void);
extern void		tcb_free	(struct tcb *);
extern void		tcb_reset	(struct tcb *, long);
extern void		tcb_delete	(struct tcb *);
extern void		tcb_wait	(struct tcb *);

extern long		tcp_isn		(void);
static short		tcp_finished	(struct tcb *);
extern long		tcp_sndrst	(BUF *);
extern long		tcp_sndack	(struct tcb *, BUF *);
extern short		tcp_valid	(struct tcb *, BUF *);
static long		tcp_seglen	(BUF *, struct tcp_dgram *);
static long		tcp_datalen	(BUF *, struct tcp_dgram *);
extern long		tcp_options	(struct tcb *, struct tcp_dgram *);
extern long		tcp_mss		(unsigned long, long);
extern unsigned short	tcp_checksum	(struct tcp_dgram *, unsigned short,
					unsigned long, unsigned long);

extern long		tcp_rcvurg	(struct tcb *, BUF *);

extern long		tcp_timeout	(struct tcb *);
extern long		tcp_rcvwnd	(struct tcb *, short);
extern long		tcp_output	(struct tcb *, struct iovec *, short,
					long, long, short);

extern void		tcp_init	(void);
extern void		tcp_dump	(BUF *);

extern void		tcp_siginit	(void);
extern void		tcp_sendsig	(struct tcb *, short);
#endif

/*
 * Some heavily used one-liners as inlines.
 */

static inline short
tcp_finished (tcb)
	struct tcb *tcb;
{
	return (tcb->flags & TCBF_FIN && SEQLT (tcb->seq_fin, tcb->rcv_nxt));
}

/* Return the length of the TCP segment in `buf'. */
static inline long
tcp_seglen (buf, tcph)
	BUF *buf;
	struct tcp_dgram *tcph;
{
	long len;

	len = (long)buf->dend - (long)tcph - tcph->hdrlen*4;
	if (tcph->flags & TCPF_SYN) ++len;
	if (tcph->flags & TCPF_FIN) ++len;
	return len;
}

static inline long
tcp_datalen (buf, tcph)
	BUF *buf;
	struct tcp_dgram *tcph;
{
	return ((long)buf->dend - (long)tcph - tcph->hdrlen*4);
}

#endif /* _TCP_H */
