/*++
*******************************************************************************
* Copyright (c) 1990-97 Digi International Inc., All Rights Reserved				*
* 																										*
* This software contains proprietary and confidential information of Digi		*
* International Inc.  By accepting transfer of this copy, Recipient agrees		*
* to retain this software in confidence, to prevent disclosure to others,		*
* and to make no use of this software other than that for which it was			*
* delivered.  This is an unpublished copyrighted work of Digi International	*
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly	*
* prohibited.																						*
* 																										*
* Restricted Rights Legend																		*
*																										*
* Use, duplication, or disclosure by the Government is subject to					*
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in			*
* Technical Data and Computer Software clause at DFARS 252.227-7031 or			*
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -				*
* Restricted Rights at 48 CFR 52.227-19, as applicable.								*
*																										*
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343				*
*																										*
*******************************************************************************

Module Name:

   dxbstat.c

Abstract:

	Usermode application sends dxb adapters W_GETSTATS request to get iwan stats.

Author:

   Michael Zarns

--*/

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "DsIoctl.h"
#include "dxbtypes.h"
#define MAXIOCBSZ 1024
#include "iwan_control.h"
#include "layer1_stats.h"
#define IWAN_DEVICE		"IWAN"


///////////////////////////////////////////////////////////////////////////////
//
// Debug Output Support
//							  

#if DBG // Checked build

#define DebugPrint		printf

#undef ASSERT
#define ASSERT( statement )																\
{																									\
	if ( !(statement) )																		\
	{																								\
		DebugPrint( "ASSERT FAILED: " #statement "\n\tfile %s, line %d\n",	\
		            __FILE__, __LINE__ );												\
		DebugBreak();																			\
	}																								\
}

#else // Free build

#define DebugPrint()
#define DebugBreak()				;
#define ASSERT( statement )	;

#endif // DBG


BOOL 
dsvSyncIoRequest( IN HANDLE hDevice, 
                  IN LONG   Ioctl, 
                  IN PVOID  pInData, 
                  IN ULONG  InDataLength, 
                  IN PVOID  pOutData, 
                  IN ULONG  OutDataLength,
                  OUT PDWORD pError )
{
	BOOL bSuccess;
	DWORD dwBytes;
	OVERLAPPED Ol;
	DWORD Error;

	ZeroMemory( &Ol, sizeof( Ol ) );
	Ol.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
	dwBytes = 0;

	bSuccess = DeviceIoControl( hDevice, Ioctl, 
	                            pInData, InDataLength,
	                            pOutData, OutDataLength,
	                            &dwBytes, &Ol );
	if ( !bSuccess )
	{
		Error = GetLastError();
		if ( Error == ERROR_IO_PENDING )
			bSuccess = GetOverlappedResult( hDevice, &Ol, &dwBytes, TRUE );
		else
			printf( "DeviceIoControl failed, Error %d\n", Error );
	}

	CloseHandle( Ol.hEvent );

	*pError = bSuccess ? 0 : GetLastError();
	return( bSuccess );
}


BOOL 
dsvAsyncIoRequest( HANDLE hDevice, 
                   LONG   Ioctl, 
                   PVOID  pInData, 
                   ULONG  InDataLength, 
                   PVOID  pOutData, 
                   ULONG  OutDataLength,
                   PDWORD pdwBytes,
                   LPOVERLAPPED pOl )
{
	BOOL bSuccess;

	bSuccess = DeviceIoControl( hDevice, Ioctl, 
	                            pInData, InDataLength,
	                            pOutData, OutDataLength,
	                            pdwBytes, pOl );

#if DBG
	if ( !bSuccess && GetLastError() != ERROR_IO_PENDING )
		DebugPrint( "AsyncIoRequest failed, GetLastError = 0x%08x\n", GetLastError() );
#endif

	return( bSuccess );
}




///////////////////////////////////////////////////////////////////////////////
//
// Helper Routines.  
//
// These routines hide the gory details of commonly performed actions, such as 
// sending an Open request.
//
// All helper, or internal, routines begin with the "dsv" prefix.
// 

BOOL
DsOpen(
	IN HANDLE hDevice,
	IN PCHAR pDeviceName,
	OUT PHANDLE phStream )
/*++

Description:

	This routine performs a synchronous open request to the named device.

Parameters:

	hDevice
		Device handle on which to send this request.

	pDeviceName
		Null-terminated string containing the devicename to open, i.e. "X250".

	phStream
		Address to which the stream handle will be written on successful completion
		of the open request..

Return Value:

	TRUE if successful, otherwise FALSE.

--*/
{
	DS_OPEN Open = {0};
	BOOL bSuccess;
	DWORD Error;

	strncpy( (PVOID)&Open.DeviceName, pDeviceName, DS_DEVICENAME_SIZE );
	bSuccess = dsvSyncIoRequest( hDevice, IOCTL_DS_OPEN,
	                             &Open, sizeof( Open ),
	                             &Open, sizeof( Open ), &Error );
	*phStream = Open.hStream;
	return( bSuccess && !Open.ErrorCode );
}


BOOL
DsClose(
	IN HANDLE hDevice,
	IN HANDLE hStream )
/*++

Description:

	Performs a synchronous close request on the stream.

Parameters:

	hDevice
		Device handle on which to send this request.

	hStream
		Handle of stream to close.

Return Value:

	TRUE if successful, otherwise FALSE.

--*/
{
	DS_CLOSE Close = {0};
	BOOL bSuccess;
	DWORD Error;
	Close.hStream = hStream;
	bSuccess = dsvSyncIoRequest( hDevice, IOCTL_DS_CLOSE,
	                             &Close, sizeof Close,
	                             &Close, sizeof Close,
	                             &Error );
	return( bSuccess );
}


BOOL
DsIoctl(
	IN HANDLE hDevice,
	IN HANDLE hStream,
	IN ULONG  Command,
	IN PVOID  pData,
	IN ULONG  cbData )

/*++

Description:

	Performs a synchronous ioctl request on the stream.

Return Value:

	TRUE if successful, otherwise FALSE.

--*/
{
	DS_IOCTL Ioctl = {0};
	BOOL bSuccess;
	DWORD Error;

	Ioctl.hStream = hStream;
	Ioctl.Command = Command;
	Ioctl.pDataIn = Ioctl.pDataOut = pData;
	Ioctl.cbDataIn = Ioctl.cbMaxDataOut = cbData;


	bSuccess = dsvSyncIoRequest( hDevice, IOCTL_DS_IOCTL, 
	                             &Ioctl, sizeof Ioctl, 
	                             &Ioctl, sizeof Ioctl, &Error );
	if ( !bSuccess || Error || Ioctl.ReturnValue || Ioctl.ErrorCode )
	{
		printf( "Ioctl failed, bSuccess 0x%x, ReturnVal 0x%x, Error 0x%x\n", bSuccess, Ioctl.ReturnValue, Ioctl.ErrorCode );
		return FALSE;
	}
	return TRUE;
}


void __cdecl 
main( int argc, char *argv[] )
{
	ULONG i;
	HANDLE hDevice = NULL;
	ULONG Snid;
	CHAR FullDeviceName[64];

	if ( argc != 3 || strlen(argv[2])!= 1 )
	{
		printf( "Usage:\n\n"
		        "  dxbstat <device> <snid>\n\n"
		        "Example:   dxbstat digidxb2 1\n" );
		return;
	}

	Snid = atoi(argv[2]);

	// Open the NT device
	strcpy( FullDeviceName, "\\\\.\\" );
	strcat( FullDeviceName, argv[1] );	// argv[0] is the exe, argv[1] is devicename
	printf( "Opening device %s\n", FullDeviceName );
	hDevice = CreateFile( FullDeviceName, GENERIC_READ | GENERIC_WRITE,  
	                      FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 
	                      FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );
	if ( hDevice == INVALID_HANDLE_VALUE )
	{
		printf( "CreateFile failed!\n" );
		goto Exit;
	}

	{
		DWORD i;
		HANDLE hStream;
		BOOL bSuccess = DsOpen( hDevice, IWAN_DEVICE, &hStream );
		if ( !bSuccess || !hStream )
		{
			printf( "DsOpen failed, bSuccess 0x%x, hStream 0x%x\n", bSuccess, hStream );
			goto Exit;
		}

		printf( "Iwan Stats, Snid %d:\n", Snid );
		for ( i = 0; i < 24; i++ )
		{
			#define BUFFER_SIZE ( sizeof(struct wan_stioc)+sizeof(hdlcstats_t) )
			CHAR Buffer[BUFFER_SIZE];
			struct wan_stioc *pIoc = (PVOID)&Buffer;
			isdnstats_t * pStats = (PVOID)( (PCHAR)pIoc + sizeof *pIoc );

			ZeroMemory( Buffer, BUFFER_SIZE );
			pIoc->w_type         = WAN_STATS;
			pIoc->w_stats_offset = sizeof *pIoc;
			pIoc->w_snid         = Snid;
			pIoc->w_chanid       = i + 1;

			bSuccess = DsIoctl( hDevice, hStream, W_GETSTATS, &Buffer, BUFFER_SIZE );
			if ( bSuccess )
			{
				printf( "ChanId %d\n"
				        "   hc_txoctets = 0x%08x, hc_txgood  = 0x%08x, hc_txclass1 = 0x%08x\n"
				        "   hc_txclass2 = 0x%08x, hc_txdef   = 0x%08x, hc_txurun   = 0x%08x\n"
				        "   hc_rxoctets = 0x%08x, hc_rxgood  = 0x%08x, hc_rxerr    = 0x%08x\n"
				        "   hc_rxorun   = 0x%08x, hc_rxcrc   = 0x%08x, hc_rxnobuf  = 0x%08x\n"
				        "   hc_rxnflow  = 0x%08x, hc_rxoflow = 0x%08x, hc_rxabort  = 0x%08x\n",
				        pIoc->w_chanid,
				        pStats->hc_txoctets, pStats->hc_txgood,  pStats->hc_txclass1,
				        pStats->hc_txclass2, pStats->hc_txdef,   pStats->hc_txurun,
				        pStats->hc_rxoctets, pStats->hc_rxgood,  pStats->hc_rxerr,
				        pStats->hc_rxorun,   pStats->hc_rxcrc,   pStats->hc_rxnobuf,
				        pStats->hc_rxnflow,  pStats->hc_rxoflow,  pStats->hc_rxabort );
			}
		}

		bSuccess = DsClose( hDevice, hStream );
		if ( !bSuccess )
			printf( "DsClose failed!\n" );
	}


Exit:
	if ( hDevice )
		CloseHandle( hDevice );
	printf( "Done\n" );
	return;
}

