/*++
*******************************************************************************
* Copyright (c) 1990-98 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:

   isdnwan.c

Abstract:

   Handler routines for Wan SetInfo and QueryInfo requests.  Each request is 
   identified by its Object Identifier (OID).  Also, routines for indicating status 
   up to Wan.

Author:

   Michael Zarns

--*/
#include "digiisdn.h"


NDIS_STATUS
IsdnWanQuery(
	IN PISDN_ADAPTER pAdapter,
	IN NDIS_OID      Oid,
	IN PVOID         pData,
	IN ULONG         cbData,
	OUT PULONG       pcbWritten,
	OUT PULONG       pcbNeeded )
/*++

Description:

	Handle all WAN query OID requests.

--*/
{
	NDIS_STATUS Status = NDIS_STATUS_SUCCESS;	// Assume success!
	ULONG cbWritten = 0;
	ULONG cbNeeded  = 0;
	CHAR Addr[6] = {'D','i','g','i','0','1'};

//	DigiDump( DIGIOID, ( "ISDN!WanQuery: pAdapter 0x%x, Oid 0x%08x\n", pAdapter, Oid ) );

	switch ( Oid )
	{
		case OID_WAN_PERMANENT_ADDRESS:
		{
			ASSERT( cbData >= sizeof Addr );
			DigiDump( DIGIWANOID, ( "Isdn!WanQuery: OID_WAN_PERMANENT_ADDRESS, pAdapter 0x%x\n", pAdapter ) );
			NdisMoveMemory( pData, &Addr, sizeof Addr );
			cbWritten = sizeof Addr;
			break;
		}

		case OID_WAN_CURRENT_ADDRESS:
		{
			ASSERT( cbData >= sizeof Addr );
			DigiDump( DIGIWANOID, ( "Isdn!WanQuery: OID_WAN_CURRENT_ADDRESS, pAdapter 0x%x\n", pAdapter ) );
			NdisMoveMemory( pData, &Addr, sizeof Addr );
			cbWritten = sizeof Addr;
			break;
		}

		case OID_WAN_QUALITY_OF_SERVICE:
		{
			PNDIS_WAN_QUALITY const pWanQuality = pData;
			DigiDump( DIGIWANOID, ( "Isdn!WanQuery: OID_WAN_QUALITY_OF_SERVICE, pAdapter 0x%x\n", pAdapter ) );
			*pWanQuality = NdisWanReliable;
			cbWritten = sizeof *pWanQuality;
			break;
		}

		case OID_WAN_HEADER_FORMAT:
		{
			PNDIS_WAN_HEADER_FORMAT const pFormat = pData;
			DigiDump( DIGIWANOID, ( "Isdn!WanQuery: OID_WAN_HEADER_FORMAT, pAdapter 0x%x\n", pAdapter ) );
			*pFormat = NdisWanHeaderNative;
			cbWritten = sizeof *pFormat;
			break;
		}

		case OID_WAN_MEDIUM_SUBTYPE:
		{
			PNDIS_WAN_MEDIUM_SUBTYPE const pSubType = pData;
			DigiDump( DIGIWANOID, ( "Isdn!WanQuery: OID_WAN_MEDIUM_SUBTYPE, pAdapter 0x%x\n", pAdapter ) );
			*pSubType = NdisWanMediumIsdn;
			DigiDump( DIGIWANOID, ( "   SubType: %s\n", *pSubType == NdisWanMediumIsdn ? "NdisWanMediumIsdn" : "Unknown" ) );
			cbWritten = sizeof *pSubType;
			break;
		}

		case OID_WAN_GET_INFO:
		{
			PNDIS_WAN_INFO const pInfo = pData;
			LARGE_INTEGER HighestAddress = NDIS_PHYSICAL_ADDRESS_CONST( -1, -1 );
			DigiDump( DIGIWANOID, ( "Isdn!WanQuery: OID_WAN_GET_INFO, pAdapter 0x%x\n", pAdapter ) );
			NdisZeroMemory( pInfo, sizeof *pInfo );
			pInfo->MaxFrameSize  = ISDN_MAX_FRAME_SIZE;
			pInfo->MaxTransmit   = ISDN_SEND_WINDOW;
			pInfo->Endpoints     = pAdapter->nLines;
			pInfo->FramingBits   = ISDN_FRAMING_BITS;
			pInfo->HighestAcceptableAddress = HighestAddress;
			cbWritten = sizeof *pInfo;
			break;
		}

		case OID_WAN_GET_LINK_INFO:
		{
			PNDIS_WAN_GET_LINK_INFO const pInfo = pData;
			PISDN_CALL const pCall = pInfo->NdisLinkHandle;
			ASSERT( pCall->Type == ISDN_TYPE_CALL );
			DigiDump( DIGIWANOID, ( "Isdn!WanQuery: OID_WAN_GET_LINK_INFO, pAdapter 0x%x, hLink\n", pAdapter, pInfo->NdisLinkHandle ) );
			pInfo->MaxSendFrameSize    = pCall->MaxSendFrameSize;
			pInfo->MaxRecvFrameSize    = pCall->MaxRecvFrameSize;
			pInfo->HeaderPadding       = pCall->HeaderPadding;
			pInfo->TailPadding         = pCall->TailPadding;
			pInfo->SendFramingBits     = pCall->SendFramingBits;
			pInfo->RecvFramingBits     = pCall->RecvFramingBits;
			pInfo->SendCompressionBits = pCall->SendCompressionBits;
			pInfo->RecvCompressionBits = pCall->RecvCompressionBits;
			cbWritten = sizeof *pInfo;
			break;
		}

		case OID_WAN_LINE_COUNT:
		{
			PULONG const pLineCount = pData;
			ASSERT( cbData >= sizeof *pLineCount );
			DigiDump( DIGIWANOID, ( "Isdn!WanQuery: OID_WAN_LINE_COUNT, pAdapter 0x%x\n", pAdapter ) );
			*pLineCount = pAdapter->nLines;
			cbWritten = sizeof *pLineCount;
			break;
		}

		default:
			DigiDump( DIGIWARN, ( "ISDN!WanQuery: Unsupported Oid 0x%08x on pAdapter 0x%x\n", Oid, pAdapter ) );
			Status = NDIS_STATUS_NOT_SUPPORTED;
			break;
	}

	*pcbWritten = cbWritten;
	*pcbNeeded  = cbNeeded;
	return Status;
}


NDIS_STATUS
IsdnWanSet(
	IN PISDN_ADAPTER pAdapter,
	IN NDIS_OID      Oid,
	IN PVOID         pData,
	IN ULONG         cbData,
	OUT PULONG       pcbRead,
	OUT PULONG       pcbNeeded )
/*++

Description:

	Handle all WAN Set OID requests.

--*/
{
	NDIS_STATUS Status = NDIS_STATUS_SUCCESS;	// Assume success!
	ULONG cbRead = 0;
	ULONG cbNeeded  = 0;
//	DigiDump( DIGIOID, ( "ISDN!WanSet: pAdapter 0x%x, Oid 0x%08x\n", pAdapter, Oid ) );

	switch ( Oid )
	{
		case OID_WAN_PROTOCOL_TYPE:
		{
			DigiDump( DIGIWANOID, ( "Isdn!WanSet: OID_WAN_PROTOCOL_TYPE, pAdapter 0x%x\n", pAdapter ) );
			// Ignore it
			cbRead = cbData;
			break;
		}

		case OID_WAN_HEADER_FORMAT:
		{
			PNDIS_WAN_HEADER_FORMAT const pFormat = pData;
			DigiDump( DIGIWANOID, ( "Isdn!WanSet: OID_WAN_HEADER_FORMAT, pAdapter 0x%x\n", pAdapter ) );
			if ( *pFormat != NdisWanHeaderNative )
				Status = NDIS_STATUS_FAILURE;
			cbRead = sizeof *pFormat;
			break;
		}

		case OID_WAN_SET_LINK_INFO:
		{
			PNDIS_WAN_SET_LINK_INFO const pInfo = pData;
			PISDN_CALL const pCall = pInfo->NdisLinkHandle;
			ASSERT( pCall->Type == ISDN_TYPE_CALL );
			DigiDump( DIGIWANOID, ( "Isdn!WanSet: OID_WAN_SET_LINK_INFO, pAdapter 0x%x\n"
			                        "   Send: FrameSize 0x%08x, FramingBits 0x%08x, CompressionBits 0x%08x\n"
			                        "   Recv: FrameSize 0x%08x, FramingBits 0x%08x, CompressionBits 0x%08x\n",
			                        pAdapter, 
			                        pInfo->MaxSendFrameSize, pInfo->SendFramingBits, pInfo->SendCompressionBits,
			                        pInfo->MaxRecvFrameSize, pInfo->RecvFramingBits, pInfo->RecvCompressionBits ) );

			pCall->MaxSendFrameSize    = pInfo->MaxSendFrameSize;
			pCall->MaxRecvFrameSize    = pInfo->MaxRecvFrameSize;
			pCall->SendFramingBits     = pInfo->SendFramingBits;
			pCall->RecvFramingBits     = pInfo->RecvFramingBits;
			pCall->SendCompressionBits = pInfo->SendCompressionBits;
			pCall->RecvCompressionBits = pInfo->RecvCompressionBits;
			cbRead = sizeof *pInfo;
			break;
		}

		default:
			DigiDump( DIGIWARN, ( "ISDN!WanSet: Unsupported Oid 0x%08x on pAdapter 0x%x\n", Oid, pAdapter ) );
			Status = NDIS_STATUS_INVALID_OID;
			break;
	}

	*pcbRead   = cbRead;
	*pcbNeeded = cbNeeded;
	return Status;
}


VOID
IsdnWanLineup(
	IN PISDN_CALL pCall,
	IN HTAPI_CALL htCall,
	IN ULONG      LinkSpeed )
/*++

Description:

	Send a Lineup indication to NdisWan.  Must only be called from within an Ndis 
	Context.

--*/
{
	NDIS_MAC_LINE_UP Lineup = { 0 };

	DigiDump( DIGIWANEVENT, ( "ISDN!WanLineup: pCall 0x%x, htCall 0x%x, LinkSpeed %d\n", pCall, htCall, LinkSpeed ) );

	Lineup.LinkSpeed           = LinkSpeed / 100;
	Lineup.Quality             = NdisWanReliable;
	Lineup.SendWindow          = ISDN_SEND_WINDOW;
	Lineup.ConnectionWrapperID = (HANDLE)htCall;
	Lineup.NdisLinkHandle      = pCall;
	Lineup.NdisLinkContext     = NULL;

	NdisMIndicateStatus( pCall->pAdapter->hMiniport, NDIS_STATUS_WAN_LINE_UP, &Lineup, sizeof Lineup );
	ASSERT( Lineup.NdisLinkContext != NULL );
	pCall->hLink = Lineup.NdisLinkContext;
	DigiDump( DIGIWANEVENT, ( "ISDN!WanLineup: returned hLink 0x%x\n", pCall->hLink ) );
	NdisMIndicateStatusComplete( pCall->pAdapter->hMiniport ); 
}


VOID
IsdnWanLinedown( 
	IN PISDN_CALL pCall )
/*++

Description:

	Send a Linedown indication to NdisWan.  Must only be called from within an Ndis 
	Context.

--*/
{
	NDIS_MAC_LINE_DOWN Linedown = { 0 };

	DigiDump( DIGIWANEVENT, ( "ISDN!WanLinedown: pCall 0x%x, htCall 0x%x, hLink 0x%x\n", pCall, pCall->htCall, pCall->hLink ) );

	// hLink is initialized in Lineup, cleared in Linedown.  Up/Down indications must 
	// be symmetric, e.g. one and only one linedown can be indicated for each lineup.
	if ( pCall->hLink )	
	{
		Linedown.NdisLinkContext = pCall->hLink;
		NdisMIndicateStatus( pCall->pAdapter->hMiniport, NDIS_STATUS_WAN_LINE_DOWN, &Linedown, sizeof Linedown );
		pCall->hLink = NULL;
		NdisMIndicateStatusComplete( pCall->pAdapter->hMiniport ); 
	}
}
