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



Abstract:

  
Author:

   Michael Zarns

--*/

#include "digiX25.h"
#pragma hdrstop



STATIC VOID
X25PutComplete(
		IN PVOID    pOwner,
		IN HANDLE   Context,
		IN PVOID    pControl,
		IN ULONG    cbControl,
		IN PVOID    pData,
		IN ULONG    cbData,
		IN NTSTATUS IoStatus )
/*++

Description:

	Generic completion routine for PutMsgs with no data portion.  Does nothing.

--*/
{
	ASSERT( pOwner != NULL );
	ASSERT( Context == NULL );
	ASSERT( pControl != NULL );
	ASSERT( cbControl != 0 );
//	ASSERT( pData == NULL );
//	ASSERT( cbData == 0 );

	if (pData != NULL)
		DigiFreeMem(pData);

	if ( NT_ERROR( IoStatus ) )
	{
		DigiDump( DIGIWARN, ( "DXB:X25PutComplete pOwner 0x%x, pIoStatus 0x%x!\n", 
		          pOwner, IoStatus ) );
	}
}


STATIC NTSTATUS
X25ConnectIndication(
	HANDLE  hStream,
	ULONG   Snid,
	PUCHAR pRemoteAddress,
	IN ULONG AddressLength
 )
/*++

Description:

	Sends an N_CI request out.  Used when dialing.

--*/
{

	NTSTATUS Status;
	struct xcallf Connect;
	PUCHAR pExtraData;
	ULONG i;
	ULONG Offset;
/*
	if ( AddressLength == 0 || AddressLength > DTEMAXSIZE )
	{
		Status = NDIS_STATUS_FAILURE;
		goto Exit;
	}
	*/
	   
   //
   // Send down the connect request, which causes an X.25 CallRequest packet to
	// be sent.
	//

	pExtraData = DigiAllocMem( NonPagedPool, sizeof( UCHAR ) );
	if ( !pExtraData )
	{
		Status = NDIS_STATUS_RESOURCES;
		goto Exit;
	}

	*pExtraData = 0xCF; // PPP NLPID

	RtlZeroMemory( &Connect, sizeof(struct xcallf) );
	Connect.xl_type = XL_CTL;
	Connect.xl_command = N_CI;
	Connect.calledaddr.sn_id = Snid;
	Connect.calledaddr.aflags = EXT_ADDR;
	Connect.calledaddr.DTE_MAC.lsap_len = pRemoteAddress[AddressLength - 1] == 0 ?
		(UCHAR)AddressLength - 1 : (UCHAR)AddressLength;

	for ( Offset = 0, i = 0; i < Connect.calledaddr.DTE_MAC.lsap_len; i++ )
	{
		UCHAR Digit;
		
		if ( pRemoteAddress[i] < '0' || pRemoteAddress[i] > '9' )
			return( NDIS_STATUS_TAPI_INVALADDRESS );

		Digit = pRemoteAddress[i] ? pRemoteAddress[i] - '0' : 0;
		if ( i % 2 == 0 )
			Connect.calledaddr.DTE_MAC.lsap_add[Offset] = Digit << 4;
		else
			Connect.calledaddr.DTE_MAC.lsap_add[Offset++] |= Digit;
	}

	DigiDump( DIGICALL, (" lsap_len = %d \n", 
		Connect.calledaddr.DTE_MAC.lsap_len) );

	for ( i = 0; i < LSAPMAXSIZE; i++ )
		DigiDump( DIGICALL, (" lsap_add[%d] = 0x%x\n", i, 
		Connect.calledaddr.DTE_MAC.lsap_add[i]) );
   
	Status = DsPutMsgEx( hStream,
	                     (PVOID)&Connect, sizeof( Connect ),
	                     (PVOID)pExtraData, sizeof( UCHAR ),
	                     NULL, DS_PRIORITY_LOW, X25PutComplete );

	// The ConnectRequest we just passed down, will be accepted or rejected with an N_CC
	// or N_DI, respectively.  N_CC is received when an X.25 CallConfirm packet is
	// received.  N_DI when an X.25 ClearIndication packet is received.
   //

Exit:   
   return( Status );
}


 

STATIC NTSTATUS
X25ConnectConfirm(
	PVOID  hOwner,
	HANDLE hStream,
	ULONG  ChanIndex,
	ULONG  Channel )


/*	
 * Sends a N_CC down
 */

{



	PX25_CALL CallObject = hOwner;
	struct xccnff CallConfirm = {0};


	ASSERT( CallObject && CallObject->Type == X25_TYPE_CALL );
	DigiDump( DIGICALL, 
	          ( "Enter AnswerOpenComplete, Call 0x%x, Address 0x%x\n",
	          CallObject, CallObject->AddressID  ) );

	CallObject->hStream = hStream;

	   //
	   // Send an X.25 Call Confirm to answer the incoming call!
	   //


	CallConfirm.xl_type = XL_CTL;
	CallConfirm.xl_command = N_CC;
	CallConfirm.conn_id = CallObject->conn_id;
	// CallConfirm->CONS_call = 0;
	// CallConfirm->negotiate_qos = 0;

	return DsPutMsgEx( CallObject->hStream,
						(PVOID)&CallConfirm,
						sizeof( struct xccnff ),
						NULL, 0, NULL, DS_PRIORITY_LOW,
						X25PutComplete );
	

}


STATIC NTSTATUS
X25DisconnectIndication(
	PVOID  pOwner,
	HANDLE hStream,
	ULONG  ConnId
	 )
/*++

Description:

	Sends an N_DI request to the board.  
--*/
{
	NTSTATUS Status;

	struct xdiscf Disconnect = {0};


	Disconnect.xl_type = XL_CTL;
	Disconnect.xl_command = N_DI;
	Disconnect.conn_id = ConnId;

	
	return	Status = DsPutMsgEx( hStream,
	                    (PVOID)&Disconnect, sizeof( Disconnect ),
	                    NULL, 0,
	                    NULL, DS_PRIORITY_LOW,X25PutComplete );

}



   


STATIC NTSTATUS
X25Listen(
	PVOID  pOwner,
	HANDLE hStream,
	ULONG  Snid )
/*++

Description:

	Sends an XN_LISTEN request to the board.  Required to accept incoming calls.

--*/
{

	NDIS_STATUS Status;
	struct xlistenf Listen;
	PUCHAR pPPPData, pPADData;
//   struct xlistenf Listen;
//   UCHAR ExtraData[7];

	pPPPData = DigiAllocMem( NonPagedPool, 7 );
	pPADData = DigiAllocMem( NonPagedPool, 7 );
	if ( !pPPPData || !pPADData )
	{
		if ( pPPPData )
			DigiFreeMem( pPPPData );
		if ( pPADData )
			DigiFreeMem( pPADData );
		Status = NDIS_STATUS_RESOURCES;
		goto Exit;
	}

	// Send the Listen Request to listen for PPP (direct) connections
	NdisZeroMemory( &Listen, sizeof( struct xlistenf ) );
	Listen.xl_type = XL_CTL;
	Listen.xl_command = N_Xlisten;
	Listen.lmax = 256;
	Listen.l_snid = Snid;
   // Listen.l_result = 0;

	pPPPData[0] = X25_IDENTITY; // l_cumode
	pPPPData[1] = 1;            // l_culength
	pPPPData[2] = 0xCF;         // l_cubytes = PPP connection
	pPPPData[3] = X25_DONTCARE;

	DigiDump( DIGILISTEN, 
             ("ListenRequest: Sending ListenRequest for PPP connections\n") );

	Status = DsPutMsgEx( hStream, 
	                     (PVOID)&Listen, sizeof( struct xlistenf ), 
	                     pPPPData, 4,
	                     NULL, DS_PRIORITY_LOW,X25PutComplete );

	// Send the Listen Request to listen for PPP (direct) connections
	NdisZeroMemory( &Listen, sizeof( struct xlistenf ) );
	Listen.xl_type = XL_CTL;
	Listen.xl_command = N_Xlisten;
	Listen.lmax = 256;

	pPADData[0] = X25_STARTSWITH; // l_cumode
	pPADData[1] = 1;              // l_culength
	pPADData[2] = 0x01;           // l_cubytes = PAD == 0x01, 0x00, 0x00, 0x00
	// pPADData[3] = 0x00;        // 
	// pPADData[4] = 0x00;        // 
	// pPADData[5] = 0x00;        // 
	pPADData[3] = X25_DONTCARE;

	DigiDump( DIGILISTEN, 
             ("ListenRequest: Sending ListenRequest for PAD connections\n") );

	Status = DsPutMsgEx( hStream, 
	                     (PVOID)&Listen, sizeof( struct xlistenf ),
	                     pPADData, 4,
	                     NULL, DS_PRIORITY_LOW,X25PutComplete );

Exit:
	return( Status );

}

STATIC VOID
X25Interpreter(
	IN PVOID                pOwner, 
	IN PX25_EVENT_HANDLERS pDispatchTable,
	IN PVOID                pControl, 
	IN ULONG                cbControl, 
	IN PVOID                pData, 
	IN ULONG                cbData )
/*++

Description:

	Called by RxEngine to interpret and process a single incoming message from the card.

--*/
{

	S_X25_HDR * pMsgHeader = pControl;
	PX25_CALL CallObject=(PX25_CALL) pOwner;
	int i;
	if ( pMsgHeader != NULL )
	{
		// Control Messages
		switch ( pMsgHeader->xl_type )
		{

			case XL_CTL:
			{
				DigiDump( DIGILISTEN, ("XL_CTL: \n") );
				switch( pMsgHeader->xl_command )
				{
					case N_CI:	// X.25 Call Indication
					{
               //
               // Connect Indication.  Incoming call
               //
	               struct xcallf *pConnect = (PVOID)pControl;
			            
    	           DigiDump( DIGILISTEN, ("   N_CI: "
                                       "   conn_id = 0x%x\n"
                                       "   CONS_call = 0x%x\n"
                                       "   negotiate_qos = 0x%x\n"
                                       "   lsap_len = 0x%x\n"
                                       "   calledaddr.sn_id = '%c' 0x%x\n",
                                       pConnect->conn_id,
                                       pConnect->CONS_call,
                                       pConnect->negotiate_qos,
                                       pConnect->calledaddr.DTE_MAC.lsap_len,
                                       pConnect->calledaddr.sn_id,
                                       pConnect->calledaddr.sn_id) );

					DigiDump( DIGILISTEN, ("   Calledaddr.lsap_add: ") );
		               for ( i = 0; i < LSAPMAXSIZE; i++)
							DigiDump(DIGILISTEN,("%x-",pConnect->calledaddr.DTE_MAC.lsap_add[i]));
						DigiDump( DIGILISTEN, ("\n") );

						DigiDump( DIGILISTEN, ("   Callingaddr.lsap_add: ") );
						for ( i = 0; i < LSAPMAXSIZE; i++)
							DigiDump(DIGILISTEN,("%x-",pConnect->callingaddr.DTE_MAC.lsap_add[i]));
						DigiDump( DIGILISTEN, ("\n") );

		               if( pConnect->negotiate_qos )
        		       {
							DigiDump( DIGIX25, ("   negotiate_qos:"
                                          "      qos.reqtclass=0x%x\n"
                                          "      qos.locthroughput=0x%x\n"
                                          "      qos.remthroughput=0x%x\n"
                                          "      qos.reqminthruput=0x%x\n"
                                          "      qos.locminthru=0x%x\n"
                                          "      qos.remminthru=0x%x\n"
                                          "      qos.reqtransitdelay=0x%x\n"
                                          "      qos.transitdelay=0x%x\n"
                                          "      qos.reqmaxtransitdelay=0x%x\n"
                                          "      qos.acceptable=0x%x\n"
                                          "      qos.reqpriority=0x%x\n"
                                          "      qos.reqprtygain=0x%x\n"
                                          "      qos.reqprtykeep=0x%x\n",
                                          pConnect->qos.reqtclass,
                                          pConnect->qos.locthroughput,
                                          pConnect->qos.remthroughput,
                                          pConnect->qos.reqminthruput,
                                          pConnect->qos.locminthru,
                                          pConnect->qos.remminthru,
                                          pConnect->qos.reqtransitdelay,
                                          pConnect->qos.transitdelay,
                                          pConnect->qos.reqmaxtransitdelay,
                                          pConnect->qos.acceptable,
                                          pConnect->qos.reqpriority,
                                          pConnect->qos.reqprtygain,
                                          pConnect->qos.reqprtykeep) );
							DigiDump( DIGIX25, ("      qos.prtydata=0x%x\n"
                                          "      qos.prtygain=0x%x\n"
                                          "      qos.prtykeep=0x%x\n"
                                          "      qos.reqlowprtydata=0x%x\n"
                                          "      qos.reqlowprtygain=0x%x\n"
                                          "      qos.reqlowprtykeep=0x%x\n"
                                          "      qos.lowprtydata=0x%x\n"
                                          "      qos.lowprtygain=0x%x\n"
                                          "      qos.lowprtykeep=0x%x\n"
                                          "      qos.protection_type=0x%x\n"
                                          "      qos.prot_len=0x%x\n"
                                          "      qos.lowprot_len=0x%x\n"
                                          "      qos.reqexpedited=0x%x\n"
                                          "      qos.reqackservice=0x%x\n",
                                          pConnect->qos.prtydata,
                                          pConnect->qos.prtygain,
                                          pConnect->qos.prtykeep,
                                          pConnect->qos.reqlowprtydata,
                                          pConnect->qos.reqlowprtygain,
                                          pConnect->qos.reqlowprtykeep,
                                          pConnect->qos.lowprtydata,
                                          pConnect->qos.lowprtygain,
                                          pConnect->qos.lowprtykeep,
                                          pConnect->qos.protection_type,
                                          pConnect->qos.prot_len,
                                          pConnect->qos.lowprot_len,
                                          pConnect->qos.reqexpedited,
                                          pConnect->qos.reqackservice) );
						
					   
						
			            }  
						pDispatchTable->OnConnect(pOwner,pControl,pData);
						break;
					} // end case N_CI


					case N_CC:		// connect confirmation
						{
						struct xccnff *ConnectConfirm = (PVOID)pControl;
						DigiDump( DIGIX25, ("N_CC: conn_id = 0x%x\n"
                                       "      CONS_call = 0x%x\n"
                                       "      negotiate_qos = 0x%x\n"
                                       "      responder.sn_id = '%c' 0x%x\n",
                                       ConnectConfirm->conn_id,
                                       ConnectConfirm->CONS_call,
                                       ConnectConfirm->negotiate_qos,
                                       ConnectConfirm->responder.sn_id,
                                       ConnectConfirm->responder.sn_id) );

						DigiDump( DIGIX25, ( "DigiX25!X25Interpreter: N_CC on pOwner 0x%x\n", pOwner ) );
						pDispatchTable->OnConnack( pOwner,pControl,pData);
						}
						break;
				
						
					case N_DI:		// Disconnect Indication
						{
						
					   struct xdiscf *pDisconnect = (PVOID)pControl;

					   DigiDump( DIGIX25, ("%s\n"
				                           "   originator = 0x%x\n"
				                           "   reason = 0x%x\n"
				                           "   cause = 0x%x\n"
				                           "   diag = 0x%x\n"
				                           "   conn_id = 0x%x\n"
				                           "   indicated_qos = 0x%x\n",
				                           pMsgHeader->xl_command==N_DI?"N_DI":"N_Abort",
				                           pDisconnect->originator,
				                           pDisconnect->reason,
				                           pDisconnect->cause,
				                           pDisconnect->diag,
				                           pDisconnect->conn_id,
				                           pDisconnect->indicated_qos) );

						DigiDump( DIGIX25, ( "DigiX25!Interpreter: N_DI on pOwner 0x%x\n", pOwner ) );
						pDispatchTable->OnDisconn( pOwner ,pControl,pData);

						}
						break;


					case N_DC:		// Disconnect Confirmation
						DigiDump( DIGIX25, ( "DigiX25!Interpreter: N_DC on pOwner 0x%x\n", pOwner  ));
						pDispatchTable->OnConnend( pOwner,pControl,pData );
						break;

	
					 case N_Xlisten:	// Confirmation of previous XListen request
						{
						struct xlistenf *pListen = (PVOID)pControl;
						DigiDump( DIGIX25, ("N_Xlisten, lmax = 0x%x, l_result = 0x%x\n",
                                       pListen->lmax,
                                       pListen->l_result) );
			               break;
            			}  // end case N_Xlisten

					 case N_Xcanlis:	// Confirmation of previous listen cancel request
						{
						struct xcanlisf *pListenCancel = (PVOID)pControl;
						DigiDump( DIGIX25, ("N_Xcanlis, c_result = 0x%x\n",
                                       pListenCancel->c_result) );
						break;

						}  // end case N_Xcanlis
					 case N_PVC_ATTACH:
						DigiDump( DIGIERROR, ("*** X25Interpretor **** "
					                      "Unexpected N_PVC_ATTACH indication! ***\n") );
						break;


						case N_PVC_DETACH:
							DigiDump( DIGIERROR, ("*** X25Interpretor: "
					                      "Unexpected N_PVC_DETACH indication! ***\n") );
							break;
									
					default:
						DigiDump( DIGIX25|DIGIERROR, ( "X25!Interpreter: Unknown msg on pOwner 0x%x!\n",  pOwner ) );
						break;
				}
			RxEngineFreeData( pData );
			break;
			}
			case XL_DAT:
			{
			// Data Messages
				DigiDump( DIGIX25, ( "X25!Interpreter: Rx Data, pOwner 0x%x, pData 0x%x, cbData 0x%x\n", pOwner, pData, cbData ) );
				pDispatchTable->OnData( pOwner, pControl,cbControl, pData, cbData );
				break;
			}

			default:
				DigiDump( DIGIX25|DIGIERROR, ( "X25!Interpreter: Unknown msg on pOwner 0x%x!\n",  pOwner ) );
				break;

		}
	}
}


X25_CODEC  X25Dispatcher = 				// For stuff going to the board
{
	X25ConnectIndication,
	X25ConnectConfirm,
	X25DisconnectIndication,
	X25Listen,
	X25Interpreter,
	sizeof( union X25_primitives ),
	X25_DEVICE_NAME
};


VOID
X25DispatchInit(
	PX25_ADAPTER pAdapter )
/*++

Description:

	

--*/
{
	pAdapter->XnDispatch = X25Dispatcher;
}
