/*++
*******************************************************************************
* 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:

   ppplisten.c

Abstract:

   ISDN firmware API requires a seperate channel or stream posting listens, called the 
   listen stream.  All incoming calls are indicated and handled via the listen stream.
   This module is that code.


--*/

#include "digippp.h"
#include "wan_proto.h"
#include "wan_control.h"

STATIC DIGI_PPP_EVENT_HANDLERS PPPMsgHandlers;

NTSTATUS
PPPStartListening(
	PDIGI_PPP_ADAPTER pAdapter )
/*++

Description:

	Open stream, send listen request and startup Rx Engine to receive incoming calls.

--*/
{
	NTSTATUS Status;
	PDIGI_PPP_LINE pLine;
	DigiDump( DIGILISTEN, ( "PPP!StartListening: pAdapter 0x%x\n", pAdapter ) );
	InitializeListHead( &pAdapter->Listen.OfferingListHead );

	//PARAG - TODO - get the stream name in the buffer
	{
		ULONG Error;
		Status = DsOpen( pAdapter->hDevice, pAdapter->LineName, pAdapter, NULL, 0, &pAdapter->hStream, &Error );
		if ( NT_ERROR( Status ) )
		{
			DigiDump( DIGIWARN, ( "PPPStartListen: DsOpen failed, status 0x%x, error 0x%x\n", Status, Error ) );
		}
	}




// Send WAN_SID
	{
		struct wan_sid sid = {0};
		sid.wan_type = WAN_SID;
		sid.wan_snid = pAdapter->Snid;


		Status = DsPutMsg( pAdapter->hStream, &sid, sizeof (sid) , NULL,
								0,DS_PRIORITY_LOW );
		ASSERT( NT_SUCCESS( Status ) );
	   		
	}

 



	
	// Configure the Line  - Baud Clocking etc.
	// Parag - TODO  - we have only one line for now. Might have to make
	// changes for CSU-DSU version
	
	// TODO recheck these parameters. 

	pLine =	&pAdapter->pLines[0];
	pLine->hStream = pAdapter->hStream;
	pLine->snid = pAdapter->Snid;
	pLine->nrzi = pAdapter->nrzi;
	pLine->clocking = pAdapter->Clocking;
	pLine->lineSpeed = pAdapter->BaudRate;
	pLine->maxFrameSize = pAdapter->maxFrameSize;
	
	if ( NT_SUCCESS( Status ) )
		Status = MdmConfigureLine(pLine);
															 
	if ( NT_SUCCESS( Status ) ) 
	{
		PDIGI_PPP_MDMENGINE	pEngine = &pAdapter->Listen.Engine;
		NdisZeroMemory( pEngine, sizeof *pEngine );
		pAdapter->DispatchTable = PPPMsgHandlers;
		pEngine->pAdapter = pAdapter;
		pEngine->snid = pAdapter->Snid;
		Status = MdmEngineStart( pEngine,pAdapter->hStream, &pAdapter->DispatchTable);
	}
	if ( NT_ERROR( Status ) )
		MdmEngineStop( &pAdapter->Listen.Engine );

	return Status;
}


VOID
PPPStopListening(
	PDIGI_PPP_ADAPTER pAdapter )
/*++

Description:

	Stops listening for incoming calls.  Stop RxEngine on Listen stream and close the
	stream.  This is called when shutting down the adapter.

--*/
{
	DigiDump( DIGILISTEN, ( "PPP!StopListening: pAdapter 0x%x\n", pAdapter ) );
	MdmEngineStop(&pAdapter->Listen.Engine);

}


VOID
PPPListenOnCDActive( PDIGI_PPP_ADAPTER pAdapter,
					 ULONG line	 )
/*++

Description:

	Called to process a received XN_CONNECT message which signals an incoming call.  If
	we like the bearer caps, etc., offer the call up to Tapi.

--*/
{
	PDIGI_PPP_MDMENGINE pEngine ;
	PDIGI_PPP_CALL pCall = pAdapter->pLines[line].pCall;

	DigiDump( DIGILISTEN, ( "PPP!OnConnect: pAdapter 0x%x,line 0x%x\n", pAdapter,  line) );

	ASSERT( MmIsAddressValid( pAdapter ) );
	ASSERT( pAdapter->Type == DIGI_PPP_TYPE_ADAPTER );

  

// This should happen only on a incoming call 	
	if (pCall == NULL)
		pCall = PPPCallConstruct( pAdapter, line );
	

	if ( pCall )
	{
	  
		AdapterAcquireLock( pAdapter );
		InsertTailList( &pAdapter->Listen.OfferingListHead, &pCall->OfferingListEntry );
		AdapterReleaseLock( pAdapter );
		PPPCallOffer( pCall );
		pCall->informOnCDInactive = TRUE;
		pCall->informOnCDActive = FALSE;

	}
	else
	{
		// Couldn't accept call.  Reject it.
		DigiDump( DIGIWARN, ( "PPP!ListenOnConnect: CallConstruct failed, rejecting call!\n" ) );
//		XnConnend( pAdapter, pAdapter, pAdapter->Listen.hStream, ChanIndex, Channel );
		
	}
}




STATIC PDIGI_PPP_CALL 
FindOfferedCall( 
	IN PDIGI_PPP_ADAPTER pAdapter,
	IN ULONG         ChanIndex,
	IN ULONG         Channel )
/*++

Description

	Find call on the offering list which matches the ChanIndex and Channel.
	Remove it from the list and return it.

--*/
{
	PDIGI_PPP_CALL pCall = NULL;
	AdapterAcquireLock( pAdapter );
	{
		PLIST_ENTRY pHead = &pAdapter->Listen.OfferingListHead;
		PLIST_ENTRY pEntry = pAdapter->Listen.OfferingListHead.Flink;
		while ( pEntry != pHead )
		{
			PDIGI_PPP_CALL pc = CONTAINING_RECORD( pEntry, DIGI_PPP_CALL, OfferingListEntry );
			if ( pc->Incoming.ChanIndex == ChanIndex && pc->Incoming.Channel == Channel )
			{
				RemoveEntryList( pEntry );
				// Why call initializeListHead here?  Because, RemoveEntryList will be
				// called at close of the call (isdncall.c, case CALL_THREAD_CLOSE:) and
				// cannot be called multiple times!  Initializing the structure to empty
				// causes any subsequent RemoveListEntry calls to do nothing harmful.
				InitializeListHead( pEntry );
				pCall = pc;
				break;
			}
		}
	}
	AdapterReleaseLock( pAdapter );
	return pCall;
}



VOID
PPPListenOnConnend( PDIGI_PPP_ADAPTER pAdapter,
					ULONG line)
/*++

Description:

	Called to process an incoming XN_CONNEND indication.  When received on the listen
	stream, it indicates the remote has timed out or given up on us answering an 
	incoming call.  Find the call on our offering list and tell Tapi it's been 
	disconnected.

--*/
{

	PDIGI_PPP_CALL pCall;
	DigiDump( DIGILISTEN, ( "PPP!ListenOnConnend: pAdapter 0x%x\n", pAdapter ) );

	ASSERT( MmIsAddressValid( pAdapter ) );
	ASSERT( pAdapter->Type == DIGI_PPP_TYPE_ADAPTER );

		pCall =  pAdapter->pLines[line].pCall;
	if ( pCall )
	{
		PPPCallOnConnend( pCall);
		pCall->informOnCDInactive = FALSE;
		pCall->informOnCDActive = TRUE;
	}
	else
	{
		DigiDump( DIGIWARN, ( "PPP!ListenOnConnend: Call not found, pAdapter 0x%x\n", pAdapter ) );
	}
}





// Dispatch table used by MdmEngine.  Calls these handlers for incoming messages.
DIGI_PPP_EVENT_HANDLERS PPPMsgHandlers = 
{
	PPPListenOnCDActive,
	PPPListenOnConnend,
	PPPCallOnData
};
