/* File MSNTCP.H
 * Main include file for TCP/IP, as revised and modified for MS-DOS Kermit.
 *
 * Copyright (C) 1991, University of Waterloo.
 *	Copyright (C) 1982, 1999, Trustees of Columbia University in the 
 *	City of New York.
 * Effective 1 July 2011, MS-DOS Kermit should be considered Open
 * Source software under the Revised 3-Clause BSD License, even
 * though the software itself and associated files may carry the old
 * copyright and licensing information.
 * http://www.columbia.edu/kermit/mskermit.html
 *
 * Original version created by Erick Engelke of the University of
 *  Waterloo, Waterloo, Ontario, Canada.
 *       Erick Engelke                Erick@development.watstar.uwaterloo.ca
 *       Faculty of Engineering
 *       University of Waterloo       (519) 885-1211 Ext. 2965
 *       200 University Ave.,
 *       Waterloo, Ont., Canada
 *       N2L 3G1
 * Adapted and modified for MS-DOS Kermit by Joe R. Doupnik, 
 *  Utah State University, jrd@cc.usu.edu, jrd@usu.Bitnet,
 *  and by Frank da Cruz, Columbia University, fdc@watsun.cc.columbia.edu.
 *
 * Name resolution services were adapted from sources made available by
 * the National Centre for Supercomputer Applications (NCSA) and Clarkson
 * University.
 *
 * The C code is designed for the small memory model of Microsoft C versions
 * 5.1 and later, with structures packed on one byte boundaries. No other
 * options are expected.
 *
 * Last edit:
 * 12 Jan 1995 version 3.14
 */
 
#define KERMIT

/*
 * Typedefs and constants
 */

#ifndef byte
typedef unsigned char byte;
#endif  /* byte */
#ifndef word
typedef unsigned int word;
#endif  /* word */
#ifndef longword
typedef unsigned long longword;
#endif /* longword */

typedef int (*procref)(void *, void *, int);
typedef byte eth_address[6];


/* MSC v6.0 & v7.0 &v8.0 definition of Far as _far */
#define FAR _far

/*
#define DEBUG
*/

#ifndef NULL
#define NULL 0
#endif

#define TRUE        1
#define FALSE       0

#define ETH_MSS 1460 			/* MSS for Ethernet >= 536 */
#define MAX_GATE_DATA 3
#define MAX_NAMESERVERS 3
#define MAX_COOKIES 0
#define MAX_STRING 64	
#define TICKS_SEC 18
#define PD_ETHER 1
#define PD_SLIP  6

#define	BOOT_FIXED	0	/* methods of obtaining our IP address */
#define	BOOT_BOOTP	1
#define	BOOT_RARP	2
#define BOOT_DHCP	3

/* Ethernet frame TYPE's in network order, reverse for host order */
#define TYPE_IP		0x0008
#define TYPE_ARP	0x0608
#define TYPE_RARP	0x3580

/* Ethernet protocol identifications */
#define ICMP_PROTO 0x01
#define TCP_PROTO  0x06
#define UDP_PROTO  0x11

				/* sock_mode byte bit-field */
#define TCP_MODE_NAGLE	0x01	/* TCP Nagle algorithm */
#define TCP_MODE_PASSIVE 0x02	/* TCP, opened in passive mode */
#define UDP_MODE_CHKSUM	0x08	/* UDP checksums */

/* The Ethernet header */
typedef struct {
    eth_address     destination;
    eth_address     source;
    word            type;
} eth_Header;

/* The Internet Header: */
typedef struct {
    byte	    hdrlen_ver;		/* both in one byte */
    byte	    tos;
    word            length;
    word            identification;
    word            frag;
    byte	    ttl;
    byte	    proto;
    word            checksum;
    longword        source;
    longword        destination;
} in_Header;

typedef struct {
    word	    srcPort;
    word	    dstPort;
    word	    length;
    word	    checksum;
} udp_Header;

typedef struct {
    word            srcPort;
    word            dstPort;
    longword        seqnum;
    longword        acknum;
    word            flags;
    word            window;
    word            checksum;
    word            urgentPointer;
} tcp_Header;

/* The TCP/UDP Pseudo Header */
typedef struct {
    longword    src;
    longword    dst;
    byte        mbz;
    byte        protocol;
    word        length;
    word        checksum;
} tcp_PseudoHeader;

/* TCP states */
#define tcp_StateLISTEN  0x0000      /* listening for connection */
#define tcp_StateSYNSENT 0x0001      /* syn sent, active open */
#define tcp_StateSYNREC  0x0002      /* syn received, synack+syn sent. */
#define tcp_StateESTAB   0x0004      /* established */
#define tcp_StateFINWT1  0x0008      /* sent FIN */
#define tcp_StateFINWT2  0x0010      /* sent FIN, received FINACK */
#define tcp_StateCLOSWT  0x0020      /* received FIN waiting for close */
#define tcp_StateCLOSING 0x0040      /* sent FIN, recvd FIN (waiting for FINACK) */
#define tcp_StateLASTACK 0x0080      /* fin received, finack+fin sent */
#define tcp_StateTIMEWT  0x0100      /* dally after sending final FINACK */
#define tcp_StateCLOSEMSL 0x0200
#define tcp_StateCLOSED  0x0400       /* finack received */

#define SOCKET_OPEN	1		/* if socket structure is active */
#define SOCKET_CLOSED	0
#define TIMED_OUT	1		/* if a timer has expired */

#define DEBUG_STATUS	1		/* Set TCP DEBUG for general info */
#define DEBUG_TIMING	2		/* for round trip timing */
/*
 * UDP socket definition, must match start of tcp_socket.
 */
typedef struct udp_socket {
    struct udp_socket *next;
    word	    ip_type;		/* always set to UDP_PROTO */
    byte	    sisopen;		/* non-zero if socket is open */
    byte	    sock_mode;	        /* a logical OR of bits */
    eth_address     hisethaddr;		/* peer's Ethernet address */
    longword        hisaddr;		/* peer's Internet address */
    word	    hisport;		/* peer's UDP port */
    word	    myport;		/* our UDP port */
    int             rdatalen;      	/* signed, bytes in receive buffer */
    byte	    FAR * rdata;	/* Far ptr to data buffer */
} udp_Socket;

/* TCP segment send queue status per segment */
typedef struct sendqstat {
	longword	time_sent;	/* Bios ticks when datagram was sent*/
	longword	timeout;	/* Bios ticks when dgram times out */
	longword	next_seq;	/* seq number of start of next dgram */
};
#define NSENDQ	20			/* number of timed segments */
#define DELAY_ACKS			/* define to use delayed ACKs */

/*
 * TCP Socket definition
 */

typedef struct tcp_socket {
    struct tcp_socket *next;
    word	    ip_type;	    /* always set to TCP_PROTO */
    byte	    sisopen;	    /* non-zero if socket is open */
    byte	    sock_mode;	    /* a logical OR of bits */
    eth_address     hisethaddr;     /* Ethernet address of peer */
    longword        hisaddr;        /* Internet address of peer */
    word            hisport;	    /* TCP port at peer */
    word	    myport;	    /* our TCP port */
    int             rdatalen;       /* signed, bytes in receive buffer */
    byte	    FAR * rdata;    /* Far ptr to receive data buffer */
    				/* above must also match udp_socket */
    byte            FAR * sdata;    /* Far ptr to send data buffer */
    int 	    sdatalen;	    /* signed number of bytes of data to send*/
    int		    sdatahwater;    /* high water mark in buffer */
    word	    state;          /* connection state */
    longword        acknum;	    /* last received byte + 1 */
    longword	    seqnum; 	    /* last sent byte + 1 */
    word            flags;          /* tcp flags word for last packet sent */
    word            mss;	    /* active Max Segment Size */
    word	    window;	    /* remote host's window size */
    word	    old_window;	    /* remote host's previous window size */
    word	    cwindow;	    /* Van Jacobson's algorithm, congest win*/
    word	    ssthresh;	    /* VJ congestion threshold */
    byte	    loss_count;	    /* times in row have lost pkt */
    byte	    last_read;	    /* last byte read by tcp_read, for CR NUL*/
    word	    vj_sa;	    /* VJ's algorithm, standard average */
    word	    vj_sd;	    /* VJ's algorithm, standard deviation */
    word	    rto;	    /* round trip timeout */
    longword        timeout;        /* TCP state timeout, in Bios tics */
    longword	    notimeseq;	    /* seq number below which repeats sent */
    longword	    idle;	    /* timeout for last xmission + rto */
    longword	    winprobe;	    /* timeout on window probes */
    longword	    keepalive;	    /* timeout on passive open'd keepalives */
#ifdef DELAY_ACKS
    longword	    delayed_ack;    /* timeout on pending delayed ACK */
#endif
    word	    probe_wait;	    /* ticks between window probes */
    word	    window_last_sent; /* our window, last sent value */
    byte	    send_kind;	    /* flag, nosend, sendnow */
    int		    sendqnum;	    /* number of active entries in sendq */
    struct sendqstat sendq[NSENDQ]; /* send queue stats per IP datagram */
} tcp_Socket;


/* sock_type used for socket io */
typedef union {
    udp_Socket udp;
    tcp_Socket tcp;
} sock_type;

/*
 * socket macros
 */

/*
 * sock_wait_established()
 *	- waits then aborts if timeout on s connection
 * sock_wait_input()
 *	- waits for received input on s
 *	- may not be valid input for sock_Gets... check returned length
 * sock_wait_closed();
 *	- discards all received data
 *
 * jump to sock_err with contents of *statusptr set to
 *	 1 on closed
 *	-1 on timeout
 */
#define sock_wait_established(s, seconds, fn, statusptr) \
    if (ip_delay0(s, seconds, fn, statusptr)) goto sock_err;
#define sock_wait_input(s, seconds, fn , statusptr) \
    if (ip_delay1(s, seconds, fn, statusptr)) goto sock_err;
#define sock_wait_closed(s, seconds, fn, statusptr)\
    if (ip_delay2(s, seconds, fn, statusptr)) goto sock_err;

/* s is a pointer to a udp or tcp socket */
int	sock_read(void *, byte FAR *, int);
int	sock_fastread(void *, byte FAR *, int);
int	sock_write(void *, byte FAR *, int);
word	sock_dataready(void *);
int	sock_established(void *);
int	sock_close(void *);
void	sock_abort(void *);
int	sock_setmode(void *, word, word);

/*
 * TCP or UDP specific material, must be used for open's and listens, but
 * sock calls are used for everything else.
 */
int	udp_open(void *, word, longword, word);
int	tcp_open(void *, word, longword, word);
int	tcp_listen(void *, word, longword, word, word);
int	tcp_established(void *);

/* timers */
int	ip_delay0(void *, int, procref, int *);
int	ip_delay1(void *, int, procref, int *);
int	ip_delay2(void *, int, procref, int *);

/* tcp_init/tcp_shutdown, init/kill all tcp and lower services.
   Call if sock_init is not used, else not recommended.
*/
int	tcp_init(void);
void	tcp_shutdown(void);
int	tcp_abort(tcp_Socket *);
/* tcp_tick - called periodically by user application in sock_wait.
  returns 0 when our socket closes
*/
int	tcp_tick(void *);

int	tcp_cancel(void *);
int	udp_cancel(void *);

int	eth_init();
byte *	eth_formatpacket(void *, word);
int	eth_send(word);
void	eth_free(void *);
byte *	eth_arrived(word *);
void	eth_release(void);
void *	eth_hardware(void *);
int	do_bootp(void);
int	do_rarp(void);
int	do_ping(byte *, longword);
longword resolve(byte *);
int	add_server(int *, int, longword *, longword);
void	arp_init(void);
int	arp_resolve(longword, void *);
void	arp_register(longword, longword);
void	arp_add_gateway(byte *, longword);
longword arp_rpt_gateway(int);
int	pkt_rarp_init(void);

word 	ntohs(word);
word 	htons(word);
longword ntohl(longword);
longword htonl(longword);
void *	movmem(void *, void *, int);

extern	word pktdevclass;
extern	word mss;
extern	longword bootphost;
extern	longword my_ip_addr;
extern	eth_address eth_addr;
extern	eth_address eth_brdcast;
extern	longword sin_mask;
extern	int last_nameserver;
extern	word arp_last_gateway;
extern	longword def_nameservers[];
extern	word debug_on;
