/*
*    Protocol structures for network communication
*
****************************************************************************
*                                                                          *
*      part of:                                                            *
*      TCP/IP kernel for NCSA Telnet                                       *
*      by Tim Krauskopf                                                    *
*                                                                          *
*      National Center for Supercomputing Applications                     *
*      152 Computing Applications Building                                 *
*      605 E. Springfield Ave.                                             *
*      Champaign, IL  61820                                                *
*                                                                          *
****************************************************************************
*
*  This file contains the structure definitions for each type of 
*  protocol that this program wishes to handle.  A companion file,
*  'protinit.c' initializes sample versions of each type of header, 
*  improving the efficiency of sending packets with constants in most
*  of the fields.
* 
*/
/************************************************************************/
/*  Ethernet frames
*      All Ethernet transmissions should use this Ethernet header which
*   denotes what type of packet is being sent.
*
*   The header is 14 bytes.  The first 6 bytes are the target's hardware
*   Ethernet address, the second 6 are the sender's hardware address and
*   the last two bytes are the packet type.  Some packet type definitions
*   are included here.
*
*   the two-byte packet type is byte-swapped, PC is lo-hi, Ether is hi-lo
*/

#define  EXNS  0x0006           /* probably need swapping */
#define  EIP   0x0008
#define  EARP  0x0608
#define  ERARP	0x3580			/* I guess this is RARP */
#define  ECHAOS  0x0408

#define DADDLEN	6
#define	MTU 1500		/* maximum ethernet transmission unit */
#define MAXSEG 1400
#define MINRTO	18		/* actually 18.2 ticks per second */

#define WINDOWSIZE	4096
#define	IMAXLEN	(MTU - 20)	/* max IP data length */
#define UMAXLEN (IMAXLEN - 8)	/* max UDP data length */
#define TMAXSIZE (IMAXLEN - 20)	/* max TCP data length */
#define ICMPMAX 300 
#define AMAXLEN	128		/* must agree with number in pkglue.asm */

#ifdef __HIGHC__
_packed
#endif
#ifdef __WATCOMC__
#pragma pack(1);
#endif
struct ether {
	u_char	dest[DADDLEN];	/* where the packet is going */
	u_char	me[DADDLEN];	/* who am i to send this packet */
	u_short	type;		/* Ethernet packet type  */
};
typedef struct ether DLAYER;

/* defined so we can do structure compares */
struct daddr {
	u_char	addr[DADDLEN];
};

/*************************************************************************/
/*  Dave Plummer's  Address Resolution Protocol (ARP) (RFC-826) and 
*   Finlayson, Mann, Mogul and Theimer's Reverse ARP packets.
*
*   Note that the 2 byte ints are not byte-swapped.  The protocols calls for
*   in-order bytes, and the PC is lo-hi ordered.
*   
*/

#define RARPR	0x0004          /*  RARP reply, from host */
#define RARPQ	0x0003		/*  RARP request */
#define ARPREP  0x0002          /*  reply */
#define ARPREQ  0x0001          /*  request */
#define HTYPE 	0x0001		/*  Ethernet hardware type */

#define ARPTO   7
#define ARPWAIT 30
#define CACHETO 7000
#define ARPRESEND	4000

#ifdef __HIGHC__
_packed
#endif
struct arp {
	DLAYER	d; 		/* data link layer packet header */
	u_short	hrd;		/* hardware type, Ethernet = 1 */
	u_short	pro;		/* protocol type to resolve for */
	u_char	hln;		/* byte length of hardware addr = 6 for ETNET */
	u_char	pln;		/* byte length of protocol = 4 for IP */
	u_short	op;		/* opcode, request = 1, reply = 2, RARP = 3,4 */
	u_char	sha[DADDLEN];	/* sender hardware address */
	u_long	spa;		/* sender protocol address */
	u_char	tha[DADDLEN];	/* target hardware address */
	u_long	tpa;		/* target protocol address */
};
typedef struct arp ARPKT;

#define NARPC	10

/***********************************************************************/
/*  ARP cache
*   Data structure for saving low-level information until needed
*/
#ifdef __HIGHC__
_packed
#endif
struct acache {
	u_char	hrd[DADDLEN];	/* hardware address for this IP address */
	u_long	ip;		/* the IP # in question */
	u_long	tm;		/* time information */
#ifdef notdef
	u_char	gate;		/* is this a gateway? */
#endif
};

/***********************************************************************/
/*   Internet protocol
*
*/
#ifdef __HIGHC__
_packed
#endif
struct iph {
	u_char	versionandhdrlen;	/* I prefer to OR them myself */
					/* each half is four bits */
	u_char	service;		/* type of service for IP */
	u_short	tlen;			/* total length of IP packet */
	u_short	ident;			/* these are all BYTE-SWAPPED! */
	u_short	frags;			/* combination of flags and value */
	u_char	ttl;    		/* time to live */
	u_char	protocol;		/* higher level protocol type */
	u_short	check;			/* header checksum, byte-swapped */
	u_long	ipsource;		/* IP addresses */
	u_long	ipdest;
};
typedef struct iph IPLAYER;

/*  
*  full IP packet, with data and ip header
*/

#ifdef __HIGHC__
_packed
#endif
struct ip {
	DLAYER d;
	IPLAYER i;
	union {
		u_char	data[536]; /* recommended max, may include options */
		u_char	options[40];
	} x;
};
typedef struct ip IPKT;

#define PROTUDP		17
#define PROTTCP		6		/* standard protocol types for IP */
#define PROTICMP	1
/************************************************************************/
/* ICMP packet
*  all of them are of a similar form, some generic fields are spec'd here.
*/
#ifdef __HIGHC__
_packed
#endif
struct icmph {
	u_char	type;		/* ICMP type field */
	u_char	code;		/* ICMP code field */
	u_short	check;          /* checksum */
	u_short	part1;		/* depends on type and code */
	u_short	part2;
};
typedef struct icmph ICMPLAYER;

#define	INMREQ	17	/* netmask request */
#define	INMREP	18	/* netmask reply */

#ifdef __HIGHC__
_packed
#endif
struct icmp {
	DLAYER d;
	IPLAYER i;
	ICMPLAYER c;
	u_char	data[ICMPMAX];
};
typedef struct icmp ICMPKT;

/**************************************************************************/
/*  TCP protocol
*      define both headers required and create a data type for a typical
*      outgoing TCP packet (with IP header)
*   
*  Note:  So far, there is no way to handle IP options fields
*    which are associated with a TCP packet.  They are mutually exclusive
*    for both receiving and sending.  Support may be added later.
*
*   The tcph and iph structures can be included in many different types of
*   arbitrary data structures and will be the basis for generic send and
*   receive subroutines later.  For now, the packet structures are optimized 
*   for packets with no options fields.  (seems to be almost all of them from
*   what I've observed.
*/

#ifdef __HIGHC__
_packed
#endif
struct tcph {
	u_short	source;		/* TCP port numbers, all byte-swapped */
	u_short	dest;
	u_long	seq;		/* sequence, ACK numbers */
	u_long	ack;
	u_char	hlen;		/* length of TCP header in 4 byte words */
	u_char	flags;		/* flag fields */
	u_short	window;		/* advertised window, byte-swapped */
	u_short	check;		/* TCP checksum of whole packet */
	u_short	urgent;		/* urgent pointer, when flag is set */
};
typedef struct tcph TCPLAYER;

/*
*  used for computing checksums in TCP
*/
#ifdef __HIGHC__
_packed
#endif
struct pseudotcp {
	u_long	source;		/* IP #'s for source,dest */
	u_long	dest;
	u_char	z;		/* zero and protocol number */
	u_char	proto;
	u_short	tcplen;		/* byte-swapped length field */
};

#ifdef __HIGHC__
_packed
#endif
struct tcp {
	DLAYER d;
	IPLAYER i;
	TCPLAYER t;
	union {
		u_char	options[40];	/* not very likely, except on SYN */
		u_char	data[TMAXSIZE];	/* largest TCP data we will use */
	} x;
};
typedef struct tcp TCPKT;

/* 
*  flag field definitions, first two bits undefined
*/
#define TURG	0x20
#define TACK	0x10
#define TPUSH	0x08
#define TRESET	0x04
#define TSYN	0x02
#define TFIN	0x01

/*************************************************************************/
/*  UDP
*   User Datagram Protocol
*   Each packet is an independent datagram, no sequencing information
*
*   UDP uses the identical checksum to TCP
*/
#ifdef __HIGHC__
_packed
#endif
struct udph {
	u_short	source;		/* port numbers, all byte-swapped */
	u_short	dest;
	u_short	length;		/* length of packet, including hdr */
	u_short	check;		/* TCP checksum of whole packet */
};
typedef struct udph UDPLAYER;

#ifdef __HIGHC__
_packed
#endif
struct udp {
	DLAYER d;
	IPLAYER i;
	UDPLAYER u;
	u_char	data[UMAXLEN];      /* largest UDP data we will use */
};
typedef struct udp UDPKT;

struct bpport {
	u_short	listen;		/* what port should this one listen to? */
	u_short	newdata;	/* have we read this packet yet? */
};

struct port {
	u_char	fd;
	u_char	flag;
	u_short	inport;		/* my port number in network order */
	u_short	outport;	/* dest port number in network byte order */
	u_short	inbase;
	u_short	infree;
	IPKT	outpkt;		/* pre-initialized as much as possible */
	u_char	stuff[2];	/* actually a lot more stuff here */
};

struct udpport {
	u_char	fd;
	u_char	flag;
	u_short	inport;		/* my port number in network order */
	u_short	outport;	/* dest port number in network byte order */
	u_short	inbase;
	u_short	infree;
	UDPKT	outpkt;		/* pre-initialized as much as possible */
	u_char	datain[WINDOWSIZE];
};

struct tcpport {
	u_char	fd;
	u_char	flag;
	u_short	inport;		/* my port number in network order */
	u_short	outport;	/* dest port number in network byte order */
	u_short	inbase;
	u_short	infree;
	TCPKT	outpkt;		/* pre-initialized as much as possible */
	u_long	lasttime;	/* time of last transmission */
	u_long	inseq;
	u_short	wait_tx;	/* number of sleeps to wait before xmit */
#ifdef notdef
	u_long	inack;		/* don't need */
#endif
	u_long	outseq;
	u_long	outack;
	u_short	outbase;	/* don't need */
	u_short	outfree;
	u_char	datain[WINDOWSIZE];
	u_char	dataout[WINDOWSIZE];
	u_char	state;		/* connection state */
	u_short	outsize;	/* peer's MSS */
	u_short	outwin;
	u_short	credit;		/* choked-down window for fast hosts */
	u_short	rto;		/* retrans timeout */
	u_short resends;	/* number of sends without ack */
};

#ifdef __HIGHC__
_packed
#endif
struct packet_info {
	u_short	packet_version;
	u_short	packet_class;
	u_short	packet_type;
	u_short	packet_ifnumber;
#if defined(__HIGHC__) || defined(__WATCOMC__)
	u_long	packet_name;
#else
	char	_far *packet_name;
#endif
	u_short	packet_extended;
};

#ifdef __WATCOMC__
#pragma pack;
#endif

union rawether {
	struct ip	ip;
	struct udp	udp;
	struct tcp	tcp;
	struct icmp	icmp;
	struct arp	arp;
	u_char data[MTU + sizeof(struct ether)];
};
#define rawip(x) ((x)->ip)
#define rawudp(x) ((x)->udp)
#define rawtcp(x) ((x)->tcp)
#define rawicmp(x) ((x)->icmp)
#define rawdata(x) ((x)->data)
