summaryrefslogtreecommitdiffstats
path: root/private/ntos/nbt/vxd/tdiout.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nbt/vxd/tdiout.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to '')
-rw-r--r--private/ntos/nbt/vxd/tdiout.c601
1 files changed, 601 insertions, 0 deletions
diff --git a/private/ntos/nbt/vxd/tdiout.c b/private/ntos/nbt/vxd/tdiout.c
new file mode 100644
index 000000000..147bcb785
--- /dev/null
+++ b/private/ntos/nbt/vxd/tdiout.c
@@ -0,0 +1,601 @@
+/*++
+
+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 );
+}
+
+