/*
 * The code in this file is derived from and very similar to the example
 * implementation provided in RFC 1144, and is therefore sort-of covered
 * by its copyright:
 *
 * Copyright (C) 1989 Regents of the University of California.
 *
 * modified for KA9Q Internet Software Package by
 * Katie Stevens (dkstevens@ucdavis.edu)
 * University of California, Davis
 * Computing Services
 *	- 01-31-90	initial adaptation
 *
 *	- Feb 1991	Bill_Simpson@um.cc.umich.edu
 *			variable number of conversation slots
 *			allow zero or one slots
 *			separate routines
 *			status display
 *
 * This adaptation (for cslip.device) by Olaf 'Rhialto' Seibert.
 */

/*
 * Compressed packet format:
 *
 * The first octet contains the packet type (top 3 bits), TCP
 * 'push' bit, and flags that indicate which of the 4 TCP sequence
 * numbers have changed (bottom 5 bits).  The next octet is a
 * conversation number that associates a saved IP/TCP header with
 * the compressed packet.  The next two octets are the TCP checksum
 * from the original datagram.	The next 0 to 15 octets are
 * sequence number changes, one change per bit set in the header
 * (there may be no changes and there are two special cases where
 * the receiver implicitly knows what changed -- see below).
 *
 * There are 5 numbers which can change (they are always inserted
 * in the following order): TCP urgent pointer, window,
 * acknowlegement, sequence number and IP ID.  (The urgent pointer
 * is different from the others in that its value is sent, not the
 * change in value.)  Since typical use of SLIP links is biased
 * toward small packets (see comments on MTU/MSS below), changes
 * use a variable length coding with one octet for numbers in the
 * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
 * range 256 - 65535 or 0.  (If the change in sequence number or
 * ack is more than 65535, an uncompressed packet is sent.)
 */

/*
 * Packet types (must not conflict with IP protocol version)
 *
 * The top nibble of the first octet is the packet type.  There are
 * three possible types: IP (not proto TCP or tcp with one of the
 * control flags set); uncompressed TCP (a normal IP/TCP packet but
 * with the 8-bit protocol field replaced by an 8-bit connection id --
 * this type of packet syncs the sender & receiver); and compressed
 * TCP (described above).
 *
 * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
 * is logically part of the 4-bit "changes" field that follows.  Top
 * three bits are actual packet type.  For backward compatibility
 * and in the interest of conserving bits, numbers are chosen so the
 * IP protocol version number (4) which normally appears in this nibble
 * means "IP packet".
 */

typedef unsigned long  u_long;
typedef unsigned int   u_int;
typedef unsigned short u_short;
typedef unsigned char  u_char;

typedef unsigned short int16;
typedef unsigned long int32;

/* IP and TCP header format */

struct ip_header {
	char v_ihl;		/* Version + IP header length */
#define IPVERSION	4
	char tos;		/* Type of service */
	int16 length;		/* Total length */
	int16 id;		/* Identification */
	int16 fl_offs;		/* Flags + fragment offset */

#define F_OFFSET	0x1fff	/* Offset field */
#define DF	0x4000		/* Don't fragment flag */
#define MF	0x2000		/* More Fragments flag */

	char ttl;		/* Time to live */
	char protocol;		/* Protocol */
	int16 checksum; 	/* Header checksum */
	int32 source;		/* Source address */
	int32 dest;		/* Destination address */
};

/* TCP segment header */
struct tcp_header {
	int16 source;	/* Source port */
	int16 dest;	/* Destination port */
	int32 seq;	/* Sequence number */
	int32 ack;	/* Acknowledgment number */
	char offset;	/* Data offset */
	char flags;	/* Flags, data offset */
#define DSHIFT	4	/* Data offset field */
#define DMASK	0x0f	/* Mask for normalized data offset field */
#define URG	0x20	/* URGent flag */
#define ACK	0x10	/* ACKnowledgment flag */
#define PSH	0x08	/* PuSH flag */
#define RST	0x04	/* ReSeT flag */
#define SYN	0x02	/* SYNchronize flag */
#define FIN	0x01	/* FINal flag */
	int16 wnd;	/* Receiver flow control window */
	int16 checksum; /* Header + data checksum */
	int16 up;	/* Urgent pointer */
};

/* IP protocol field values */
#define TCP_PTCL	6	/* Transmission Control Protocol */

#define lonibble(x)     ((x) & 0x0F)

struct mbuf {
	u_char *m_off;	/* pointer to start of data */
	int	m_len;	/* length of data */
};
#define mtod(m, t)      ((t)(m->m_off))

/* Appendix A.1  Definitions and State Data */

#define MAX_STATES	16	/* must be >2 and <255 */
#define MAX_HDR 	128	/* max TCP+IP hdr length (by protocol def) */

/* packet types */
#define TYPE_IP 	0x40
#define TYPE_UNCOMPRESSED_TCP 0x70
#define TYPE_COMPRESSED_TCP 0x80
#define TYPE_ERROR	0x00	/* this is not a type that ever appears on
				 * the wire. The receive framer uses it to
				 * tell the decompressor there was a packet
				 * transmission error. */
/*
 * Bits in the first octet of the compressed packet
 */

/* flag bits for what changed in a packet */

#define NEW_C		0x40	/* Connection id */
#define NEW_I		0x20	/* IP ID field (change != 1) */
#define TCP_PUSH_BIT	0x10	/* TCP PUSH bit */

#define NEW_S		0x08	/* Sequence number */
#define NEW_A		0x04	/* Acknowledgement */
#define NEW_W		0x02	/* Window size */
#define NEW_U		0x01	/* Urgent pointer */

/* reserved, special-case values of above */

#define SPECIAL_I	(NEW_S|NEW_W|NEW_U)     /* echoed interactive traffic */
#define SPECIAL_D	(NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */
#define SPECIALS_MASK	(NEW_S|NEW_A|NEW_W|NEW_U)

/*
 * "state" data for each active tcp conversation on the wire. This is
 * basically a copy of the entire TCP/IP header from the last packet together
 * with a small identifier the transmit & receive ends of the line use to
 * locate the saved header.
 */
struct cstate {
	struct cstate *cs_next; /* next most recently used cstate (xmit only) */
	u_short cs_hlen;	/* size of hdr (receive only) */
	u_char cs_id;		/* connection # associated with this state */
	u_char cs_filler;
	union {
		u_char csu_hdr[MAX_HDR];
		int32 csu_hdr4[1];
		struct ip_header csu_ip; /* ip/tcp hdr from most recent packet */
	} slcs_u;
};
#define cs_ip		slcs_u.csu_ip
#define cs_hdr		slcs_u.csu_hdr
#define cs_hdr4 	slcs_u.csu_hdr4

/*
 * all the state data for one serial line (we need one of these per line).
 */
struct slcompress {
	struct cstate *tstate;	/* transmit connection states (array)*/
	struct cstate *rstate;	/* receive connection states (array)*/

	u_char tslot_limit;	/* highest transmit slot id (0-l)*/
	u_char rslot_limit;	/* highest receive slot id (0-l)*/

	struct cstate *last_cs; /* most recently used tstate */
	u_char last_recv;	/* last received connection id */
	u_char last_xmit;	/* last sent connection id */
	u_char flags;

	u_long sls_o_nontcp;	/* outbound non-TCP packets */
	u_long sls_o_tcp;	/* outbound TCP packets */
	u_long sls_o_uncompressed;	/* outbound uncompressed packets */
	u_long sls_o_compressed;/* outbound compressed packets */
	u_long sls_o_searches;	/* searches for connection state */
	u_long sls_o_misses;	/* times couldn't find conn. state */

	u_long sls_i_ip;	/* inbound non-TCP packets */
	u_long sls_i_uncompressed;	/* inbound uncompressed packets */
	u_long sls_i_compressed;/* inbound compressed packets */
	u_long sls_i_error;	/* inbound error packets */
	u_long sls_i_tossed;	/* inbound packets tossed because of error */

	signed char on; 	/* ==SL_ON: on, >0: trycount, ==0: off */
};

/* last_xmit/last_recv initial value */
#define NO_CID		255

/* flag values */
#define SLF_TOSS	1	/* tossing rcvd frames because of input err */
#define SLF_ALLOWED	2	/* allow receiving compression */
#define SLF_ON		4	/* use compression */

/* optional trycount feature */
#define TRYCOUNT	3	/* try 3 TCP_UNCOMPRESSED packets */
#define SL_ON		-1	/* use compression */

/*
 * The following macros are used to encode and decode numbers. They all
 * assume that 'cp' points to a buffer where the next byte encoded (decoded)
 * is to be stored (retrieved). Since the decode routines do arithmetic,
 * they have to convert from and to network byte order.
 */

/*
 * ENCODE encodes a number that is known to be non-zero. ENCODEZ checks for
 * zero (zero has to be encoded in the long, 3 byte form).
 */

#define ENCODE(n) { \
	if ((u_short)(n) >= 256) { \
	    *cp++ = 0; \
	    cp[1] = (n); \
	    cp[0] = (n) >> 8; \
	    cp += 2; \
	} else { \
	    *cp++ = (n); \
	} \
    }

#define ENCODEZ(n) { \
	if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
	    *cp++ = 0; \
	    cp[1] = (n); \
	    cp[0] = (n) >> 8; \
	    cp += 2; \
	} else { \
	    *cp++ = (n); \
	} \
    }

/*
 * DECODEL takes the compressed change at byte cp and adds it to the
 * current value of packet field 'f' (which must be a 4-byte (long) integer
 * in the current network byte order). DECODES does the same for a 2-byte (short)
 * field. DECODEU takes the change at cp and stuffs it into the (short) field f.
 * 'cp' is updated to point to the next field in the compressed header.
 */

#define DECODEL(f) { \
	if (*cp == 0) { \
	    (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \
	    cp += 3; \
	} else { \
	    (f) = htonl(ntohl(f) + (u_long)*cp++); \
	} \
    }

#define DECODES(f) { \
	if (*cp == 0) { \
	    (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \
	    cp += 3; \
	} else { \
	    (f) = htons(ntohs(f) + (u_short)*cp++); \
	} \
    }

#define DECODEU(f) { \
	if (*cp == 0) { \
	    (f) = htons(((cp[1] << 8) | cp[2])); \
	    cp += 3; \
	} else { \
	    (f) = htons((u_short)*cp++); \
	} \
    }

#define BCOPY(s, d, l)  memcpy(d, s, l)
#define BCMP(s, d, l)   memcmp(d, s, l)

#define htons(s)        (s)     /* on big-endian machines, that is */
#define ntohs(s)        (s)
#define htonl(l)        (l)
#define ntohl(l)        (l)

/* Sana2 special stats values */

#define S2SS_CSLIP_O_NONTCP	((S2WireType_CSLIP << 16) | 1)
#define S2SS_CSLIP_O_TCP	((S2WireType_CSLIP << 16) | 2)
#define S2SS_CSLIP_O_UNCOMPRESSED   ((S2WireType_CSLIP << 16) | 3)
#define S2SS_CSLIP_O_COMPRESSED ((S2WireType_CSLIP << 16) | 4)
#define S2SS_CSLIP_O_SEARCHES	((S2WireType_CSLIP << 16) | 5)
#define S2SS_CSLIP_O_MISSES	((S2WireType_CSLIP << 16) | 6)

#define S2SS_CSLIP_I_IP 	((S2WireType_CSLIP << 16) | 17)
#define S2SS_CSLIP_I_UNCOMPRESSED   ((S2WireType_CSLIP << 16) | 18)
#define S2SS_CSLIP_I_COMPRESSED ((S2WireType_CSLIP << 16) | 19)
#define S2SS_CSLIP_I_ERROR	((S2WireType_CSLIP << 16) | 20)
#define S2SS_CSLIP_I_TOSSED	((S2WireType_CSLIP << 16) | 21)

/* Prototypes for functions defined in cslip.c */

u_char sl_compress_tcp(struct mbuf *m, struct slcompress *comp);
void sl_xmit_error(struct slcompress *comp);
struct mbuf *sl_uncompress_tcp(struct mbuf *m, u_int type, struct slcompress *comp);
void sl_compress_init(struct slcompress *comp, int, int);
void sl_compress_deinit(struct slcompress *comp);

