/****************************************************************************
*
* (C) 2000 by BECK IPC GmbH
*
*  BECK IPC GmbH
*  Garbenheimerstr. 38
*  D-35578 Wetzlar
*
*  Phone : (49)-6441-905-240
*  Fax   : (49)-6441-905-245
*
* ---------------------------------------------------------------------------
* Module         : IPC@Chip SC12 API :tcpip.c
*
* Function       : TCPIP API socket functions
*                  Use memory model large!!!!
*
* Author        : bartat
* Date          : 22.01.00
* ---------------------------------------------------------------------------
$Log:
 25   IPC@CHIP  1.24        23.05.2002 12:04:08  Markus Bartat   Modified htons
      function: Implemented as a simple byte exchange,
      not necessayr to call int86x for this
 24   IPC@CHIP  1.23        07.05.2002 14:50:50  Markus Bartat   added
      C-function for TCPAPI call 0x22 Get_tcp-socket_state
 23   IPC@CHIP  1.22        01.03.2002 18:49:25  Markus Bartat   added functions
      for API calls 0x45,0x44,0x55
 22   IPC@CHIP  1.21        26.02.2002 18:45:51  Christoph Stoidner Add
      PPPSetPPPOption
 21   IPC@CHIP  1.20        30.01.2002 12:52:06  Markus Bartat   added extendend
      dhcp_stat function 0x73
 20   IPC@CHIP  1.19        23.01.2002 16:40:26  Christoph Stoidner delete
      unused timeout variable
 19   IPC@CHIP  1.18        14.01.2002 13:33:36  Christoph Stoidner add new
      functions (Set/get Idle timeout: 0x79)
 18   IPC@CHIP  1.17        14.01.2002 13:19:05  Christoph Stoidner add new
      functions
 17   IPC@CHIP  1.16        14.12.2001 11:55:07  Markus Bartat   Added C
      functions and define for TCPIP API calls 0x90-0x92
 16   IPC@CHIP  1.15        17.09.2001 12:40:22  Markus Bartat   added tcpip api
      call 0x67
 15   IPC@CHIP  1.14        23.07.2001 10:18:10  Christoph Stoidner Bugfix in
      CloseSocket func.
 14   IPC@CHIP  1.13        21.06.2001 13:53:31  Markus Bartat   added tcpip api
      call 0x19
 13   IPC@CHIP  1.12        19.06.2001 13:35:08  Markus Bartat   start: Added
      comments to the c functions
 12   IPC@CHIP  1.11        01.06.2001 12:20:28  Markus Bartat   added new
      functions
 11   IPC@CHIP  1.10        31.05.2001 16:19:03  Christoph Stoidner
 10   IPC@CHIP  1.9         31.05.2001 14:27:46  Christoph Stoidner
 9    IPC@CHIP  1.8         31.05.2001 09:18:00  Markus Bartat   bugfix snmp_get
 8    IPC@CHIP  1.7         29.05.2001 16:04:20  Markus Bartat   added aPI call
      0x60 Get access to internal snmp variables
 7    IPC@CHIP  1.6         19.04.2001 10:44:25  Markus Bartat   bugfix at
      tcp_connect: parameter error was overwritten by
      closesocket calls
 6    IPC@CHIP  1.5         14.03.2001 16:56:21  Christoph Stoidner
 5    IPC@CHIP  1.4         14.03.2001 16:55:09  Christoph Stoidner convert
      datatypes to prevent compiler warnings
 4    IPC@CHIP  1.3         14.03.2001 16:52:42  Christoph Stoidner
 3    IPC@CHIP  1.2         08.03.2001 15:30:17  Christoph Stoidner
 2    IPC@CHIP  1.1         08.03.2001 11:33:19  Ernest Schlösser Added a
      tcp_connect function to create a socket and connect to a server
 1    IPC@CHIP  1.0         14.02.2001 16:09:59  Christoph Stoidner
$

* History       :
*
*  Vx.yy                   Author  Changes
*
*             22.01.00      mb    Create
*             28.01.00      mb     add calls setlinger and set reuse
*             06.05.00      mb     add ppp client API calls
*             26.06.00      mb     add ppp server API calls
*             14.07.00      mb     add reconfig, dhcp  and ip setting API calls
              18.07.00      mb     add TCPIP statistics
              24.08.00      mb     add PPP client API calls
              06.09.00      mb     add set and getsockopt calls
              15.09.00      mb     add ping api calls
              07.11.00      mb     add memory information call
              08.12.00      mb     add routing calls
              22.12.00      mb     add blocking mode call for sockets
              30.05.01      mb    add API_SNMP_GET function
              01.06.01      mb    add telnet and ftp login functions
              20.06.01      mb     add register callback function
              17.09.01      mb     add get telnet state function
              30.01.02      mb     add dhcp_stat_ext function (requires BIOS 1.03B or higher)
              25.02.02      mb/cs  added new function PPP_GET_DNSIP 0x44 and pppsetoptions 0x45,0x55
              07.05.02      mb     added TCP API function 0x22, get state of tcp socket
*****************************************************************************/
#include <DOS.H>
#include <STDLIB.H>
#include "CLIB/TCPIPAPI.H"
#include "CLIB/TCPIP.H"



/*****************************************************************************
*
*	open a tcp connection
*
*	DestIPStr: destionation IP address format xxx.xxx.xxx.xxx
*	ClientPort: local port (0=random port)
*	HostPort: remote port
*	error: TCP/IP error
*
*
*	return: socket descriptor (-1 = error)
*/

int tcp_connect(char *DestIPStr, unsigned int ClientPort, unsigned int HostPort, int *error)
{
	struct sockaddr_in addr;
	unsigned long DestIPAddr;
	int sd; // socket descriptor
        int dummyerror;

	// open socket
	sd = opensocket(SOCK_STREAM,error);
	if (sd==-1 || *error!=0)
	{
		return -1;
	}

	addr.sin_family = PF_INET;
	addr.sin_port = htons(ClientPort);	// convert byte order
	addr.sin_addr.s_addr =  0;
	if (ClientPort!=0)
	{	// force client port
		bind(sd, (struct sockaddr *)&addr, error);
		if (*error!=0)
		{
                   closesocket(sd, &dummyerror);
			return -1;
		}
	}
	addr.sin_port = htons(HostPort);	// convert byte order

	// convert server IP address string to binary
	*error = inet_addr(DestIPStr,&DestIPAddr);
	if (*error!=0)
	{
             closesocket(sd, &dummyerror);
		return -1;
	}
	addr.sin_addr.s_addr = DestIPAddr;

	// establish a connection to the FTP server
	connect(sd, (struct sockaddr *) &addr, error);
	if (*error!=0)
	{
            closesocket(sd, &dummyerror);
		return -1;
	};

	*error = 0;
	return sd;

}	// tcp_connect()



/*************************************************************************/
//accept
/*************************************************************************/
int accept(int sd, struct sockaddr * addressPtr, int *error)
{

	  union  REGS  inregs;
	  union  REGS  outregs;

	  *error = 0;

	  inregs.h.ah     = API_ACCEPT;
	  inregs.x.bx     = sd;

	  inregs.x.dx     = FP_SEG(addressPtr);
	  inregs.x.si     = FP_OFF(addressPtr);

	  int86(TCPIPVECT,&inregs,&outregs);

	  if(outregs.x.dx == (unsigned int)API_ERROR)
	  {
		  *error =  outregs.x.ax;
		  return API_ERROR;
	  }
	  //return socketdescriptor
	  *error = 0;
	  return outregs.x.ax;
}

/*************************************************************************/
//sleep
/*************************************************************************/
void api_sleep(unsigned int howlong)
{
	union  REGS  inregs;
	union  REGS  outregs;

	inregs.h.ah     = API_SLEEP;
	inregs.x.bx     = howlong;
	int86(TCPIPVECT,&inregs,&outregs);
}
/*************************************************************************/
//bind
/*************************************************************************/
int bind(int sd, struct sockaddr * addressPtr, int *error)
{

	union  REGS  inregs;
	union  REGS  outregs;

	*error = 0;
	inregs.h.ah     = API_BIND;
	inregs.x.bx     = sd;
	inregs.x.dx     = FP_SEG(addressPtr);
	inregs.x.si     = FP_OFF(addressPtr);
	int86(TCPIPVECT,&inregs,&outregs);

	if(outregs.x.dx == (unsigned int)API_ERROR)
	{
		 *error = outregs.x.ax;
	}
	return outregs.x.dx;
}
/*************************************************************************/
//connect
/*************************************************************************/
int connect(int sd, struct sockaddr * addressPtr, int *error)
{

	union  REGS  inregs;
	union  REGS  outregs;


	*error = 0;

	inregs.h.ah     = API_CONNECT;
	inregs.x.bx     = sd;
	inregs.x.dx     = FP_SEG(addressPtr);
	inregs.x.si     = FP_OFF(addressPtr);
	int86(TCPIPVECT,&inregs,&outregs);

	if(outregs.x.dx == (unsigned int)API_ERROR)
	{
		 *error = outregs.x.ax;

	}
	return outregs.x.dx;
}


/*************************************************************************/
//closesocket
/*************************************************************************/
int closesocket(int sd, int *error)
{

	union  REGS  inregs;
	union  REGS  outregs;

	inregs.h.ah = API_CLOSESOCKET;
	inregs.x.bx = sd;
	int86(TCPIPVECT,&inregs,&outregs);

	if(outregs.x.dx==(unsigned int)API_ERROR)
	{
	  *error = outregs.x.ax;
          return API_ERROR;
	}
	*error = 0;
	return outregs.x.dx;
}

/*************************************************************************/
//get waiting bytes
/*************************************************************************/
int GetWaitingBytes(int sd, int *error)
{
	union  REGS  inregs;
	union  REGS  outregs;

	inregs.h.ah      = API_GETRCV_BYTES;
	inregs.x.bx      = sd;
	int86(TCPIPVECT,&inregs,&outregs);

	if(outregs.x.dx==(unsigned int)API_ERROR)
	{
	  *error = outregs.x.ax;
	  return API_ERROR;
	}
	*error = 0;
	return outregs.x.ax;
}
/*************************************************************************/
//htons
/*************************************************************************/
unsigned int htons(unsigned int value)
{

    asm
    {
      mov ax,value
      ror ax, 8
    }
    return  (unsigned short)_AX;
}

/*************************************************************************/
//listen
/*************************************************************************/
int listen(int sd,int backlog, int *error)
{
  union  REGS  inregs;
  union  REGS  outregs;

  inregs.h.ah      = API_LISTEN;
  inregs.x.bx      = sd;
  inregs.x.cx      = backlog;

  int86(TCPIPVECT,&inregs,&outregs);

  if(outregs.x.dx == (unsigned int)API_ERROR)
  {
	  *error = outregs.x.ax;
	  return API_ERROR;
  }
  *error = 0;
  return 0;
}
/*************************************************************************/
//inet_addr
/*************************************************************************/
int inet_addr(char * IPAddressStringPtr, unsigned long * IPAddress)
{
	union  REGS  inregs;
	union  REGS  outregs;
	struct SREGS sregs;

	inregs.h.ah      = API_INETADDR;
	inregs.x.bx      = FP_SEG(IPAddressStringPtr);
	inregs.x.si      = FP_OFF(IPAddressStringPtr);
	sregs.es         = FP_SEG(IPAddress);
	inregs.x.di      = FP_OFF(IPAddress);
	int86x(TCPIPVECT,&inregs,&outregs,&sregs);
	return outregs.x.dx;
}
/*************************************************************************/
//inet_to ascii
/*************************************************************************/
int InetToAscii(unsigned long * IPAddress, char * IPAddressStringPtr)
{

	  union  REGS  inregs;
	  union  REGS  outregs;
	  struct SREGS sregs;

	  inregs.h.ah     = API_INETTOASCII;
	  inregs.x.bx     = FP_SEG(IPAddress);
	  inregs.x.si     = FP_OFF(IPAddress);
	  sregs.es        = FP_SEG(IPAddressStringPtr);
	  inregs.x.di     = FP_OFF(IPAddressStringPtr);
	  int86x(TCPIPVECT,&inregs,&outregs,&sregs);
	  return 0;
}
/*************************************************************************/
//recvfrom
/*************************************************************************/
int recvfrom(int sd, char * bufptr, int bufLen, int flags,
				 unsigned long timeout,struct sockaddr * fromPtr, int *error)
{
	  int fromLen;
	  struct recv_params R;
	  union  REGS  inregs;
	  union  REGS  outregs;

	  //fill the struct recv_param R
	  fromLen          =   sizeof(struct sockaddr_in);
	  R.bufferPtr      =   bufptr;
	  R.bufferLength   =   bufLen;
	  R.flags          =   flags;
	  R.fromPtr        =   (struct sockaddr *)fromPtr;
	  R.fromlengthPtr  =   &fromLen;
	  R.timeout        =   timeout; /*milliseconds*/

	  //API
	  inregs.h.ah      = API_RECVFROM;
	  inregs.x.bx      = sd;
	  inregs.x.dx      = FP_SEG(&R);
	  inregs.x.si      = FP_OFF(&R);
	  int86(TCPIPVECT,&inregs,&outregs);

	  if(outregs.x.dx == (unsigned int)API_ERROR)
	  {
			*error = outregs.x.ax;
			return API_ERROR;
	  }

	  *error = 0;
	  return outregs.x.ax;
}
/*************************************************************************/
//recv
/*************************************************************************/
int recv(int sd, char * bufptr, int bufLen, int flags, unsigned long timeout,
			int *error)
{

	  struct recv_params R;
	  union  REGS  inregs;
	  union  REGS  outregs;

	  //fill the struct recv_param R
	  R.bufferPtr      =   bufptr;
	  R.bufferLength   =   bufLen;
	  R.flags          =   flags;
	  R.timeout        =   timeout;
	  R.fromPtr        =   NULL;
	  R.fromlengthPtr  =   NULL;

	  inregs.h.ah      = API_RECV;
	  inregs.x.bx      = sd;
	  inregs.x.dx      = FP_SEG(&R);
	  inregs.x.si      = FP_OFF(&R);
	  int86(TCPIPVECT,&inregs,&outregs);

	  if(outregs.x.dx == (unsigned int)API_ERROR)
	  {
		  *error = outregs.x.ax;
		  return API_ERROR;
	  }
	  *error = 0;
	  return outregs.x.ax;
}
/*************************************************************************/
//reset connection
/*************************************************************************/
int ResetConnection(int sd, int *error)
{
	  union  REGS  inregs;
	  union  REGS  outregs;

	  inregs.h.ah      = API_RESETCONNECTION;
	  inregs.x.bx      = sd;
	  int86(TCPIPVECT,&inregs,&outregs);
     if(outregs.x.dx == (unsigned int)API_ERROR)
	  {
		  *error = outregs.x.ax;
		  return API_ERROR;
	  }
	  *error = 0;
	  return 0;
}
/*************************************************************************/
//sendto
/*************************************************************************/
int sendto(int sd, char * bufptr, int bufLen, int flags,
			  const struct sockaddr * toPtr, int *error)
{

	  int toLen;
	  struct send_params S;
	  union  REGS  inregs;
	  union  REGS  outregs;

	  //Init the struct send_param S for API-Call
	  toLen            = sizeof(struct sockaddr_in);
	  S.bufferPtr      = bufptr;
	  S.bufferLength   = bufLen;
	  S.flags          = flags;
	  S.toPtr          = (struct sockaddr *)toPtr;
	  S.tolengthPtr    = &toLen;

	  inregs.h.ah      = API_SENDTO;
	  inregs.x.bx      = sd;
	  inregs.x.dx      = FP_SEG(&S);
	  inregs.x.si      = FP_OFF(&S);
	  int86(TCPIPVECT,&inregs,&outregs);

	  if(outregs.x.dx == (unsigned int)API_ERROR)
	  {
		 *error = outregs.x.ax;
		 return API_ERROR;
	  }
	  *error = 0;
	  return outregs.x.ax;
}

/*************************************************************************/
//send
/*************************************************************************/
int send(int sd, char * bufptr, int bufLen, int flags, int *error)
{
	  struct send_params S;
	  union  REGS  inregs;
	  union  REGS  outregs;

	  //fill the struct send_param S
	  S.bufferPtr      =   bufptr;
	  S.bufferLength   =   bufLen;
	  S.flags          =   flags;
	  S.toPtr          =   NULL;
	  S.tolengthPtr    =   NULL;

	  inregs.h.ah      = API_SEND;
	  inregs.x.bx      = sd;
	  inregs.x.dx      = FP_SEG(&S);
	  inregs.x.si      = FP_OFF(&S);
	  int86(TCPIPVECT,&inregs,&outregs);

	  if(outregs.x.dx == (unsigned int)API_ERROR)
	  {
		  *error = outregs.x.ax;
		  return API_ERROR;
	  }
	  *error = 0;
	  return outregs.x.ax;
}
/*************************************************************************/
//set linger time on close
/*************************************************************************/
int setlinger(int sd, int seconds, int *error)
{
	 union  REGS  inregs;
	 union  REGS  outregs;
	 inregs.h.ah = API_SETLINGER;
	 inregs.x.bx = sd;
	 inregs.x.cx = seconds;

	 int86(TCPIPVECT,&inregs,&outregs);

	 if(outregs.x.dx == (unsigned int)API_ERROR)
	 {
		  *error = outregs.x.ax;
		  return API_ERROR;
	 }
	 *error = 0;
	 return outregs.x.ax;
}
/*************************************************************************/
//set resuse option on a listening socket
/*************************************************************************/
int setreuse(int sd,int *error)
{
	 union  REGS  inregs;
	 union  REGS  outregs;
	 inregs.h.ah = API_SETREUSE;
	 inregs.x.bx = sd;

	 int86(TCPIPVECT,&inregs,&outregs);

	 if(outregs.x.dx == (unsigned int)API_ERROR)
	 {
		  *error = outregs.x.ax;
		  return API_ERROR;
	 }
	 *error = 0;
	 return outregs.x.ax;
}

/*********************************************************************************/
//@CHIP-RTOS with SNMP support only:
// search for tcp socket by lgiven local and return state,remote ip and local port
/*********************************************************************************/

unsigned char Get_TCP_Socket_State(unsigned int localPort, unsigned long * remoteIP, unsigned int * remotePort)
{

   union  REGS  inregs;
	union  REGS  outregs;
	struct SREGS sregs;

	inregs.h.ah      = API_GET_TCP_STATE;
   inregs.x.bx      = localPort;
	sregs.es         = FP_SEG(remoteIP);
	inregs.x.di      = FP_OFF(remoteIP);
	int86x(TCPIPVECT,&inregs,&outregs,&sregs);
   *remotePort = outregs.x.cx;
	return outregs.h.al;
}
/*************************************************************************/
//get last socket error
/*************************************************************************/
int get_socketerror(int sd)
{
	 union  REGS  inregs;
	 union  REGS  outregs;

	 inregs.h.ah = API_GET_SOCKETERROR;
	 inregs.x.bx = sd;

	 int86(TCPIPVECT,&inregs,&outregs);

	 return outregs.x.ax;
}

/*************************************************************************/
//Set IP Type-Of-Service on a socket
/*************************************************************************/
int Set_IP_Type_Of_Service(int sd, unsigned char TOS, int *error)
{

   union  REGS  inregs;
	union  REGS  outregs;

   *error=0;
   inregs.h.ah = API_SETIPTOS;
   inregs.h.al = TOS;
   inregs.x.bx = sd;
	int86(TCPIPVECT,&inregs,&outregs);
   if((int)outregs.x.ax==-1)
   {
      *error = outregs.x.dx;
   }
   return  outregs.x.ax;

}

/*************************************************************************/
//get and set socket option
/*************************************************************************/

int setsockopt(int sd, SetSocketOption *sockoptptr, int *error)
{
  union  REGS  inregs;
	union  REGS  outregs;
   struct SREGS sregs;

   *error=0;
   inregs.h.ah = API_SETSOCKOPT;
   inregs.x.bx = sd;
   sregs.es    = FP_SEG(sockoptptr);
   inregs.x.di = FP_OFF(sockoptptr);
   int86x(TCPIPVECT,&inregs,&outregs,&sregs);

   if((int)outregs.x.dx==-1)
   {
      *error = outregs.x.ax;
   }
   return  outregs.x.dx;
}

int getsockopt(int sd, GetSocketOption *sockoptptr, int *error)
{
   union  REGS  inregs;
	union  REGS  outregs;
   struct SREGS sregs;

   *error=0;
   inregs.h.ah = API_GETSOCKOPT;
   inregs.x.bx = sd;
   sregs.es    = FP_SEG(sockoptptr);
   inregs.x.di = FP_OFF(sockoptptr);
   int86x(TCPIPVECT,&inregs,&outregs,&sregs);

   if((int)outregs.x.dx==-1)
   {
      *error = outregs.x.ax;
   }
   return  outregs.x.dx;
}


/*************************************************************************/
//Set blocking mode on a socket (default is blocking!!)
/*************************************************************************/
int Set_Blocking_Mode(int sd, unsigned char mode, int *error)
{

   union  REGS  inregs;
   union  REGS  outregs;

   *error=0;
   inregs.h.ah = API_SETBLOCKINGMODE;
   inregs.h.al = mode;
   inregs.x.bx = sd;
   int86(TCPIPVECT,&inregs,&outregs);
   if((int)outregs.x.dx==-1)
   {
      *error = outregs.x.ax;
   }
   return  outregs.x.dx;
}

/*************************************************************************/
//open socket
/*************************************************************************/
int opensocket(unsigned char type, int *error)
{

	union  REGS  inregs;
	union  REGS  outregs;

	inregs.h.ah = API_OPENSOCKET;
	inregs.h.al = type;


	int86(TCPIPVECT,&inregs,&outregs);

	if(outregs.x.dx == (unsigned int)API_ERROR)
	{
		*error = outregs.x.ax;
		return API_ERROR;
	}
	*error = 0;
	return outregs.x.ax;
}


/*************************************************************************/
//Register callback function on socket events
/*************************************************************************/
int RegisterCallbackFunction(int sd, void * funcptr, int eventflagmask ,int *error)
{

   union  REGS  inregs;
	union  REGS  outregs;
   struct SREGS sregs;

   *error=0;
   inregs.h.ah      = API_REGISTERCALLBACK;
   inregs.x.bx      = sd;
   inregs.x.cx      = eventflagmask;
	sregs.es         = FP_SEG(funcptr);
	inregs.x.di      = FP_OFF(funcptr);
   int86x(TCPIPVECT,&inregs,&outregs,&sregs);

   if((int)outregs.x.dx==-1)
   {
      *error = outregs.x.ax;
   }
   return  outregs.x.dx;
}



/*************************************************************************/
//PPP client installed
/*************************************************************************/
int PPP_Client_Installed(void)
{

   union  REGS  inregs;
	union  REGS  outregs;

   inregs.h.ah      = PPPCLIENT_INSTALLED;
   int86(TCPIPVECT,&inregs,&outregs);

   return  outregs.x.ax;
}


/*************************************************************************/
//PPP client open
/*************************************************************************/
int PPP_Client_Open(PPPClient_Init * ptr, int *error)
{

   union  REGS  inregs;
	union  REGS  outregs;
   struct SREGS sregs;

   *error=0;

   inregs.h.ah      = PPPCLIENT_OPEN;
	sregs.es         = FP_SEG(ptr);
	inregs.x.di      = FP_OFF(ptr);
   int86x(TCPIPVECT,&inregs,&outregs,&sregs);

   if((int)outregs.x.dx==-1)
   {
      *error = outregs.x.ax;
   }

   return  outregs.x.dx;
}



/*************************************************************************/
//PPP client close
/*************************************************************************/
int PPP_Client_Close(int *error)
{

   union  REGS  inregs;
	union  REGS  outregs;

   *error=0;
   inregs.h.ah = PPPCLIENT_CLOSE;
	int86(TCPIPVECT,&inregs,&outregs);

   if((int)outregs.x.dx==-1)
   {
      *error = outregs.x.ax;
   }
   return  outregs.x.ax;
}

/*************************************************************************/
//PPP client get status
/*************************************************************************/
int PPP_Client_GetStatus(int *error)
{

   union  REGS  inregs;
	union  REGS  outregs;

   inregs.h.ah = PPPCLIENT_GET_STATUS;
	int86(TCPIPVECT,&inregs,&outregs);

   if((int)outregs.x.ax==-1)
   {
      *error = outregs.x.dx;
   }
   return  outregs.x.ax;
}


/*************************************************************************/
//PPP client set options
/*************************************************************************/
int PPP_Client_SetOptions(PPP_Option *ptr)
{

   union  REGS  inregs;
	union  REGS  outregs;
   struct SREGS segregs;

   inregs.h.ah = PPPCLIENT_SET_OPTIONS;
   segregs.es  = FP_SEG(ptr);
   inregs.x.di = FP_OFF(ptr);
	int86x(TCPIPVECT,&inregs,&outregs,&segregs);

   return  outregs.x.ax;
}


/*************************************************************************/
//PPP client get DNS IP as negotiated by the remote PPP server
/*************************************************************************/
int PPP_Client_Get_DNSIP(unsigned long * IPaddress, int primary_sec, int *error)
{

   union  REGS  inregs;
	union  REGS  outregs;
   struct SREGS sregs;

   *error=0;

   inregs.h.ah      = PPPCLIE_GET_DNSIP;
   inregs.x.bx      = primary_sec;
	sregs.es         = FP_SEG(IPaddress);
	inregs.x.di      = FP_OFF(IPaddress);
   int86x(TCPIPVECT,&inregs,&outregs,&sregs);

   if((int)outregs.x.ax==-1)
   {
      *error = outregs.x.dx;
   }

   return  outregs.x.dx;
}

/*************************************************************************/
//PPP server installed
/*************************************************************************/

int PPP_Server_Installed(void)
{
   union  REGS  inregs;
	union  REGS  outregs;

   inregs.h.ah = PPPSERVER_INSTALLED;
	int86(TCPIPVECT,&inregs,&outregs);
   return  outregs.x.ax;
}


/*************************************************************************/
//PPP server suspend
/*************************************************************************/
int PPP_Server_Suspend(int timeoutsecs, int *error)
{

   union  REGS  inregs;
	union  REGS  outregs;

   *error=0;
   inregs.h.ah = PPPSERVER_SUSPEND;
   inregs.x.bx = timeoutsecs;
	int86(TCPIPVECT,&inregs,&outregs);
   if((int)outregs.x.ax==-1)
   {
      *error = outregs.x.dx;
   }
   return  outregs.x.ax;

}

/*************************************************************************/
//PPP server  activate
/*************************************************************************/
int PPP_Server_Activate(int timeoutsecs,int *error)
{
   union  REGS  inregs;
	union  REGS  outregs;

   *error=0;
   inregs.h.ah = PPPSERVER_ACTIVATE;
   inregs.x.bx = timeoutsecs;
	int86(TCPIPVECT,&inregs,&outregs);
   if((int)outregs.x.ax==-1)
   {
      *error = outregs.x.dx;
   }
   return  outregs.x.ax;
}


/*************************************************************************/
//PPP server  get config
/*************************************************************************/
int PPP_Server_Get_Cfg(PPP_IPCfg_Data *ptr , int *error)
{
   union  REGS  inregs;
	union  REGS  outregs;
   struct SREGS sregs;

   *error=0;

   inregs.h.ah = PPPSERVER_GET_CFG;
   sregs.es    = FP_SEG(ptr);
   inregs.x.di = FP_OFF(ptr);
   int86x(TCPIPVECT,&inregs,&outregs,&sregs);

   if((int)outregs.x.ax==-1)
   {
      *error = outregs.x.dx;
   }
   return  outregs.x.ax;
}
/*************************************************************************/
//PPP server, get status
/*************************************************************************/
int PPP_Server_GetStatus(void)
{

   union  REGS  inregs;
	union  REGS  outregs;


   inregs.h.ah = PPPSERVER_GET_STATUS;

	int86(TCPIPVECT,&inregs,&outregs);
   return  outregs.x.ax;
}

/*************************************************************************/
//PPP server set options
/*************************************************************************/
int PPP_Server_SetOptions(PPP_Option *ptr)
{

   union  REGS  inregs;
	union  REGS  outregs;
   struct SREGS segregs;

   inregs.h.ah = PPPSERVER_SET_OPTIONS;
   segregs.es  = FP_SEG(ptr);
   inregs.x.di = FP_OFF(ptr);
	int86x(TCPIPVECT,&inregs,&outregs,&segregs);

   return  outregs.x.ax;
}


/*************************************************************************/
//Get pointer to internal TCIP SNMP mib structures
/*************************************************************************/
int Get_SNMP_Data(unsigned char which , void * * snmp_mib_ptr)
{
   union  REGS  inregs;
	union  REGS  outregs;
   struct SREGS sregs;


   inregs.h.ah = API_SNMP_GET;
   inregs.h.al = which;
   int86x(TCPIPVECT,&inregs,&outregs,&sregs);

   if((int)outregs.x.ax==0)
   {
      *snmp_mib_ptr = (void *)MK_FP(sregs.es,outregs.x.di);
      return 0;
   }
   return  outregs.x.ax;
}

/*************************************************************************/
//FTP server: Return the addresss of the FTPserver login counters
/*************************************************************************/
int Get_FTP_Login_Counters(unsigned long * * FTP_Login_Count,unsigned long * * FTP_Login_failCount)
{
  union  REGS  inregs;
  union  REGS  outregs;
  struct SREGS sregs;


  inregs.h.ah = API_FTP_GET_LOGIN;
  int86x(TCPIPVECT,&inregs,&outregs,&sregs);

  *FTP_Login_Count     = NULL;
  *FTP_Login_failCount = NULL;
  if(outregs.x.ax==0)
  {
    *FTP_Login_Count     = (unsigned long *)MK_FP(sregs.es,outregs.x.di);
    *FTP_Login_failCount = (unsigned long *)MK_FP(sregs.ds,outregs.x.si);
  }
  return outregs.x.ax;
}

/*************************************************************************/
//Telnet server: Return the addresss of the Telnetserver login counters
/*************************************************************************/
int Get_Telnet_Login_Counters(unsigned long * * Telnet_Login_Count,unsigned long * * Telnet_Login_failCount)
{
  union  REGS  inregs;
  union  REGS  outregs;
  struct SREGS sregs;


  *Telnet_Login_Count     = NULL;
  *Telnet_Login_failCount = NULL;

  inregs.h.ah = API_TELNET_GET_LOGIN;
  int86x(TCPIPVECT,&inregs,&outregs,&sregs);

  if(outregs.x.ax==0)
  {
    *Telnet_Login_Count     = (unsigned long *)MK_FP(sregs.es,outregs.x.di);
    *Telnet_Login_failCount = (unsigned long *)MK_FP(sregs.ds,outregs.x.si);
  }
  return outregs.x.ax;
}

/*************************************************************************/
//Set FTP Server Idle timeout (using: Set/Get Server Idle Timeout)
/*************************************************************************/
int Set_FTPServer_Idle_Timeout( unsigned timeout )
{
   union  REGS  inregs;
   union  REGS  outregs;

   inregs.h.ah = SET_SERVER_IDLE_TIMEOUT;
   inregs.h.al = 0x00; // set timeout
   inregs.x.bx = 0x00; // Ftp server
   inregs.x.dx = timeout;
   int86( TCPIPVECT, &inregs, &outregs );

   return outregs.x.ax;
}

/*************************************************************************/
//Set Telnet Server Idle timeout (using: Set/Get Server Idle Timeout)
/*************************************************************************/
int Set_TelnetServer_Idle_Timeout( unsigned timeout )
{
   union  REGS  inregs;
   union  REGS  outregs;

   inregs.h.ah = SET_SERVER_IDLE_TIMEOUT;
   inregs.h.al = 0x00; // set timeout
   inregs.x.bx = 0x01; // Telnet server
   inregs.x.dx = timeout;
   int86( TCPIPVECT, &inregs, &outregs );

   return outregs.x.ax;
}

/*************************************************************************/
//Get FTP Server Idle timeout (using: Set/Get Server Idle Timeout)
/*************************************************************************/
unsigned Get_FTPServer_Idle_Timeout(void)
{
   union  REGS  inregs;
   union  REGS  outregs;

   inregs.h.ah = SET_SERVER_IDLE_TIMEOUT;
   inregs.h.al = 0x01; // get timeout
   inregs.x.bx = 0x00; // ftp server
   int86( TCPIPVECT, &inregs, &outregs );

   return outregs.x.dx;
}


/*************************************************************************/
//Get Telnet Server Idle timeout (using: Set/Get Server Idle Timeout)
/*************************************************************************/
unsigned Get_TelnetServer_Idle_Timeout(void)
{
   union  REGS  inregs;
   union  REGS  outregs;

   inregs.h.ah = SET_SERVER_IDLE_TIMEOUT;
   inregs.h.al = 0x01; // get timeout
   inregs.x.bx = 0x01; // Telnet server
   int86( TCPIPVECT, &inregs, &outregs );

   return outregs.x.dx;
}

/*************************************************************************/
//Get telnet state
/*************************************************************************/
int Get_Telnet_State(int *error)
{
   union  REGS  inregs;
	union  REGS  outregs;

   *error=0;
   inregs.h.ah = API_GET_TELNET_STATE;
	int86(TCPIPVECT,&inregs,&outregs);
   if((int)outregs.x.dx==-1)
   {
      *error = outregs.x.dx;
   }
   return  outregs.x.ax;
}


/*************************************************************************/
//Get installed servers and devices of the SC12
/*************************************************************************/
void Get_Installed_Servers(unsigned int * AX, unsigned int *DX)
{
  union  REGS  inregs;
  union  REGS  outregs;

  inregs.h.ah = GET_INSTALLED_SERVERS;
  int86(TCPIPVECT,&inregs,&outregs);
  *AX = outregs.x.ax;
  *DX = outregs.x.dx;
}



/*************************************************************************/
//Reconfigure ethernet interface
/*************************************************************************/
int Reconfigure_ethernet(void)
{
  union  REGS  inregs;
  union  REGS  outregs;
  inregs.h.ah = REINIT_ETHERNET;
  int86(TCPIPVECT,&inregs,&outregs);
  return outregs.x.ax;
}

/*************************************************************************/
//DHCP use   dhcp_use 0/1
/*************************************************************************/
int DHCP_use(unsigned char dhcp_use)
{
  union  REGS  inregs;
  union  REGS  outregs;
  inregs.h.ah = DHCP_USE;
  inregs.h.al = dhcp_use;
  int86(TCPIPVECT,&inregs,&outregs);
  return outregs.x.ax;
}

/*************************************************************************/
//DHCP Stat
/*************************************************************************/
void Get_DHCP_Status(unsigned int * dhcp_use, unsigned int *dhcp_stat)
{
  union  REGS  inregs;
  union  REGS  outregs;
  inregs.h.ah = DHCP_STAT;
  int86(TCPIPVECT,&inregs,&outregs);
  *dhcp_use = outregs.x.ax;
  *dhcp_stat = outregs.x.dx;
}

/*************************************************************************/
//DHCP Stat extended function with getting dhcp config data
//(requires BIOS 1.03B or higher)
/*************************************************************************/
void Get_DHCP_Status_Ext(unsigned int * dhcp_use, unsigned int *dhcp_stat, UserEthDhcp_Entry * * dhcpptr)
{
  union  REGS  inregs;
  union  REGS  outregs;
  struct SREGS sregs;
  inregs.h.ah = DHCP_STAT;
  int86x(TCPIPVECT,&inregs,&outregs,&sregs);
  *dhcp_use = outregs.x.ax;
  *dhcp_stat = outregs.x.dx;
  if(outregs.x.dx==1)
     *dhcpptr = (tag_UserDhcpEthEntry*)MK_FP(sregs.es,outregs.x.di);
  else
     *dhcpptr = NULL;
}
/*************************************************************************/
//Get IP of the ethernet interface
/*************************************************************************/
void Get_IPConfig(char *IP, char * Mask, char *Gateway)
{
  union  REGS  inregs;
  union  REGS  outregs;
  struct SREGS sregs;

  inregs.h.ah = 0x01;
  sregs.es    = FP_SEG(IP);
  inregs.x.dx = FP_OFF(IP);
  int86x(0xA0,&inregs,&outregs,&sregs);

  inregs.h.ah = 0x03;
  sregs.es    = FP_SEG(Mask);
  inregs.x.dx = FP_OFF(Mask);
  int86x(0xA0,&inregs,&outregs,&sregs);


  inregs.h.ah = 0x05;
  sregs.es    = FP_SEG(Gateway);
  inregs.x.dx = FP_OFF(Gateway);
  int86x(0xA0,&inregs,&outregs,&sregs);
}

/*************************************************************************/
//Set IP configuration,becomes valid after call of reconfigure Ethernet
/*************************************************************************/
void Set_IPConfig(char *IP, char * Mask, char *Gateway)
{
  union  REGS  inregs;
  union  REGS  outregs;
  struct SREGS sregs;

  inregs.h.ah = 0x02;
  sregs.es    = FP_SEG(IP);
  inregs.x.dx = FP_OFF(IP);
  int86x(0xA0,&inregs,&outregs,&sregs);

  inregs.h.ah = 0x04;
  sregs.es    = FP_SEG(Mask);
  inregs.x.dx = FP_OFF(Mask);
  int86x(0xA0,&inregs,&outregs,&sregs);

  inregs.h.ah = 0x06;
  sregs.es    = FP_SEG(Gateway);
  inregs.x.dx = FP_OFF(Gateway);
  int86x(0xA0,&inregs,&outregs,&sregs);
}

/*************************************************************************/
//return the address of TCPIP packet counter struct
/*************************************************************************/
void Get_TCPIP_Statistics(Packet_Count * * Packet_Count_Pointer)
{
  union  REGS  inregs;
  union  REGS  outregs;
  struct SREGS sregs;

  inregs.h.ah = TCPIP_STATISTICS;
  int86x(TCPIPVECT,&inregs,&outregs,&sregs);

  *Packet_Count_Pointer = (Packet_Count *)MK_FP(sregs.es,outregs.x.di);

}

/*************************************************************************/
//ping open
/*************************************************************************/
int Ping_Open(Ping * pingptr, int * errorcode)
{
  union  REGS  inregs;
  union  REGS  outregs;
  struct SREGS sregs;


  inregs.h.ah = PING_OPEN;
  sregs.es    = FP_SEG(pingptr);
  inregs.x.di = FP_OFF(pingptr);
  int86x(TCPIPVECT,&inregs,&outregs,&sregs);
  *errorcode=outregs.x.ax;
  return outregs.x.dx;
}


/*************************************************************************/
//ping close
/*************************************************************************/
int Ping_Close(int sd)
{
  union  REGS  inregs;
  union  REGS  outregs;

  inregs.h.ah = PING_CLOSE;
  inregs.x.bx = sd;
  int86(TCPIPVECT,&inregs,&outregs);
  return outregs.x.dx;
}
/*************************************************************************/
//ping statistics
/*************************************************************************/
int Ping_Statistics(Ping * pingptr)
{
  union  REGS  inregs;
  union  REGS  outregs;
  struct SREGS sregs;



  inregs.h.ah = PING_STATISTICS;
  sregs.es    = FP_SEG(pingptr);
  inregs.x.di = FP_OFF(pingptr);
  int86x(TCPIPVECT,&inregs,&outregs,&sregs);
  return outregs.x.dx;
}

/*************************************************************************/
//memory
/*************************************************************************/
void Get_TCPIP_Memory_Status(unsigned long * total, unsigned long * used)
{
   union  REGS  inregs;
   union  REGS  outregs;
   struct SREGS sregs;

   inregs.h.ah = GET_MEMORY_INFO;
   sregs.es    = FP_SEG(total);
   inregs.x.di = FP_OFF(total);
   sregs.ds    = FP_SEG(used);
   inregs.x.si = FP_OFF(used);
   int86x(TCPIPVECT,&inregs,&outregs,&sregs);
}

/*************************************************************************/
//Add gateway
/*************************************************************************/
int  AddDefaultGateway( int interface , unsigned long * Gateway, int * errorcode)
{
   union  REGS  inregs;
   union  REGS  outregs;
   struct SREGS sregs;

   inregs.h.ah = ADD_DEFAULT_GATEWAY;
   inregs.x.bx = interface;
   sregs.es    = FP_SEG(Gateway);
   inregs.x.di = FP_OFF(Gateway);

   int86x(TCPIPVECT,&inregs,&outregs,&sregs);
   *errorcode=outregs.x.ax;
   return outregs.x.dx;
}

/*************************************************************************/
//Delete gateway
/*************************************************************************/
int  DelDefaultGateway(unsigned long * Gateway, int * errorcode)
{
   union  REGS  inregs;
   union  REGS  outregs;
   struct SREGS sregs;

   inregs.h.ah = DEL_DEFAULT_GATEWAY;
   sregs.es    = FP_SEG(Gateway);
   inregs.x.di = FP_OFF(Gateway);

   int86x(TCPIPVECT,&inregs,&outregs,&sregs);
   *errorcode=outregs.x.ax;
   return outregs.x.dx;
}

/*************************************************************************/
//Get gateway
/*************************************************************************/
int  GetDefaultGateway(unsigned long * Gateway, int * errorcode)
{
   union  REGS  inregs;
   union  REGS  outregs;
   struct SREGS sregs;

   inregs.h.ah = GET_DEFAULT_GATEWAY;
   sregs.es    = FP_SEG(Gateway);
   inregs.x.di = FP_OFF(Gateway);

   int86x(TCPIPVECT,&inregs,&outregs,&sregs);
   *errorcode=outregs.x.ax;
   return outregs.x.dx;
}


/*************************************************************************/
//Add a static route
/*************************************************************************/
int  AddStaticRoute(int interface, Route_Entry * route, int * errorcode)
{
   union  REGS  inregs;
   union  REGS  outregs;
   struct SREGS sregs;

   inregs.h.ah = ADD_STATIC_ROUTE;
   inregs.x.bx = interface;
   sregs.es    = FP_SEG(route);
   inregs.x.di = FP_OFF(route);

   int86x(TCPIPVECT,&inregs,&outregs,&sregs);
   *errorcode=outregs.x.ax;
   return outregs.x.dx;
}


/*************************************************************************/
//Delete a static route
/*************************************************************************/
int  DelStaticRoute(int interface, Route_Entry * route, int * errorcode)
{
   union  REGS  inregs;
   union  REGS  outregs;
   struct SREGS sregs;

   inregs.h.ah = DEL_STATIC_ROUTE;
   inregs.x.bx = interface;
   sregs.es    = FP_SEG(route);
   inregs.x.di = FP_OFF(route);

   int86x(TCPIPVECT,&inregs,&outregs,&sregs);
   *errorcode=outregs.x.ax;
   return outregs.x.dx;
}


/*************************************************************************/
//Install an IP multicast address, join a multicast group
/*************************************************************************/
int  Add_IGMP_Membership(unsigned long * MulticastIP, unsigned char * MacAddress, int * errorcode)
{
    union  REGS  inregs;
    union  REGS  outregs;
    struct SREGS sregs;

   inregs.h.ah = ADD_IGMP_MEMBERSHIP;
   //inregs.x.bx = sd;
   sregs.es    = FP_SEG(MulticastIP);
   inregs.x.di = FP_OFF(MulticastIP);
   sregs.ds    = FP_SEG(MacAddress);
   inregs.x.si = FP_OFF(MacAddress);

   int86x(TCPIPVECT,&inregs,&outregs,&sregs);
   *errorcode=outregs.x.ax;
   return outregs.x.dx;
}
/*************************************************************************/
//Delete an IP multicast address, leave a multicast group
/*************************************************************************/
int  Drop_IGMP_Membership(unsigned long * MulticastIP, int * errorcode)
{
    union  REGS  inregs;
    union  REGS  outregs;
    struct SREGS sregs;

   inregs.h.ah = DROP_IGMP_MEMBERSHIP;
   sregs.es    = FP_SEG(MulticastIP);
   inregs.x.di = FP_OFF(MulticastIP);

   int86x(TCPIPVECT,&inregs,&outregs,&sregs);
   *errorcode=outregs.x.ax;
   return outregs.x.dx;
}


/*************************************************************************/
//Map IP multicast to Ethernet multicast
/*************************************************************************/
int  IPMulticast_to_MacAddr(unsigned long * MulticastIP, unsigned char * MacAddress, int * errorcode)
{
    union  REGS  inregs;
    union  REGS  outregs;
    struct SREGS sregs;

   inregs.h.ah = MCASTIP_TO_MACADDR;
   sregs.es    = FP_SEG(MulticastIP);
   inregs.x.di = FP_OFF(MulticastIP);
   sregs.ds    = FP_SEG(MacAddress);
   inregs.x.si = FP_OFF(MacAddress);

   int86x(TCPIPVECT,&inregs,&outregs,&sregs);
   *errorcode=outregs.x.ax;
   return outregs.x.dx;
}






/*************************************************************************/
//end tcpip.c
/*************************************************************************/
