/******************************************************************************/
/*                                                                            */
/* ifcheck.c                                                                  */
/*                                                                            */
/* Check status of SANA-II interface under AmiTCP                             */
/*                                                                            */
/* Format:                                                                    */
/*     ifcheck <interface>                                                    */
/*                                                                            */
/* Template:                                                                  */
/*     INTERFACE/A                                                            */
/*                                                                            */
/* Return codes:                                                              */
/*     0         if AmiTCP is active and <interface> is up                    */
/*     5         if AmiTCP is inactive or <interface> is down                 */
/*    10         if any fatal error occurs                                    */
/*                                                                            */
/* Author:                                                                    */
/*     Mathew Hendry (scampi@dial.pipex.com)                                  */
/*                                                                            */
/*                                                                            */
/******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <exec/types.h>
#include <proto/exec.h>
#include <proto/dos.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>

#define IFCHECK_BUFFSIZE 10240

BOOL IsInterfaceUp( char* pIfName, BOOL* fFailed );

extern struct DosLibrary* DOSBase;
struct Library*	SocketBase;

static char pTemplate[] = "INTERFACE/A";
static char pVersion[] = "$VER: ifcheck 0.0 (29.1.97)\0";

int
main( void )
{
	BOOL fFailed = FALSE;
	BOOL fUp = FALSE;
	int nRet = 0;

	if ((DOSBase = (struct DosLibrary*)OpenLibrary( "dos.library", 37 )) != NULL)
	{
		struct RDArgs* pRDArgs;
		char* apArgs[ 1 ] = { 0 };

		if ((pRDArgs = ReadArgs( pTemplate, (LONG*)apArgs, NULL )) != NULL)
		{
			if ((SocketBase = OpenLibrary( "bsdsocket.library", 3 )) != NULL)
			{
				fUp = IsInterfaceUp( apArgs[ 0 ], &fFailed ); 
				CloseLibrary( SocketBase );
			}

			printf( "Interface %s is %s\n", apArgs[ 0 ], (fUp ? "up" : "down") );
			FreeArgs( pRDArgs );
		}
		else
		{
			fprintf( stderr, "ifcheck: required argument missing\n" );
			fFailed = TRUE;
		}

		CloseLibrary( (struct Library*)DOSBase );
	}
	else
	{
		fprintf( stderr, "ifcheck: cannot open dos.library version 37 or higher\n" );
		fFailed = TRUE;
	}

	/* Set FAIL if anything went badly wrong */
	if (fFailed)
	{
		nRet = 10;
	}
	else
	{
		/* Set WARN if interface is down */
		if (!fUp)
		{
			nRet = 5;
		}
	}

	return nRet;
}

BOOL
IsInterfaceUp( char* pIfName, BOOL* fFailed )
{
	BOOL fUp = FALSE;
	BOOL fDone = FALSE;

	int nSocket;

	/* Open socket */
	if ((nSocket = socket( AF_INET, SOCK_DGRAM, 0 )) >= 0)
	{
		char* pBuffer;

		/* Allocate buffer to store interface configuration */
		if ((pBuffer = malloc( IFCHECK_BUFFSIZE * sizeof( char ) )) != NULL)
		{
			struct ifconf ifConf;
			ifConf.ifc_len = IFCHECK_BUFFSIZE;
			ifConf.ifc_buf = pBuffer;

			/* Get interface configuration */
			if (IoctlSocket( nSocket, SIOCGIFCONF, (char*)&ifConf ) >= 0)
			{
				struct ifreq* pifReq = ifConf.ifc_req;
				struct ifreq* pifReqEnd = (struct ifreq*)((caddr_t)pifReq + ifConf.ifc_len);

				/* Scan interface configuration */
				while (!fDone && !(*fFailed))
				{
					int nFudge;

					/* Check interface name */
					if (!strcmp( pifReq->ifr_name, pIfName ))
					{
						/* Get interface flags */
						if (IoctlSocket( nSocket, SIOCGIFFLAGS, (char*)pifReq ) >= 0)
						{
							/* Check whether interface is up */
							if (pifReq->ifr_flags & IFF_UP)
							{
								fUp = TRUE;
								fDone = TRUE;
							}
						}
						else
						{
							fprintf( stderr, "ifcheck: SIOCGIFFLAGS request failed\n" );
							*fFailed = TRUE;
						}
					}

					/* Fudge for variable-length addresses */
					nFudge = pifReq->ifr_addr.sa_len - sizeof( struct sockaddr );
					pifReq = (struct ifreq*)((caddr_t)pifReq + sizeof( struct ifreq ) + nFudge);

					if (pifReq >= pifReqEnd)
					{
						fDone = TRUE;
					}
				}
			}
			else
			{
				fprintf( stderr, "ifcheck: SIOCGIFCONF request failed\n" );
				*fFailed = TRUE;
			}

			free( pBuffer );
		}
		else
		{
			fprintf( stderr, "ifcheck: failed to allocate memory\n" );
			*fFailed = TRUE;
		}

		CloseSocket( nSocket );
	}
	else
	{
   		fprintf( stderr, "ifcheck: unable to open socket\n" );
		*fFailed = TRUE;
	}

	return fUp;
}
