mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
601 lines
16 KiB
601 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1989-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Tdiout.c
|
|
|
|
Abstract:
|
|
|
|
|
|
This file represents the TDI interface on the bottom edge of NBT.
|
|
The procedures herein conform to the TDI I/F spec. and then convert
|
|
the information to NT specific Irps etc. This implementation can be
|
|
changed out to run on another OS.
|
|
|
|
Author:
|
|
|
|
Jim Stewart (Jimst) 10-2-92
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <nbtprocs.h> // procedure headings
|
|
|
|
// function prototypes for completion routines used in this file
|
|
VOID
|
|
SendComplete(
|
|
PVOID pContext,
|
|
TDI_STATUS tdistatus,
|
|
UINT cbSentSize
|
|
);
|
|
VOID
|
|
TcpConnectComplete(
|
|
PVOID pContext,
|
|
TDI_STATUS tdistatus,
|
|
PVOID pv
|
|
);
|
|
|
|
VOID DisconnectWaitComplete( PVOID pContext,
|
|
TDI_STATUS status,
|
|
ULONG Extra ) ;
|
|
|
|
void VxdDelayedCallHandler( struct CTEEvent *pEvent, void * pContext ) ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
TdiSendDatagram(
|
|
IN PTDI_REQUEST pRequest,
|
|
IN PTDI_CONNECTION_INFORMATION pSendDgramInfo,
|
|
IN ULONG SendLength,
|
|
OUT PULONG pSentSize,
|
|
IN tBUFFER * pSendBuffer,
|
|
IN ULONG SendFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sends a datagram to the transport
|
|
|
|
Arguments:
|
|
|
|
pSendBuffer - this is really an Mdl in NT land. It must be tacked on
|
|
the end of the Mdl created for the Nbt datagram header.
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
{
|
|
TDI_STATUS tdistatus = TDI_SUCCESS ;
|
|
PTDI_SEND_CONTEXT psendCont = NULL ;
|
|
|
|
if ( !GetSendContext( &psendCont ) )
|
|
{
|
|
tdistatus = STATUS_INSUFFICIENT_RESOURCES ;
|
|
goto ErrorExit ;
|
|
}
|
|
|
|
//
|
|
// Save away the old completion routine and context and replace them
|
|
// with new ones. The new completion routines will call the old ones
|
|
// if they are non-NULL and then free the structure.
|
|
//
|
|
psendCont->OldRequestNotifyObject = pRequest->RequestNotifyObject ;
|
|
psendCont->OldContext = pRequest->RequestContext ;
|
|
psendCont->NewContext = NULL ;
|
|
pRequest->RequestContext = psendCont ;
|
|
|
|
//
|
|
// Set the send completion callback
|
|
//
|
|
pRequest->RequestNotifyObject = SendComplete;
|
|
|
|
InitNDISBuff( &psendCont->ndisHdr,
|
|
pSendBuffer->pDgramHdr,
|
|
pSendBuffer->HdrLength,
|
|
&psendCont->ndisData1 ) ;
|
|
|
|
InitNDISBuff( &psendCont->ndisData1,
|
|
pSendBuffer->pBuffer,
|
|
pSendBuffer->Length,
|
|
NULL ) ;
|
|
|
|
tdistatus = TdiVxdSendDatagram( pRequest,
|
|
pSendDgramInfo,
|
|
SendLength,
|
|
pSentSize,
|
|
&psendCont->ndisHdr ) ;
|
|
|
|
if ( !NT_SUCCESS( tdistatus ) )
|
|
goto ErrorExit ;
|
|
|
|
return tdistatus ;
|
|
|
|
ErrorExit:
|
|
|
|
DbgPrint("TdiSendDatagram ErrorExit: tdistatus= ") ;
|
|
DbgPrintNum( tdistatus ) ;
|
|
DbgPrint("\n\r") ;
|
|
|
|
//
|
|
// Call *our* completion routine which frees memory etc.
|
|
//
|
|
if ( psendCont && pRequest->RequestNotifyObject )
|
|
{
|
|
((NBT_COMPLETION)pRequest->RequestNotifyObject)(
|
|
psendCont,
|
|
tdistatus,
|
|
0 ) ;
|
|
|
|
return( STATUS_PENDING );
|
|
}
|
|
|
|
return tdistatus ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
SendComplete(
|
|
PVOID pContext,
|
|
TDI_STATUS tdistatus,
|
|
UINT cbSentSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles the completion of a datagram/session send to the
|
|
transport. It must call the client completion routine and free the TDI_SEND_CONTEXT
|
|
structure pointed at by pContext.
|
|
|
|
Note that this routine may also be called if an error is returned from
|
|
the send call. This is done to localize cleanup.
|
|
|
|
Arguments:
|
|
|
|
pContext - Pointer to a TDI_SEND_CONTEXT
|
|
tdistatus - Completion status of the TDI request
|
|
cbSentSize- Bytes taken by TDI
|
|
|
|
--*/
|
|
{
|
|
PTDI_SEND_CONTEXT psendCont = pContext ;
|
|
if ( tdistatus != TDI_SUCCESS )
|
|
{
|
|
DbgPrint("SendComplete: TDI Error reported: 0x") ;
|
|
DbgPrintNum( tdistatus ) ;
|
|
DbgPrint("\r\n") ;
|
|
}
|
|
|
|
if ( psendCont )
|
|
{
|
|
if ( psendCont->OldRequestNotifyObject )
|
|
{
|
|
//
|
|
// This calls the name server datagram completion routine which
|
|
// in turn will call CTEIoComplete (VxdIoComplete) which will call
|
|
// the NCB post routine (and fill out the NCB)
|
|
//
|
|
psendCont->OldRequestNotifyObject( psendCont->OldContext,
|
|
tdistatus,
|
|
cbSentSize ) ;
|
|
}
|
|
|
|
FreeSendContext( psendCont ) ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
TdiConnect(
|
|
IN PTDI_REQUEST pRequest,
|
|
IN ULONG lTimeout,
|
|
IN PTDI_CONNECTION_INFORMATION pSendInfo,
|
|
OUT PVOID pIrp //IN PTDI_CONNECTION_INFORMATION pReturnInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sends a connect request to the tranport provider, to setup
|
|
a connection to the other side...
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
{
|
|
TDI_STATUS status ;
|
|
DbgPrint("TdiConnect Entered\n\r") ;
|
|
status = TdiVxdConnect( pRequest,
|
|
(PVOID)lTimeout,
|
|
pSendInfo,
|
|
NULL ) ; // pReturnInfo) ;
|
|
|
|
if ( !NT_SUCCESS( status ) )
|
|
{
|
|
DbgPrint("TdiVxdConnect: Returned error " ) ;
|
|
DbgPrintNum( status ) ;
|
|
DbgPrint("\n\r") ;
|
|
|
|
//
|
|
// call the completion routine with this status
|
|
//
|
|
//
|
|
(*((NBT_COMPLETION)pRequest->RequestNotifyObject))
|
|
((PVOID)pRequest->RequestContext,
|
|
status,
|
|
0L);
|
|
return STATUS_PENDING;
|
|
}
|
|
else
|
|
{
|
|
DbgPrint("TdiVxdConnect - Connection ID: 0x") ;
|
|
DbgPrintNum( (ULONG) pRequest->Handle.ConnectionContext ) ; DbgPrint("\r\n") ;
|
|
}
|
|
|
|
return status ;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
TdiDisconnect(
|
|
IN PTDI_REQUEST pRequest,
|
|
IN PVOID lTimeout,
|
|
IN ULONG Flags,
|
|
IN PTDI_CONNECTION_INFORMATION pSendInfo,
|
|
IN PCTE_IRP pClientIrp,
|
|
IN BOOLEAN Wait
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sends a connect request to the tranport provider, to setup
|
|
a connection to the other side...
|
|
|
|
Arguments:
|
|
|
|
Wait is only used for NT (used in case when deleting address object
|
|
with open connections, which Vxd doesn't allow due to Netbios spec).
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
{
|
|
TDI_STATUS status ;
|
|
DbgPrint("TdiDisconnect Entered\n\r") ;
|
|
DbgPrint("TdiDisconnect - Disconnecting Connection ID: 0x") ;
|
|
DbgPrintNum( (ULONG) pRequest->Handle.ConnectionContext ) ; DbgPrint("\r\n") ;
|
|
|
|
ASSERT( Flags <= 0xffff ) ;
|
|
status = TdiVxdDisconnect( pRequest,
|
|
lTimeout,
|
|
(ushort) Flags,
|
|
pSendInfo,
|
|
NULL ) ;
|
|
|
|
if ( !NT_SUCCESS( status ) )
|
|
{
|
|
DbgPrint("TdiVxdConnect: Returned error " ) ;
|
|
DbgPrintNum( status ) ;
|
|
DbgPrint("\n\r") ;
|
|
}
|
|
|
|
return status ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
TdiSend(
|
|
IN PTDI_REQUEST pRequest,
|
|
IN USHORT sFlags,
|
|
IN ULONG SendLength,
|
|
OUT PULONG pSentSize,
|
|
IN tBUFFER *pBuff,
|
|
IN ULONG SendFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sends a packet to the transport on a TCP connection
|
|
|
|
If this is a chain send (SendFlags & CHAIN_SEND_FLAG) then pBuff will
|
|
point to a tBUFFERCHAINSEND (which contains a tBUFFER as its first element).
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
{
|
|
TDI_STATUS tdistatus = TDI_SUCCESS ;
|
|
PTDI_SEND_CONTEXT psendCont = NULL ;
|
|
tBUFFERCHAINSEND * pSendBuff = (tBUFFERCHAINSEND*) pBuff ;
|
|
PNDIS_BUFFER pndis2 = NULL ;
|
|
PNDIS_BUFFER pndis1 = NULL ;
|
|
DbgPrint("TdiSend Entered - sending 0x") ; DbgPrintNum( SendLength ) ;
|
|
DbgPrint(" bytes\r\n") ;
|
|
|
|
if ( !GetSendContext( &psendCont ))
|
|
{
|
|
tdistatus = STATUS_INSUFFICIENT_RESOURCES ;
|
|
if ( pRequest->RequestNotifyObject )
|
|
{
|
|
((NBT_COMPLETION)pRequest->RequestNotifyObject)(
|
|
pRequest->RequestContext,
|
|
tdistatus,
|
|
0 ) ;
|
|
}
|
|
return tdistatus ;
|
|
}
|
|
|
|
//
|
|
// Save away the old completion routine and context and replace them
|
|
// with new ones. The new completion routines will call the old ones
|
|
// if they are non-NULL and then free the structure.
|
|
//
|
|
psendCont->OldRequestNotifyObject = pRequest->RequestNotifyObject ;
|
|
psendCont->OldContext = pRequest->RequestContext ;
|
|
psendCont->NewContext = NULL ;
|
|
pRequest->RequestContext = psendCont ;
|
|
|
|
//
|
|
// Set the send completion callback
|
|
//
|
|
pRequest->RequestNotifyObject = SendComplete ;
|
|
|
|
//
|
|
// Build the ndis buffer chain (Header and data)
|
|
//
|
|
|
|
if ( (SendFlags & CHAIN_SEND_FLAG) && pSendBuff->Length2 )
|
|
{
|
|
InitNDISBuff( &psendCont->ndisData2,
|
|
pSendBuff->pBuffer2,
|
|
pSendBuff->Length2,
|
|
NULL ) ;
|
|
pndis2 = &psendCont->ndisData2 ;
|
|
}
|
|
|
|
if ( pSendBuff->tBuff.Length && (SendLength > pSendBuff->tBuff.HdrLength) )
|
|
{
|
|
InitNDISBuff( &psendCont->ndisData1,
|
|
pSendBuff->tBuff.pBuffer,
|
|
pSendBuff->tBuff.Length,
|
|
pndis2 ) ;
|
|
pndis1 = &psendCont->ndisData1 ;
|
|
}
|
|
|
|
InitNDISBuff( &psendCont->ndisHdr,
|
|
pSendBuff->tBuff.pDgramHdr,
|
|
pSendBuff->tBuff.HdrLength,
|
|
pndis1 ) ;
|
|
|
|
tdistatus = TdiVxdSend( pRequest,
|
|
sFlags,
|
|
SendLength,
|
|
&psendCont->ndisHdr ) ;
|
|
|
|
if ( !NT_SUCCESS( tdistatus ) )
|
|
goto ErrorExit ;
|
|
else
|
|
*pSentSize = SendLength ;
|
|
|
|
return tdistatus ;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Call *our* completion routine which frees memory etc.
|
|
//
|
|
if ( psendCont && pRequest->RequestNotifyObject )
|
|
{
|
|
((NBT_COMPLETION)pRequest->RequestNotifyObject)(
|
|
psendCont,
|
|
tdistatus,
|
|
0 ) ;
|
|
}
|
|
|
|
DbgPrint("TdiSend: returning ") ;
|
|
DbgPrintNum( tdistatus ) ;
|
|
DbgPrint("\n\r") ;
|
|
return tdistatus ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: VxdScheduleDelayedCall
|
|
|
|
SYNOPSIS: Schedules a callback at some later time
|
|
|
|
ENTRY: pClientContext - Context to pass callback
|
|
CallBackRoutine - Routine to call
|
|
|
|
RETURNS: STATUS_PENDING if successfully scheduled
|
|
|
|
NOTES: This is aliased to CTEQueueForNonDispProcessing.
|
|
|
|
The memory for the DCC is freed by the application
|
|
|
|
HISTORY:
|
|
Johnl 2-Sep-1993 Created
|
|
|
|
********************************************************************/
|
|
|
|
NTSTATUS VxdScheduleDelayedCall( tDGRAM_SEND_TRACKING * pTracker,
|
|
PVOID pClientContext,
|
|
PVOID ClientCompletion,
|
|
PVOID CallBackRoutine,
|
|
tDEVICECONTEXT *pDeviceContext )
|
|
{
|
|
CTELockHandle OldIrq;
|
|
PDELAYED_CALL_CONTEXT pDCC = CTEAllocMem( sizeof( DELAYED_CALL_CONTEXT )) ;
|
|
|
|
if ( !pDCC )
|
|
return STATUS_INSUFFICIENT_RESOURCES ;
|
|
|
|
ASSERT( CallBackRoutine != NULL ) ;
|
|
|
|
pDCC->dc_WIC.pTracker = pTracker ;
|
|
pDCC->dc_WIC.pClientContext = pClientContext ;
|
|
pDCC->dc_WIC.ClientCompletion = ClientCompletion ;
|
|
pDCC->dc_Callback = CallBackRoutine ;
|
|
pDCC->pDeviceContext = pDeviceContext;
|
|
|
|
//
|
|
// put this event on the deviceContext queue if we know the devicecontext
|
|
// otherwise, on the nbtconfig queue. This allows us to cancel the event
|
|
// later if we wish to (e.g. adapter goes away in pnp, or lease expires)
|
|
// if the adapter is marked as going down, don't schedule an event but
|
|
// execute it synchronously.
|
|
//
|
|
if (pDeviceContext)
|
|
{
|
|
ASSERT( pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT );
|
|
|
|
if (!pDeviceContext->fDeviceUp)
|
|
{
|
|
pDCC->dc_Callback( pDCC ) ;
|
|
|
|
DbgPrint("VxdScheduleDelayedCall: device going down,executing now\r\n") ;
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
else
|
|
{
|
|
CTESpinLock(pDeviceContext,OldIrq);
|
|
InsertTailList(&pDeviceContext->DelayedEvents,&pDCC->Linkage);
|
|
CTESpinFree(pDeviceContext,OldIrq);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CTESpinLock(&NbtConfig,OldIrq);
|
|
InsertTailList(&NbtConfig.DelayedEvents,&pDCC->Linkage);
|
|
CTESpinFree(&NbtConfig,OldIrq);
|
|
}
|
|
|
|
CTEInitEvent( &pDCC->dc_event, VxdDelayedCallHandler ) ;
|
|
|
|
CTEScheduleEvent( &pDCC->dc_event, pDCC) ;
|
|
|
|
return STATUS_PENDING ;
|
|
}
|
|
|
|
|
|
void VxdDelayedCallHandler( struct CTEEvent *pEvent, void * pContext )
|
|
{
|
|
PDELAYED_CALL_CONTEXT pDCC = pContext ;
|
|
CTELockHandle OldIrq;
|
|
tDEVICECONTEXT *pDeviceContext;
|
|
|
|
|
|
ASSERT( pDCC != NULL && pDCC->dc_Callback != NULL ) ;
|
|
|
|
pDeviceContext = pDCC->pDeviceContext;
|
|
|
|
if (pDeviceContext)
|
|
{
|
|
ASSERT( pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT );
|
|
CTESpinLock(pDeviceContext,OldIrq);
|
|
RemoveEntryList(&pDCC->Linkage);
|
|
CTESpinFree(pDeviceContext,OldIrq);
|
|
}
|
|
else
|
|
{
|
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|
RemoveEntryList(&pDCC->Linkage);
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|
}
|
|
|
|
pDCC->dc_Callback( pDCC ) ;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CancelAllDelayedEvents
|
|
|
|
SYNOPSIS: Since the device (or the entire vxd!) is going away,
|
|
cancel all the events that were queued to be scheduled
|
|
later. If a particular device context is going away (but
|
|
not the entire system) then execute all those events
|
|
synchronously.
|
|
|
|
ENTRY: pDeviceContext - the device context that's going away
|
|
NULL if the vxd is getting unloaded
|
|
|
|
RETURNS: TRUE if at least one event present and was cancelled
|
|
FALSE if there were no events queued.
|
|
|
|
HISTORY:
|
|
Koti Jan. 9, 95
|
|
|
|
********************************************************************/
|
|
|
|
BOOL
|
|
CancelAllDelayedEvents( tDEVICECONTEXT *pDeviceContext )
|
|
{
|
|
|
|
LIST_ENTRY *pHead;
|
|
LIST_ENTRY *pEntry;
|
|
PDELAYED_CALL_CONTEXT pDCC;
|
|
CTELockHandle OldIrq;
|
|
BOOL fAtLeastOne=FALSE;
|
|
|
|
|
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|
|
|
if (pDeviceContext)
|
|
pHead = &pDeviceContext->DelayedEvents;
|
|
else
|
|
pHead = &NbtConfig.DelayedEvents;
|
|
|
|
pEntry = pHead->Flink;
|
|
|
|
while (pEntry != pHead)
|
|
{
|
|
pDCC = CONTAINING_RECORD(pEntry,DELAYED_CALL_CONTEXT,Linkage);
|
|
pEntry = pEntry->Flink;
|
|
|
|
RemoveEntryList(&pDCC->Linkage);
|
|
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|
|
|
CTECancelEvent( &pDCC->dc_event );
|
|
|
|
//
|
|
// if only one device context is going away, execute the event now
|
|
//
|
|
if (pDeviceContext)
|
|
{
|
|
pDCC->dc_Callback( pDCC ) ;
|
|
}
|
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|
|
|
fAtLeastOne = TRUE;
|
|
}
|
|
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|
|
|
ASSERT( IsListEmpty( pHead ) );
|
|
|
|
return( fAtLeastOne );
|
|
}
|
|
|
|
|