/*++

/*****************************************************************************
 * Copyright (c) 1988-95 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 copyright work  Digi   International
 * Inc.    Ecept   as   permitted   by  federal  law,  17 USC 117, copying is
 * strictly prohibited.
 * 
 * Digi  International  Inc.  CONFIDENTIAL  -   (Digi    International    Inc.
 * Confidential  when   combined   with   the   aggregated  modules  for  this
 * product) OBJECT CODE ONLY SOURCE MATERIALS
 * 
 * (C) COPYRIGHT Digi International Inc. 1995
 * 
 * All Rights Reserved
 * 
 * US   Government   Users   Restricted   Rights   -   Use,   duplication   or
 * disclosure  restricted by GSA ADP Schedule Contract with Digi International
 * Inc.
 * 
 *****************************************************************************

Module Name:

   frtrace.c

Abstract:

   This module contains code to turn on tracing on a Digi Frame Relay adapter.
	Taken from Rik/Craig's Digi NT X25Trace code base.

Revision History:

--*/

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

#include "dxbtypes.h"
#include "dsioctl.h"
#include "dsuser.h"

//#include "fr_cont.h"
#include "wan_control.h"

//#define WAN    0x00000001
//#define LAPB   0x00000002
//#define X25    0x00000004
//#define FR     0x00000008

void	getwanlinestats(wan_linestatus_t *wan_line);

#define PrintUsage() \
   printf( "usage:\n"   \
           "   snatrace <device> <Snid>\n"   \
           "      e.g. snatrace digidxb2 2\n" );

//------------------------------------------------------------ MLZ 03/20/96 {
// Revised SXB stuff
#define XIOCTL_DATA_SIZE 512
typedef struct X_IOCTL
{
	DS_IOCTL SxbIoctl;
	UCHAR Data[512];
} X_IOCTL, *PX_IOCTL;

#define XGETMSG_CONTROL_SIZE 512
#define XGETMSG_DATA_SIZE 3300

typedef struct X_GETMSG
{
	DS_GETMSG SxbGetMsg;
	UCHAR Control[XGETMSG_CONTROL_SIZE];
	UCHAR Data[XGETMSG_DATA_SIZE];
} X_GETMSG, *PX_GETMSG;
//------------------------------------------------------------ MLZ 03/20/96 }

CHAR	DeviceName[32];
HANDLE	hFile;
INT		Snid;
HANDLE	hStream = NULL;

BOOL WINAPI MyCtrlHandler( DWORD dwCtrlType );

int StrToWStr( LPWSTR wszDest, LPSTR szSrc, LONG count );
USHORT WstrLength( IN PWSTR Wstr );

#if 0
void print_fr( PX_GETMSG pXGetMsg );
void print_lmi( PUCHAR Payload, ULONG Length, fr_trc_msg_t * TraceMsg );
void print_iframe( PUCHAR Payload, ULONG Length, fr_trc_msg_t * TraceMsg );
void print_user( PUCHAR dp, int len );
void print_ip( PUCHAR dp, ULONG length );
void print_ipx( PUCHAR dp );
void make_ipx_str( PUCHAR buffer, PUCHAR addr );
void make_ip_str( PUCHAR buffer, PUCHAR addr );
#endif // 0


BOOL WINAPI MyCtrlHandler (DWORD dwCtrlType)
{
	BOOL    bSuccess;

	switch (dwCtrlType)
	{
	case CTRL_C_EVENT:
	case CTRL_BREAK_EVENT:
		bSuccess = DsPurge (hFile, hStream, DS_PURGE_ALL);
		printf ("Calling DsClose()\n");
		bSuccess = DsClose (hFile, hStream);

		// Always close the file handle.
		printf ("Closing device %s\n", DeviceName);
		CloseHandle (hFile);
		printf ("Returning FALSE\n");
		return (FALSE);

	default:
		return (FALSE);
	}
}



void _cdecl
main (int argc, char *argv[])
{
	char				**device = NULL;
	int					errflg = 0;
	BOOL				bSuccess = FALSE;
	wan_linestatus_t	WanLineStatus = {0};


	if (argc != 3)
	{
		PrintUsage ();
		return;
	}

	device = &argv[1];
	if (device == NULL)
	{
		PrintUsage ();
		return;
	}
	else if (device[0] == NULL)
	{
		PrintUsage ();
		return;
	}

	SetConsoleCtrlHandler (MyCtrlHandler, TRUE);

	Snid = atoi (argv[2]);

	strcpy (DeviceName, "\\\\.\\");
	strcat (DeviceName, device[0]);

	printf ("device = %s\n", DeviceName);
	printf ("Snid   = 0x%x\n", Snid);
	printf ("Trace type = SNA\n");

#if 1
	if ((hFile = CreateFile (DeviceName,
			GENERIC_READ | GENERIC_WRITE,
			FILE_SHARE_READ | FILE_SHARE_WRITE,
			NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
			NULL)) == INVALID_HANDLE_VALUE)
	{
		printf ("Couldn't open %s\n", DeviceName);
		return;
	}

	bSuccess = DsOpen (hFile, "WAN", &hStream);
	if (!bSuccess)
	{
		printf ("DsOpen failed, GetLastError = 0x%x\n", GetLastError ());
		return;
	}
	else
	{
		printf ("DsOpen succeeded on WAN\n");
	}

	{
		WanLineStatus.wan_linestatus_snid = Snid;

		bSuccess = DsIoctl (hFile, hStream, W_LINESTATUS, &WanLineStatus, sizeof (WanLineStatus));
		if (!bSuccess)
		{
			printf ("DsIoctl W_LINESTATUS failed, GetLastError = 0x%x\n", GetLastError ());
			printf ("Calling DsClose()\n");
			bSuccess = DsClose (hFile, hStream);
			return;
		}

		if (WanLineStatus.wan_linestatus_snid)
		{
			printf ("Wan Line Status for Snid 0x%x\n", Snid);
		}

		printf ("Calling getwanlinestats()\n");
		getwanlinestats(&WanLineStatus);
	}

	printf ("Calling DsClose()\n");
	bSuccess = DsClose (hFile, hStream);

	// Always close the file handle.
	printf ("Closing device %s\n", DeviceName);
	CloseHandle (hFile);
#endif // 0

}	// end main


#if 0
void 
print_fr (PX_GETMSG pXGetMsg)
{
	ULONG   r;
	int     len = 0;
	char   *dp;
	fr_trc_msg_t *pTraceMsg;

	dp = (PVOID) & pXGetMsg->Data;

	for (r = 0; r < pXGetMsg->SxbGetMsg.cbData; r++)
	{
		printf ("%02x", (unsigned char) dp[r]);
		if (++len == 78)
		{
			printf ("\n");
			len = 0;
		}
	}

	printf ("\n");

	pTraceMsg = (PVOID) & pXGetMsg->Control;

	if (pTraceMsg->fr_trc_dlci == (pTraceMsg->fr_trc_lmi & 0x3ff))
		print_lmi (dp, pXGetMsg->SxbGetMsg.cbData, pTraceMsg);
	else
		print_iframe (dp, pXGetMsg->SxbGetMsg.cbData, pTraceMsg);

	return;
}									// end print_fr


void
print_iframe (
	PUCHAR Payload,
	ULONG Length,
	fr_trc_msg_t * TraceMsg
)
{
	USHORT  Dlci;
	PUCHAR  Packet;
	ULONG   oui;
	USHORT  pid;

	Dlci = (((USHORT) Payload[0] & 0xfc) << 2) |
		(((USHORT) Payload[1] & 0xf0) >> 4);

	printf ("DLCI=%d C/R=%d ", Dlci, (Payload[0] & 2) > 1);
	printf ("FECN=%d BECN=%d DE=%d EA=%d\n",
		Payload[1] & 8 ? 1 : 0,
		Payload[1] & 4 ? 1 : 0,
		Payload[1] & 2 ? 1 : 0,
		Payload[1] & 1 ? 1 : 0);

	if (Dlci != TraceMsg->fr_trc_dlci)
		printf ("*** DLCI does not match internal dlci (%d) ***\n",
			TraceMsg->fr_trc_dlci);

	if (!(TraceMsg->fr_trc_opts & 0x2000))
	{
		/* Not IETF encapsulated frame... just dump the data */
		printf ("DXE DATA\n");
		print_user (Payload + 2, Length - 2);
		return;
	}

	printf ("%sFRAME\nEncapsulated Packet Type: ",
		(Payload[2] == 0x03 ? "UI-" : "RAW I-"));

	/* Deep breath... and... decode! Skip possible padding, start at NLPID */
	Packet = (PUCHAR) (Payload[3] ? Payload + 3 : Payload + 4);
	Length -= (Payload[3] ? 3 : 4);

	switch (Packet[0])
	{
	case 0x08:						/* Q.933 */
		printf ("Q.933\n");
		print_user (Packet + 1, Length - 1);
		break;
	case 0x81:						/* CLNP */
		printf ("ISO CLNP\n");
		print_user (Packet + 1, Length - 1);
		break;
	case 0x82:						/* ESIS */
		printf ("ISO ESIS\n");
		print_user (Packet + 1, Length - 1);
		break;
	case 0x83:						/* ISIS */
		printf ("ISO ISIS\n");
		print_user (Packet + 1, Length - 1);
		break;
	case 0xCC:						/* IP */
		printf ("IP\n");
		print_ip (Packet + 1, Length - 1);
		break;
	case 0x80:						/* SNAP */
		printf ("SNAP  OUI: %02x-%02x-%02x    PID: %02x-%02x\n",
			Packet[1], Packet[2], Packet[3], Packet[4], Packet[5]);
		oui = (((ULONG) Packet[1]) << 16) |
			(((ULONG) Packet[2]) << 8) |
			((ULONG) Packet[3]);
		pid = (((USHORT) Packet[4]) << 8) | ((USHORT) Packet[5]);
		switch (oui)
		{
		case 0x000000:				/* Ethertype */
			switch (pid)
			{
			case 0x8137:			/* IPX */
				printf ("IPX Ethertype\n");
				print_ipx (Packet + 6);
				print_user (Packet + 6, Length - 6);
				break;
			default:
				printf ("Unknown Ethertype\n");
				print_user (Packet + 6, Length - 6);
				break;
			}
			break;

		case 0x0080C2:				/* 802.1 type */
			switch (pid)
			{
			case 0x0001:
			case 0x0007:
				printf ("802.3/Ethernet\n");
				print_user (Packet + 6, Length - 6);
				break;
			case 0x0002:
			case 0x0008:
				printf ("802.4\n");
				print_user (Packet + 6, Length - 6);
				break;
			case 0x0003:
			case 0x0009:
				printf ("802.5\n");
				print_user (Packet + 6, Length - 6);
				break;
			case 0x0004:
			case 0x000A:
				printf ("FDDI\n");
				print_user (Packet + 6, Length - 6);
				break;
			case 0x000B:
				printf ("802.6\n");
				print_user (Packet + 6, Length - 6);
				break;
			case 0x000E:
				printf ("BPDU\n");
				print_user (Packet + 6, Length - 6);
				break;
			case 0x000D:
				printf ("Packet Fragment:   Sequence Number: 0x%04x   Offset: %4d   Final -> %s\n",
					((u_short) Packet[6] << 8) | ((u_short) Packet[7]),
					((((u_short) Packet[8] & 0x7) << 8) | ((u_short) Packet[9])) * 32,
					Packet[8] & 0x80 ? "Yes" : "No");
				print_user (Packet + 10, Length - 10);
				break;
			}
			break;

		default:
			printf ("Unknown OUI\n");
			print_user (Packet + 6, Length - 6);
			break;
		}
		break;

	default:
		printf ("UNKNOWN (%02x)\n", Packet[0]);
		print_user (Packet + 1, Length - 1);
		break;
	}

}									// end print_iframe




void
print_lmi (
	PUCHAR payload,
	ULONG length,
	fr_trc_msg_t * TraceMsg
)
{
	u_short dlci = (((u_short) payload[0] & 0xfc) << 2) | (((u_short) payload[1] & 0xF0) >> 4);

	printf ("DLCI=%d C/R=%d ", dlci, (payload[0] & 2) > 1);
	printf ("FECN=%d BECN=%d DE=%d EA=%d\n",
		payload[1] & 8 ? 1 : 0,
		payload[1] & 4 ? 1 : 0,
		payload[1] & 2 ? 1 : 0,
		payload[1] & 1 ? 1 : 0);


	printf ("Un-Number Frame(Control)=%d\n", payload[2]);
	printf ("Protocol Discriminator=%d\n", payload[3]);
	printf ("Call Reference=%d\n", payload[4]);

	switch (payload[5])
	{
	case 0x7D:
		printf ("LMI Status Message\n");
//			fr_print_lmi_status( &payload[6], length - 6 ) ;
		break;

	case 0x75:
		printf ("LMI Status Enquiry\n");
//			fr_print_lmi_status_enquiry( &payload[6] );
		break;

	case 0x7B:
		printf ("LMI Update Status\n");
//			fr_print_lmi_update_status( &payload[6], length - 6 ) ;
		break;

	default:
		break;
	}
}									// end print_lmi



void
print_ip (PUCHAR dp, ULONG length)
{
	u_short header_size;
	u_short packet_size;
	u_short true_packet_size = (u_short) length;
	u_short min;
	char    src_addr[16], dst_addr[16];

	header_size = (dp[0] & 0x0F) * 4;
	packet_size = ((u_short) dp[2] << 8) | ((u_short) dp[3]);
	make_ip_str (src_addr, dp + 12);
	make_ip_str (dst_addr, dp + 16);

	min = (header_size < 20) ? header_size : 20;

	if (true_packet_size < min)
	{
		printf ("Garbaged IP packet\n");
		return;
	}

	if (true_packet_size != packet_size)
	{
		printf ("IP packet has incorrect size values... Adjusting data size to %d\n", (packet_size = true_packet_size) - header_size);
	}

	printf ("Header Size: %d bytes;  Source: %s     Dest: %s\n",
		header_size, src_addr, dst_addr);

	print_user (dp, header_size);

	printf ("IP Data:\n");

	print_user (dp + header_size, packet_size - header_size);
}



void
print_ipx (PUCHAR dp)
{
	u_short length;
	char    src_addr[30], dst_addr[30];

	length = (((u_short) dp[2]) << 8) | ((u_short) dp[3]);
	make_ipx_str (dst_addr, dp + 6);
	make_ipx_str (src_addr, dp + 18);

	printf (
		"Packet Length: %d\nSource: %s\nDest: %s\n",
		length,
		src_addr,
		dst_addr
		);

	print_user (dp, 30);

	if (length > 30)
	{
		printf ("Data:\n");
		print_user (dp + 30, length - 30);
	}
	else
		printf ("No data in packet\n");
}




void
print_user (PUCHAR dp, int len)
{
	int     i, k;

	k = 0;
	while (k <= len)
	{
		if ((len - k) > 16)
		{
			for (i = 0; i < 16; i++)
			{
				printf ("%02x ", dp[i]);
				k++;
			}

			printf (" ");

			for (i = 0; i < 16; i++)
			{
				if (dp[i] >= 0x20 && dp[i] <= 0x7E)
					printf ("%c", dp[i]);
				else
					printf (".");
			}
			printf ("\n");
			dp += i;
		}
		else
		{
			for (i = 0; i < (len - k); i++)
			{
				printf ("%02x ", dp[i]);
			}

			for (i = 0; i < (16 - (len - k)); i++)
				printf ("   ");

			printf (" ");

			for (i = 0; i < (len - k); i++)
			{
				if (dp[i] >= 0x20 && dp[i] <= 0x7E)
					printf ("%c", dp[i]);
				else
					printf (".");
			}
			printf ("\n");
			return;
		}
	}
}

void
make_ip_str (PUCHAR buffer, PUCHAR addr)
{
	/* buffer MUST be 16 characters or greater */
	/* addr must point to the first byte of the IP address */

	sprintf (buffer, "%3d.%3d.%3d.%3d", addr[0], addr[1], addr[2], addr[3]);
}

void
make_ipx_str (PUCHAR buffer, PUCHAR addr)
{
	/* buffer MUST be 27 characters or greater */
	/* addr must point to the first byte of the IPX address */

	/* This is a long sprintf, yes, but it is hopefully also endian independent */
	sprintf (buffer, "%02x%02x%02x%02x/%02x%02x%02x%02x%02x%02x/%02x%02x",
		addr[0], addr[1], addr[2], addr[3],
		addr[4], addr[5], addr[6], addr[7], addr[8], addr[9],
		addr[10], addr[11]);
}
#endif // 0


void
getwanlinestats(wan_linestatus_t *wan_line)
{
	int mask = 0x01, signals = 0, OutLen = 0, Ret = 0;
#define TWO_WIRE	1
#define NRZI		2
#define SDLCCRC		4
#define TxInvert	8

#define FULL_DUPLEX 0
#define HALF_DUPLEX 2
printf ("Entered getwanlinestats()\n");


	fprintf(stdout,"WAN Line Statistics for Subnetwork %d\n", wan_line->wan_linestatus_snid);

	fprintf(stdout,"\t%8ld  good frames transmitted\n", wan_line->wan_linestatus_stats.hc_txgood);
	fprintf(stdout,"\t%8ld  good frames received\n", wan_line->wan_linestatus_stats.hc_rxgood);
	fprintf(stdout,"\t%8ld  good bytes transmitted\n", wan_line->wan_linestatus_stats.hc_txgdbytes);
	fprintf(stdout,"\t%8ld  good bytes received\n", wan_line->wan_linestatus_stats.hc_rxgdbytes);
	fprintf(stdout,"\t%8ld  transmit underruns\n", wan_line->wan_linestatus_stats.hc_txurun);
	fprintf(stdout,"\t%8ld  receive overruns\n", wan_line->wan_linestatus_stats.hc_rxorun);
	fprintf(stdout,"\t%8ld  CRC/frame errors received\n", wan_line->wan_linestatus_stats.hc_rxcrc);
	fprintf(stdout,"\t%8ld  received frames with no buffer\n", wan_line->wan_linestatus_stats.hc_rxnobuf);
	fprintf(stdout,"\t%8ld  received frames with no flow control\n", wan_line->wan_linestatus_stats.hc_rxnflow);
	fprintf(stdout,"\t%8ld  receive buffer overflows\n", wan_line->wan_linestatus_stats.hc_rxoflow);
	fprintf(stdout,"\t%8ld  receive aborts\n", wan_line->wan_linestatus_stats.hc_rxabort);
	fprintf(stdout,"\t%8ld  transmit aborts\n", wan_line->wan_linestatus_stats.hc_txabort);
	fprintf(stdout,"\t%8ld  clock missing timeouts\n", wan_line->wan_linestatus_stats.hc_noclock);
	fprintf(stdout,"\t%8ld  short_frame/bit count errors\n", wan_line->wan_linestatus_stats.hc_rxbiterr);
	fprintf(stdout,"\t%8ld  Frames without buffers available\n", wan_line->wan_linestatus_stats.hc_rxnomp);
	if(wan_line->wan_linestatus_linespeed || wan_line->wan_linestatus_config_baud == 0) {
		fprintf(stdout,"\t%8ld  Line Speed\n", wan_line->wan_linestatus_linespeed);
		if (wan_line->wan_linestatus_linestatus & WAN_LINESTATUS_FLAGS)
			fprintf(stdout,"\t\t  Line Status: Receiving flags\n");
		else if (wan_line->wan_linestatus_linestatus & WAN_LINESTATUS_IDLE)
			fprintf(stdout,"\t\t  Line Status: Line is Idle\n");
		else
			fprintf(stdout,"\t\t  Line Status: Receiving frames\n");
	} else {
		fprintf(stdout,"\t%8ld  Configured baud rate\n", wan_line->wan_linestatus_config_baud);
	}
	fprintf(stdout,"\t%8ld  Maximum Frame Size\n", wan_line->wan_linestatus_maxframe);
	fprintf(stdout,"\t\t  Line options: ", wan_line->wan_linestatus_options);
	if (wan_line->wan_linestatus_options & TWO_WIRE)
		fprintf(stdout,"Two wire, ");
	else
		fprintf(stdout,"Four wire, ");

	if (wan_line->wan_linestatus_options & NRZI)
		fprintf(stdout,"NRZI, ");
	else
		fprintf(stdout,"NRZ, ");

	if (wan_line->wan_linestatus_options & SDLCCRC)
		fprintf(stdout,"Stream CRC flags");
	else
		fprintf(stdout,"Do not stream CRC flags");

	if (wan_line->wan_linestatus_options & TxInvert)
		fprintf(stdout,", Transmit Invert\n");
	else
		fprintf(stdout,"\n");

	if (wan_line->wan_linestatus_hdplx == HALF_DUPLEX)
		fprintf(stdout,"\t\t  Half Duplex\n");
	else
		fprintf(stdout,"\t\t  Full Duplex\n");
	fprintf(stdout,"\t\t  Cable Id: ", wan_line->wan_linestatus_cable_id);
	switch(wan_line->wan_linestatus_cable_id) {
		case WAN_X21:
			fprintf(stdout,"V.11\n");
			break;
		case WAN_V28:
			fprintf(stdout,"RS-232\n");
			break;
		case WAN_V35:
			fprintf(stdout,"V.35\n");
			break;
		case WAN_V36:
			fprintf(stdout,"V.36\n");
			break;
		default:
			fprintf(stdout,"Unknown\n");
			break;
	}
	fprintf(stdout,"\t\t  Modem signals: ", wan_line->wan_linestatus_modem);
	signals = wan_line->wan_linestatus_modem;
	while (signals) {
		switch((signals & mask)) {
			case 0: break;
			case W_DTR:
				fprintf(stdout,"DTR");
				signals &= ~W_DTR;
				if (signals) 
					fprintf(stdout,", ");
				break;
			case W_RTS:
				fprintf(stdout,"RTS");
				signals &= ~W_RTS;
				if (signals) 
					fprintf(stdout,", ");
				break;
			case W_CTS:
				fprintf(stdout,"CTS");
				signals &= ~W_CTS;
				if (signals) 
					fprintf(stdout,", ");
				break;
			case W_DSR:
				fprintf(stdout,"DSR");
				signals &= ~W_DSR;
				if (signals) 
					fprintf(stdout,", ");
				break;
			case W_DCD:
				fprintf(stdout,"DCD");
				signals &= ~W_DCD;
				if (signals) 
					fprintf(stdout,", ");
				break;
			case W_MODE:
				fprintf(stdout,"MODE");
				signals &= ~W_MODE;
				if (signals) 
					fprintf(stdout,", ");
				break;
			case W_RI:
				fprintf(stdout,"RI");
				signals &= ~W_RI;
				if (signals) 
					fprintf(stdout,", ");
				break;
			default:
				fprintf(stdout,"Unknown");
				signals = 0;
				break;
		}
		mask = mask << 1;
	}

	fprintf(stdout,"\n");
	fprintf(stdout,"\n");
}



int 
StrToWStr (LPWSTR wszDest, LPSTR szSrc, LONG count)
{
	LONG    i;

	for (i = 0; i < count; i++)
	{
		wszDest[i] = szSrc[i];
	}

	return (i - 1);
}




USHORT WstrLength (IN PWSTR Wstr)
/*++

Routine Description:

   Determines the number of bytes used by the passed in Wstr

Arguments:

   Wstr - Pointer to wide character string.

Return Value:

   Length, in bytes.

--*/
{
	USHORT  Length = 0;

	while (*Wstr++)
	{
		Length += sizeof (WCHAR);
	}
	return (Length);
}									// end DigiWstrLength

