/* 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) 1991,1993, Trustees of Columbia University in the
 *  City of New York.  Permission is granted to any individual or
 *  institution to use, copy, or redistribute this software as long as
 *  it is not sold for profit and this copyright notice is retained.
 *
 * 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:
 * 18 June 1993
 */
 
/* Kernel version (major major minor minor) */
#define WTCP_VER 0x0311
#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 definition of Far as _far */
#define FAR _far

/*
#define DEBUG
*/

#ifndef NULL
#define NULL 0
#endif

#define TRUE        1
#define FALSE       0

#ifdef KERMIT
#define ETH_MSS 1046 			/* MSS for Ethernet >= 536 */
#define TCP_SBUFSIZE (2*ETH_MSS)	/* max bytes to buffer in a tcp socket */
#define TCP_RBUFSIZE 4096
#define UDP_BUFSIZE ETH_MSS		/* max bytes to buffer in a udp socket */
#define MAX_GATE_DATA 2
#define MAX_NAMESERVERS 3
#define MAX_COOKIES 0
#else
#define ETH_MSS 1500			/* MSS for Ethernet */
#define tcp_MaxBufSize 2048	/* maximum bytes to buffer in a socket */
#define udp_MaxBufSize 2048	/* max bytes to buffer in a udp socket */
#define MAX_GATE_DATA 12
#define MAX_NAMESERVERS 10
#define MAX_COOKIES 10
#endif

#define MAX_STRING 50	
#define TICKS_SEC 18
#define PD_ETHER 1
#define PD_SLIP  6

/* 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 UDP_PROTO  0x11
#define TCP_PROTO  0x06
#define ICMP_PROTO 0x01

#define TCP_MODE_BINARY  0       /* default mode */
#define TCP_MODE_ASCII   1
#define TCP_MODE_NAGLE   0       /* Nagle algorithm */
#define TCP_MODE_NONAGLE 4
#define UDP_MODE_CHK     0       /* default to having checksums */
#define UDP_MODE_NOCHK   2       /* turn off 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;


#define in_GetVersion(ip) ((ip)->hdrlen_ver >> 4)
#define in_GetHdrlen(ip)  ((ip)->hdrlen_ver & 0xf)  /* 32 bit word size */
#define in_GetHdrlenBytes(ip)  (in_GetHdrlen(ip) << 2) /* 8 bit byte size */
#define in_GetTos(ip)      ((ip)->tos)
#define in_GetTTL(ip)      ((ip)->ttl)
#define in_GetProtocol(ip) ((ip)->proto)

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

#define UDP_LENGTH (sizeof(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;


#define tcp_FlagFIN     0x0001
#define tcp_FlagSYN     0x0002
#define tcp_FlagRST     0x0004
#define tcp_FlagPUSH    0x0008
#define tcp_FlagACK     0x0010
#define tcp_FlagURG     0x0020
#define tcp_FlagDO      0xF000
#define tcp_GetDataOffset(tp) (ntohs((tp)->flags) >> 12)

/*
 * TCP states, from tcp manual.
 * Note: close-wait state is bypassed by automatically closing a connection
 *       when a FIN is received.  This is easy to undo.
 */
#define tcp_StateLISTEN  0      /* listening for connection */
#define tcp_StateSYNSENT 1      /* syn sent, active open */
#define tcp_StateSYNREC  2      /* syn received, synack+syn sent. */
#define tcp_StateESTAB   3      /* established */
#define tcp_StateFINWT1  4      /* sent FIN */
#define tcp_StateFINWT2  5      /* sent FIN, received FINACK */
#define tcp_StateCLOSWT  6      /* received FIN waiting for close */
#define tcp_StateCLOSING 7      /* sent FIN, recvd FIN (waiting for FINACK) */
#define tcp_StateLASTACK 8      /* fin received, finack+fin sent */
#define tcp_StateTIMEWT  9      /* dally after sending final FINACK */
#define tcp_StateCLOSEMSL 10
#define tcp_StateCLOSED  11     /* finack received */

#define SOCKET_OPEN	1
#define SOCKET_CLOSED	0

/*
 * 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	   *err_msg;		/* null when all is ok */
    word	    soc_mode;	        /* a logical OR of bits */
    longword	    usertimer;		/* ip_timer_set, ip_timer_timeout */
    eth_address     hisethaddr;		/* peer's Ethernet address */
    longword        hisaddr;		/* peer's Internet address */
    word	    hisport;		/* peer's UDP port */
    word	    myport;
    int             rdatalen;           /* must be signed */
    byte	    FAR * rdata;	/* Far ptr to data buffer */
} udp_Socket;

/*
 * 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 	   *err_msg;
    word	    soc_mode;	    /* a logical OR of bits */
    longword	    usertimer;	    /* ip_timer_set, ip_timer_timeout */
    eth_address     hisethaddr;     /* Ethernet address of peer */
    longword        hisaddr;        /* Internet address of peer */
    word            hisport;	    /* tcp ports for this connection */
    word	    myport;
    int             rdatalen;       /* signed, bytes in receive buffer */
    byte	    FAR * rdata;    /* Far ptr to receive data buffer */
    				/* above must also match udp_socket */
    int		    rmaxdatalen;    /* normally TCP_MAXRBUFSIZE */
    byte            FAR * sdata;    /* Far ptr to send data buffer */
    int 	    sdatalen;	    /* signed number of bytes of data to send*/
    word	    state;          /* connection state */
    longword        acknum;
    longword	    seqnum; 	    /* data ack'd and sequence num */
    long            timeout;        /* timeout, in milliseconds */
    word            flags;          /* tcp flags word for last packet sent */
    word            mss;	    /* active Max Segment Size */
    word	    window;	    /* other guy's window */
    byte	    cwindow;	    /* Van Jacobson's algorithm */
    byte	    wwindow;
    word	    vj_sa;	    /* VJ's alg, standard average */
    word	    vj_sd;	    /* VJ's alg, standard deviation */
    longword	    vj_last;	    /* last transmit time */
    word	    rto;
    byte	    karn_count;	    /* count of packets */
    byte            rptxmit;	    /* flag, to rpt transmission on timeout */

    /* retransmission timeout proceedure, these are in PC clock ticks */
    longword        rtt_lasttran;       /* last transmission time */
    longword        rtt_smooth;         /* smoothed round trip time */
    longword        rtt_delay;          /* delay for next transmission */
    longword        rtt_time;           /* time of next transmission */
} tcp_Socket;

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

/* similar to UNIX */
typedef struct sockaddr {
    word        s_type;
    word        s_port;
    longword    s_ip;
    byte        s_spares[6];    /* unused in TCP realm */
};

/*
 * 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_tick()
 *	- do tick and jump on abort
 * 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_tick(s, statusptr) \
    if (!tcp_tick(s)) { *statusptr = 1 ; goto sock_err; }
#define sock_wait_closed(s, seconds, fn, statusptr)\
    if (ip_delay2(s, seconds, fn, statusptr)) goto sock_err;

longword resolve();
int	add_server(int *, int, longword *, longword);
longword inet_addr(byte *);
byte *	sockerr(tcp_Socket *);
byte *	sockstate(tcp_Socket *);
byte *	getdomainname(byte *, int);
byte *	setdomainname(byte *);

sock_init(void);
/* 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);
int	sock_fastwrite(void *, byte FAR *, int);
int	sock_flush(void *);
int	sock_flushnext(void *);
int	sock_puts(void *, byte *);
word 	sock_gets(void *, byte *, int);
int	sock_putc(void *, byte);
int	sock_getc(void *);
word	sock_dataready(void *);
int	sock_established(void *);
int	sock_close(void *);
void	sock_abort(void *);
int	sock_mode(void *, word);		/* see TCP_MODE_... */

/*
 * 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 *);

/* less general functions */
longword resolve(byte *);
int	isaddr(byte *);

/* timers */
void	ip_timer_init(void *, int);
int	ip_timer_expired(void *);
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 *);
/* tcp_set_debug_state - set 1 or reset 0, development tool */
void	tcp_set_debug_state(word);

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

int	ping(longword, longword);
longword chk_ping(longword, longword);

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	dobootp(void);
void	arp_add_gateway(byte *, longword);
int	do_rarp(void);
int	do_ping(byte *, longword);

/* bsd-similar stuff */

int	sock_rbsize(void *);
int	sock_rbused(void *);
int	sock_rbleft(void *);
int	sock_tbsize(void *);
int	sock_tbused(void *);
int	sock_tbleft(void *);
getpeername(tcp_Socket *, void *, int *);
getsockname(tcp_Socket *, void *, int *);

chk_socket(tcp_Socket *);
byte *	psocket(tcp_Socket *);
byte *	sockerr(tcp_Socket *);
byte *	sockstate(tcp_Socket *);
byte *	getdomainname(byte *, int);
byte *	setdomainname(byte *);
byte *	gethostname(byte *, int);
byte *	sethostname(byte *);
longword gethostid();
longword sethostid(longword);
word 	ntohs(word);
word 	htons(word);
longword ntohl(longword);
longword htonl(longword);
longword realclock(void);
longword inet_addr(byte *);
void *	movmem(void *, void *, int);

void	arp_register(longword, longword);
int	arp_resolve(longword, void *);
void	arp_init(void);
longword arp_rpt_gateway(int);
int	pkt_rarp_init(void);

extern	survivebootp;
extern	word pktdevclass;
extern	word mss;
extern	word bootptimeout;
extern	longword bootphost;
extern	word bootpon;
extern	longword my_ip_addr;
extern	eth_address eth_addr;
extern	eth_address eth_brdcast;
extern	longword sin_mask;
extern	word sock_delay;
extern	int last_nameserver;
extern	longword def_nameservers[];
extern	word debug_on;
