windows-nt/Source/XPSP1/NT/net/netbeui/sys/request.c
2020-09-26 16:20:57 +08:00

1378 lines
34 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1989, 1990, 1991 Microsoft Corporation
Module Name:
request.c
Abstract:
This module contains code which implements the TP_REQUEST object.
Routines are provided to create, destroy, reference, and dereference,
transport request objects.
Author:
David Beaver (dbeaver) 1 July 1991
Environment:
Kernel mode
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#ifdef RASAUTODIAL
#include <acd.h>
#include <acdapi.h>
#endif // RASAUTODIAL
//
// External variables
//
#ifdef RASAUTODIAL
extern BOOLEAN fAcdLoadedG;
extern ACD_DRIVER AcdDriverG;
//
// Imported routines
//
VOID
NbfNoteNewConnection(
PTP_CONNECTION Connection,
PDEVICE_CONTEXT DeviceContext
);
#endif // RASAUTODIAL
VOID
NbfTdiRequestTimeoutHandler(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
This routine is executed as a DPC at DISPATCH_LEVEL when a request
such as TdiSend, TdiReceive, TdiSendDatagram, TdiReceiveDatagram, etc.,
encounters a timeout. This routine cleans up the activity and cancels it.
Arguments:
Dpc - Pointer to a system DPC object.
DeferredContext - Pointer to the TP_REQUEST block representing the
request that has timed out.
SystemArgument1 - Not used.
SystemArgument2 - Not used.
Return Value:
none.
--*/
{
KIRQL oldirql;
PTP_REQUEST Request;
PTP_CONNECTION Connection;
#if DBG
LARGE_INTEGER time, difference;
#endif
PIO_STACK_LOCATION IrpSp;
PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
PDEVICE_CONTEXT DeviceContext;
Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
ENTER_NBF;
Request = (PTP_REQUEST)DeferredContext;
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint1 ("RequestTimeoutHandler: Entered, Request %lx\n", Request);
}
ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
Request->Flags &= ~REQUEST_FLAGS_TIMER;
if ((Request->Flags & REQUEST_FLAGS_STOPPING) == 0) {
#if DBG
KeQuerySystemTime (&time);
difference.QuadPart = time.QuadPart - (Request->Time).QuadPart;
NbfPrint1 ("RequestTimeoutHandler: Request timed out, queued for %ld seconds\n",
difference.LowPart / SECONDS);
#endif
//
// find reason for timeout
//
IrpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
if (IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) {
switch (IrpSp->MinorFunction) {
//
// none of these should time out.
//
case TDI_SEND:
case TDI_ACCEPT:
case TDI_SET_INFORMATION:
case TDI_SET_EVENT_HANDLER:
case TDI_SEND_DATAGRAM:
case TDI_RECEIVE_DATAGRAM:
case TDI_RECEIVE:
#if DBG
NbfPrint1 ("RequestTimeoutHandler: Request: %lx Timed out, and shouldn't have!\n",
Request);
#endif
ASSERT (FALSE);
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
NbfCompleteRequest (Request, STATUS_IO_TIMEOUT, 0);
break;
case TDI_LISTEN:
case TDI_CONNECT:
#if DBG
NbfPrint2 ("RequestTimeoutHandler: %s Failed, Request: %lx\n",
IrpSp->MinorFunction == TDI_LISTEN ?
"Listen" :
IrpSp->MinorFunction == TDI_CONNECT ?
"Connect" : "Disconnect",
Request);
#endif
Connection = (PTP_CONNECTION)(Request->Context);
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
//
// Since these requests are part of the connection
// itself, we just stop the connection and the
// request will get torn down then. If we get the
// situation where the request times out before
// it is queued to the connection, then the code
// that is about to queue it will check the STOPPING
// flag and complete it then.
//
// Don't stop the connection if an automatic connection
// is in progress.
//
#if DBG
DbgPrint("RequestTimeoutHandler: AUTOCONNECTING=0x%x\n", Connection->Flags2 & CONNECTION_FLAGS2_AUTOCONNECTING);
#endif
if (!(Connection->Flags2 & CONNECTION_FLAGS2_AUTOCONNECTING))
NbfStopConnection (Connection, STATUS_IO_TIMEOUT);
break;
case TDI_DISCONNECT:
//
// We don't create requests for TDI_DISCONNECT any more.
//
ASSERT(FALSE);
break;
case TDI_QUERY_INFORMATION:
DeviceContext = (PDEVICE_CONTEXT)IrpSp->FileObject->DeviceObject;
query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&IrpSp->Parameters;
IF_NBFDBG (NBF_DEBUG_DEVCTX) {
NbfPrint1 ("RequestTimeout: %lx:\n", DeviceContext);
}
//
// Determine if the request is done, or if we should
// requeue it.
//
--Request->Retries;
if (Request->Retries > 0) {
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
//
// Send another packet out, and restart the timer.
//
if (query->QueryType == TDI_QUERY_FIND_NAME) {
NbfSendQueryFindName (
DeviceContext,
Request);
} else if (query->QueryType == TDI_QUERY_ADAPTER_STATUS) {
PUCHAR SingleSR;
UINT SingleSRLength;
//
// Send the STATUS_QUERY frames out as
// single-route source routing.
//
// On a second status query this should
// really be sent directed, but currently we
// don't record the address anywhere.
//
MacReturnSingleRouteSR(
&DeviceContext->MacInfo,
&SingleSR,
&SingleSRLength);
NbfSendStatusQuery (
DeviceContext,
Request,
&DeviceContext->NetBIOSAddress,
SingleSR,
SingleSRLength);
} else {
ASSERT (FALSE);
}
} else {
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
//
// That's it, we retried enough, complete it.
//
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
RemoveEntryList (&Request->Linkage);
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
if (Request->BytesWritten > 0) {
NbfCompleteRequest (Request, STATUS_SUCCESS, Request->BytesWritten);
} else {
NbfCompleteRequest (Request, STATUS_IO_TIMEOUT, Request->BytesWritten);
}
}
break;
default:
#if DBG
NbfPrint2 ("RequestTimeoutHandler: Unknown Request Timed out, Request: %lx Type: %x\n",
Request, IrpSp->MinorFunction);
#endif
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
break;
} // end of switch
} else {
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
}
NbfDereferenceRequest ("Timeout", Request, RREF_TIMER); // for the timeout
} else {
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
NbfDereferenceRequest ("Timeout: stopping", Request, RREF_TIMER); // for the timeout
}
LEAVE_NBF;
return;
} /* RequestTimeoutHandler */
VOID
NbfAllocateRequest(
IN PDEVICE_CONTEXT DeviceContext,
OUT PTP_REQUEST *TransportRequest
)
/*++
Routine Description:
This routine allocates a request packet from nonpaged pool and initializes
it to a known state.
NOTE: This routine is called with the device context spinlock
held, or at such a time as synchronization is unnecessary.
Arguments:
DeviceContext - Pointer to the device context (which is really just
the device object with its extension) to be associated with the
address.
TransportRequest - Pointer to a place where this routine will return
a pointer to a transport request structure. It returns NULL if no
storage can be allocated.
Return Value:
None.
--*/
{
PTP_REQUEST Request;
if ((DeviceContext->MemoryLimit != 0) &&
((DeviceContext->MemoryUsage + sizeof(TP_REQUEST)) >
DeviceContext->MemoryLimit)) {
PANIC("NBF: Could not allocate request: limit\n");
NbfWriteResourceErrorLog(
DeviceContext,
EVENT_TRANSPORT_RESOURCE_LIMIT,
104,
sizeof(TP_REQUEST),
REQUEST_RESOURCE_ID);
*TransportRequest = NULL;
return;
}
Request = (PTP_REQUEST)ExAllocatePoolWithTag (
NonPagedPool,
sizeof (TP_REQUEST),
NBF_MEM_TAG_TP_REQUEST);
if (Request == NULL) {
PANIC("NBF: Could not allocate request: no pool\n");
NbfWriteResourceErrorLog(
DeviceContext,
EVENT_TRANSPORT_RESOURCE_POOL,
204,
sizeof(TP_REQUEST),
REQUEST_RESOURCE_ID);
*TransportRequest = NULL;
return;
}
RtlZeroMemory (Request, sizeof(TP_REQUEST));
DeviceContext->MemoryUsage += sizeof(TP_REQUEST);
++DeviceContext->RequestAllocated;
Request->Type = NBF_REQUEST_SIGNATURE;
Request->Size = sizeof (TP_REQUEST);
Request->ResponseBuffer = NULL;
Request->Provider = DeviceContext;
Request->ProviderInterlock = &DeviceContext->Interlock;
KeInitializeSpinLock (&Request->SpinLock);
KeInitializeDpc (&Request->Dpc, NbfTdiRequestTimeoutHandler, (PVOID)Request);
KeInitializeTimer (&Request->Timer); // set to not-signaled state.
*TransportRequest = Request;
} /* NbfAllocateRequest */
VOID
NbfDeallocateRequest(
IN PDEVICE_CONTEXT DeviceContext,
IN PTP_REQUEST TransportRequest
)
/*++
Routine Description:
This routine frees a request packet.
NOTE: This routine is called with the device context spinlock
held, or at such a time as synchronization is unnecessary.
Arguments:
DeviceContext - Pointer to the device context (which is really just
the device object with its extension) to be associated with the
address.
TransportRequest - Pointer to a transport request structure.
Return Value:
None.
--*/
{
ExFreePool (TransportRequest);
--DeviceContext->RequestAllocated;
DeviceContext->MemoryUsage -= sizeof(TP_REQUEST);
} /* NbfDeallocateRequest */
NTSTATUS
NbfCreateRequest(
IN PIRP Irp,
IN PVOID Context,
IN ULONG Flags,
IN PMDL Buffer2,
IN ULONG Buffer2Length,
IN LARGE_INTEGER Timeout,
OUT PTP_REQUEST * TpRequest
)
/*++
Routine Description:
This routine creates a transport request and associates it with the
specified IRP, context, and queue. All major requests, including
TdiSend, TdiSendDatagram, TdiReceive, and TdiReceiveDatagram requests,
are composed in this manner.
Arguments:
Irp - Pointer to an IRP which was received by the transport for this
request.
Context - Pointer to anything to associate this request with. This
value is not interpreted except at request cancelation time.
Flags - A set of bitflags indicating the disposition of this request.
Timeout - Timeout value (if non-zero) to start a timer for this request.
If zero, then no timer is activated for the request.
TpRequest - If the function returns STATUS_SUCCESS, this will return
pointer to the TP_REQUEST structure allocated.
Return Value:
NTSTATUS - status of operation.
--*/
{
KIRQL oldirql;
PDEVICE_CONTEXT DeviceContext;
PTP_REQUEST Request;
PLIST_ENTRY p;
PIO_STACK_LOCATION irpSp;
#if DBG
LARGE_INTEGER Time;
#endif
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint0 ("NbfCreateRequest: Entered.\n");
}
irpSp = IoGetCurrentIrpStackLocation(Irp);
DeviceContext = (PDEVICE_CONTEXT)irpSp->FileObject->DeviceObject;
#if DBG
if (!MmIsNonPagedSystemAddressValid (DeviceContext->RequestPool.Flink)) {
NbfPrint2 ("NbfCreateRequest: RequestList hosed: %lx DeviceContext: %lx\n",
&DeviceContext->RequestPool, DeviceContext);
}
#endif
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
p = RemoveHeadList (&DeviceContext->RequestPool);
if (p == &DeviceContext->RequestPool) {
if ((DeviceContext->RequestMaxAllocated == 0) ||
(DeviceContext->RequestAllocated < DeviceContext->RequestMaxAllocated)) {
NbfAllocateRequest (DeviceContext, &Request);
IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
NbfPrint1 ("NBF: Allocated request at %lx\n", Request);
}
} else {
NbfWriteResourceErrorLog(
DeviceContext,
EVENT_TRANSPORT_RESOURCE_SPECIFIC,
404,
sizeof(TP_REQUEST),
REQUEST_RESOURCE_ID);
Request = NULL;
}
if (Request == NULL) {
++DeviceContext->RequestExhausted;
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
PANIC ("NbfCreateConnection: Could not allocate request object!\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
} else {
Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
}
++DeviceContext->RequestInUse;
if (DeviceContext->RequestInUse > DeviceContext->RequestMaxInUse) {
++DeviceContext->RequestMaxInUse;
}
DeviceContext->RequestTotal += DeviceContext->RequestInUse;
++DeviceContext->RequestSamples;
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
//
// fill out the request.
//
// Request->Provider = DeviceContext;
Request->IoRequestPacket = Irp;
Request->Buffer2 = Buffer2;
Request->Buffer2Length = Buffer2Length;
Request->Flags = Flags;
Request->Context = Context;
Request->ReferenceCount = 1; // initialize reference count.
#if DBG
{
UINT Counter;
for (Counter = 0; Counter < NUMBER_OF_RREFS; Counter++) {
Request->RefTypes[Counter] = 0;
}
// This reference is removed by NbfCompleteRequest
Request->RefTypes[RREF_CREATION] = 1;
}
#endif
#if DBG
Request->Completed = FALSE;
Request->Destroyed = FALSE;
Request->TotalReferences = 0;
Request->TotalDereferences = 0;
Request->NextRefLoc = 0;
ExInterlockedInsertHeadList (&NbfGlobalRequestList, &Request->GlobalLinkage, &NbfGlobalInterlock);
StoreRequestHistory (Request, TRUE);
#endif
#if DBG
KeQuerySystemTime (&Time); // ugly, but effective
Request->Time.LowPart = Time.LowPart;
Request->Time.HighPart = Time.HighPart;
#endif
IF_NBFDBG (NBF_DEBUG_IRP) {
if (Irp->MdlAddress != NULL) {
PMDL mdl;
NbfPrint2 ("NbfCreateRequest: Map request %lx Irp %lx MdlChain \n",
Request, Request->IoRequestPacket);
mdl = Request->Buffer2;
while (mdl != NULL) {
NbfPrint4 ("Mdl %lx Va %lx StartVa %lx Flags %x\n",
mdl, MmGetSystemAddressForMdl(mdl), MmGetMdlVirtualAddress(mdl),
mdl->MdlFlags);
mdl = mdl->Next;
}
}
}
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint3 ("NbfCreateRequest: Request %lx Buffer2: %lx Irp: %lx\n", Request,
Buffer2, Irp);
}
if ((Timeout.LowPart == 0) && (Timeout.HighPart == 0)) {
// no timeout
} else {
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint3 ("NbfCreateRequest: Starting timer %lx%lx Flags %lx\n",
Timeout.HighPart, Timeout.LowPart, Request->Flags);
}
Request->Flags |= REQUEST_FLAGS_TIMER; // there is a timeout on this request.
KeInitializeTimer (&Request->Timer); // set to not-signaled state.
NbfReferenceRequest ("Create: timer", Request, RREF_TIMER); // one for the timer
KeSetTimer (&Request->Timer, Timeout, &Request->Dpc);
}
*TpRequest = Request;
return STATUS_SUCCESS;
} /* NbfCreateRequest */
VOID
NbfDestroyRequest(
IN PTP_REQUEST Request
)
/*++
Routine Description:
This routine returns a request block to the free pool.
Arguments:
Request - Pointer to a TP_REQUEST block to return to the free pool.
Return Value:
NTSTATUS - status of operation.
--*/
{
KIRQL oldirql;
PIO_STACK_LOCATION irpSp;
PDEVICE_CONTEXT DeviceContext;
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint0 ("NbfDestroyRequest: Entered.\n");
}
#if DBG
if (Request->Destroyed) {
NbfPrint1 ("attempt to destroy already-destroyed request 0x%lx\n", Request);
DbgBreakPoint ();
}
Request->Destroyed = TRUE;
#if 1
ACQUIRE_SPIN_LOCK (&NbfGlobalInterlock, &oldirql);
RemoveEntryList (&Request->GlobalLinkage);
RELEASE_SPIN_LOCK (&NbfGlobalInterlock, oldirql);
#else
ExInterlockedRemoveHeadList (Request->GlobalLinkage.Blink, &NbfGlobalInterlock);
#endif
#endif
ASSERT(Request->Completed);
//
// Return the request to the caller with whatever status is in the IRP.
//
IF_NBFDBG (NBF_DEBUG_IRP) {
NbfPrint1 ("NbfCompleteRequest: Completing IRP: %lx\n",
Request->IoRequestPacket);
}
//
// Now dereference the owner of this request so that we are safe when
// we finally tear down the {connection, address}. The problem we're
// facing here is that we can't allow the user to assume semantics;
// the end of life for a connection must truly be the real end of life.
// for that to occur, we reference the owning object when the request is
// created and we dereference it just before we return it to the pool.
//
switch (Request->Owner) {
case ConnectionType:
NbfDereferenceConnection ("Removing Connection",((PTP_CONNECTION)Request->Context), CREF_REQUEST);
break;
#if DBG
case AddressType:
ASSERT (FALSE);
NbfDereferenceAddress ("Removing Address", ((PTP_ADDRESS)Request->Context), AREF_REQUEST);
break;
#endif
case DeviceContextType:
NbfDereferenceDeviceContext ("Removing Address", ((PDEVICE_CONTEXT)Request->Context), DCREF_REQUEST);
break;
}
//
// Unmap a possibly mapped buffer. We've only mapped the buffer if the
// Irp Major function is not method 0. (of 0, 1, 2, and 3.)
//
IF_NBFDBG (NBF_DEBUG_IRP) {
{
PMDL mdl;
NbfPrint2 ("NbfDestroyRequest: Unmap request %lx Irp %lx MdlChain \n",
Request, Request->IoRequestPacket);
mdl = Request->Buffer2;
while (mdl != NULL) {
NbfPrint4 ("Mdl %lx Va %lx StartVa %lx Flags %x\n",
mdl, MmGetSystemAddressForMdl(mdl), MmGetMdlVirtualAddress(mdl),
mdl->MdlFlags);
mdl = mdl->Next;
}
}
}
irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
DeviceContext = Request->Provider;
LEAVE_NBF;
IoCompleteRequest (Request->IoRequestPacket, IO_NETWORK_INCREMENT);
ENTER_NBF;
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
//
// Put the request back on the free list. NOTE: we have the
// lock held here.
//
DeviceContext->RequestTotal += DeviceContext->RequestInUse;
++DeviceContext->RequestSamples;
--DeviceContext->RequestInUse;
if ((DeviceContext->RequestAllocated - DeviceContext->RequestInUse) >
DeviceContext->RequestInitAllocated) {
NbfDeallocateRequest (DeviceContext, Request);
IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
NbfPrint1 ("NBF: Deallocated request at %lx\n", Request);
}
} else {
InsertTailList (&DeviceContext->RequestPool, &Request->Linkage);
}
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
} /* NbfDestroyRequest */
#if DBG
VOID
NbfRefRequest(
IN PTP_REQUEST Request
)
/*++
Routine Description:
This routine increments the reference count on a transport request.
Arguments:
Request - Pointer to a TP_REQUEST block.
Return Value:
none.
--*/
{
LONG result;
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint1 ("NbfRefRequest: Entered, ReferenceCount: %x\n",
Request->ReferenceCount);
}
#if DBG
StoreRequestHistory( Request, TRUE );
#endif
ASSERT (Request->ReferenceCount > 0);
result = InterlockedIncrement (&Request->ReferenceCount);
} /* NbfRefRequest */
#endif
VOID
NbfDerefRequest(
IN PTP_REQUEST Request
)
/*++
Routine Description:
This routine dereferences a transport request by decrementing the
reference count contained in the structure. If, after being
decremented, the reference count is zero, then this routine calls
NbfDestroyRequest to remove it from the system.
Arguments:
Request - Pointer to a transport request object.
Return Value:
none.
--*/
{
LONG result;
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint1 ("NbfDerefRequest: Entered, ReferenceCount: %x\n",
Request->ReferenceCount);
}
#if DBG
StoreRequestHistory( Request, FALSE );
#endif
result = InterlockedDecrement (&Request->ReferenceCount);
ASSERT (result >= 0);
//
// If we have deleted all references to this request, then we can
// destroy the object. It is okay to have already released the spin
// lock at this point because there is no possible way that another
// stream of execution has access to the request any longer.
//
if (result == 0) {
NbfDestroyRequest (Request);
}
} /* NbfDerefRequest */
VOID
NbfCompleteRequest(
IN PTP_REQUEST Request,
IN NTSTATUS Status,
IN ULONG Information
)
/*++
Routine Description:
This routine completes a transport request object, completing the I/O,
stopping the timeout, and freeing up the request object itself.
Arguments:
Request - Pointer to a transport request object.
Status - Actual return status to be assigned to the request. This
value may be overridden if the timed-out bitflag is set in the request.
Information - the information field for the I/O Status Block.
Return Value:
none.
--*/
{
KIRQL oldirql;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
NTSTATUS FinalStatus = Status;
NTSTATUS CopyStatus;
BOOLEAN TimerWasSet;
ASSERT (Status != STATUS_PENDING);
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint2 ("NbfCompleteRequest: Entered Request %lx, Request->Flags %lx\n",
Request, Request->Flags);
}
#if DBG
if (Request->Completed) {
NbfPrint1 ("attempt to completed already-completed request 0x%lx\n", Request);
DbgBreakPoint ();
}
Request->Completed = TRUE;
#endif
ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
if ((Request->Flags & REQUEST_FLAGS_STOPPING) == 0) {
Request->Flags |= REQUEST_FLAGS_STOPPING;
//
// Cancel the pending timeout on this request. Not all requests
// have their timer set. If this request has the TIMER bit set,
// then the timer needs to be cancelled. If it cannot be cancelled,
// then the timer routine will be run, so we just return and let
// the timer routine worry about cleaning up this request.
//
if ((Request->Flags & REQUEST_FLAGS_TIMER) != 0) {
Request->Flags &= ~REQUEST_FLAGS_TIMER;
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
TimerWasSet = KeCancelTimer (&Request->Timer);
if (TimerWasSet) {
NbfDereferenceRequest ("Complete: stop timer", Request, RREF_TIMER);
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint1 ("NbfCompleteRequest: Canceled timer: %lx.\n", &Request->Timer);
}
}
} else {
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
}
Irp = Request->IoRequestPacket;
#ifdef RASAUTODIAL
//
// If this is a connect operation that has
// returned with either STATUS_SUCCESS or
// STATUS_BAD_NETWORK_PATH, then
// inform the automatic connection driver.
//
if (fAcdLoadedG) {
IrpSp = IoGetCurrentIrpStackLocation(Irp);
if (IrpSp->MinorFunction == TDI_CONNECT &&
FinalStatus == STATUS_SUCCESS)
{
KIRQL adirql;
BOOLEAN fEnabled;
ACQUIRE_SPIN_LOCK(&AcdDriverG.SpinLock, &adirql);
fEnabled = AcdDriverG.fEnabled;
RELEASE_SPIN_LOCK(&AcdDriverG.SpinLock, adirql);
if (fEnabled) {
NbfNoteNewConnection(
IrpSp->FileObject->FsContext,
(PDEVICE_CONTEXT)IrpSp->FileObject->DeviceObject);
}
}
}
#endif // RASAUTODIAL
//
// For requests associated with a device context, we need
// to copy the data from the temp buffer to the MDL and
// free the temp buffer.
//
if (Request->ResponseBuffer != NULL) {
if ((FinalStatus == STATUS_SUCCESS) ||
(FinalStatus == STATUS_BUFFER_OVERFLOW)) {
CopyStatus = TdiCopyBufferToMdl (
Request->ResponseBuffer,
0L,
Information,
Irp->MdlAddress,
0,
&Information);
if (CopyStatus != STATUS_SUCCESS) {
FinalStatus = CopyStatus;
}
}
ExFreePool (Request->ResponseBuffer);
Request->ResponseBuffer = NULL;
}
//
// Install the return code in the IRP so that when we call NbfDestroyRequest,
// it will get completed with the proper return status.
//
Irp->IoStatus.Status = FinalStatus;
Irp->IoStatus.Information = Information;
//
// The entire transport is done with this request.
//
NbfDereferenceRequest ("Complete", Request, RREF_CREATION); // remove creation reference.
} else {
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
}
} /* NbfCompleteRequest */
#if DBG
VOID
NbfRefSendIrp(
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This routine increments the reference count on a send IRP.
Arguments:
IrpSp - Pointer to the IRP's stack location.
Return Value:
none.
--*/
{
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint1 ("NbfRefSendIrp: Entered, ReferenceCount: %x\n",
IRP_SEND_REFCOUNT(IrpSp));
}
ASSERT (IRP_SEND_REFCOUNT(IrpSp) > 0);
InterlockedIncrement (&IRP_SEND_REFCOUNT(IrpSp));
} /* NbfRefSendIrp */
VOID
NbfDerefSendIrp(
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This routine dereferences a transport send IRP by decrementing the
reference count contained in the structure. If, after being
decremented, the reference count is zero, then this routine calls
IoCompleteRequest to actually complete the IRP.
Arguments:
Request - Pointer to a transport send IRP's stack location.
Return Value:
none.
--*/
{
LONG result;
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint1 ("NbfDerefSendIrp: Entered, ReferenceCount: %x\n",
IRP_SEND_REFCOUNT(IrpSp));
}
result = InterlockedDecrement (&IRP_SEND_REFCOUNT(IrpSp));
ASSERT (result >= 0);
//
// If we have deleted all references to this request, then we can
// destroy the object. It is okay to have already released the spin
// lock at this point because there is no possible way that another
// stream of execution has access to the request any longer.
//
if (result == 0) {
PIRP Irp = IRP_SEND_IRP(IrpSp);
IRP_SEND_REFCOUNT(IrpSp) = 0;
IRP_SEND_IRP (IrpSp) = NULL;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
}
} /* NbfDerefSendIrp */
#endif
VOID
NbfCompleteSendIrp(
IN PIRP Irp,
IN NTSTATUS Status,
IN ULONG Information
)
/*++
Routine Description:
This routine completes a transport send IRP.
Arguments:
Irp - Pointer to a send IRP.
Status - Actual return status to be assigned to the request. This
value may be overridden if the timed-out bitflag is set in the request.
Information - the information field for the I/O Status Block.
Return Value:
none.
--*/
{
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PTP_CONNECTION Connection;
ASSERT (Status != STATUS_PENDING);
Connection = IRP_SEND_CONNECTION(IrpSp);
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint2 ("NbfCompleteSendIrp: Entered IRP %lx, connection %lx\n",
Irp, Connection);
}
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = Information;
NbfDereferenceSendIrp ("Complete", IrpSp, RREF_CREATION); // remove creation reference.
NbfDereferenceConnectionMacro ("Removing Connection", Connection, CREF_SEND_IRP);
} /* NbfCompleteSendIrp */
#if DBG
VOID
NbfRefReceiveIrpLocked(
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This routine increments the reference count on a receive IRP.
Arguments:
IrpSp - Pointer to the IRP's stack location.
Return Value:
none.
--*/
{
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint1 ("NbfRefReceiveIrpLocked: Entered, ReferenceCount: %x\n",
IRP_RECEIVE_REFCOUNT(IrpSp));
}
ASSERT (IRP_RECEIVE_REFCOUNT(IrpSp) > 0);
IRP_RECEIVE_REFCOUNT(IrpSp)++;
} /* NbfRefReceiveIrpLocked */
#endif
VOID
NbfDerefReceiveIrp(
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This routine dereferences a transport receive IRP by decrementing the
reference count contained in the structure. If, after being
decremented, the reference count is zero, then this routine calls
IoCompleteRequest to actually complete the IRP.
Arguments:
Request - Pointer to a transport receive IRP's stack location.
Return Value:
none.
--*/
{
ULONG result;
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint1 ("NbfDerefReceiveIrp: Entered, ReferenceCount: %x\n",
IRP_RECEIVE_REFCOUNT(IrpSp));
}
result = ExInterlockedAddUlong (
(PULONG)&IRP_RECEIVE_REFCOUNT(IrpSp),
(ULONG)-1,
(IRP_RECEIVE_CONNECTION(IrpSp)->LinkSpinLock));
ASSERT (result > 0);
//
// If we have deleted all references to this request, then we can
// destroy the object. It is okay to have already released the spin
// lock at this point because there is no possible way that another
// stream of execution has access to the request any longer.
//
if (result == 1) {
PIRP Irp = IRP_RECEIVE_IRP(IrpSp);
ExInterlockedInsertTailList(
&(IRP_DEVICE_CONTEXT(IrpSp)->IrpCompletionQueue),
&Irp->Tail.Overlay.ListEntry,
&(IRP_DEVICE_CONTEXT(IrpSp)->Interlock));
}
} /* NbfDerefReceiveIrp */
#if DBG
VOID
NbfDerefReceiveIrpLocked(
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This routine dereferences a transport receive IRP by decrementing the
reference count contained in the structure. If, after being
decremented, the reference count is zero, then this routine calls
IoCompleteRequest to actually complete the IRP.
Arguments:
Request - Pointer to a transport receive IRP's stack location.
Return Value:
none.
--*/
{
ULONG result;
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint1 ("NbfDerefReceiveIrpLocked: Entered, ReferenceCount: %x\n",
IRP_RECEIVE_REFCOUNT(IrpSp));
}
result = IRP_RECEIVE_REFCOUNT(IrpSp)--;
ASSERT (result > 0);
//
// If we have deleted all references to this request, then we can
// destroy the object. It is okay to have already released the spin
// lock at this point because there is no possible way that another
// stream of execution has access to the request any longer.
//
if (result == 1) {
PIRP Irp = IRP_RECEIVE_IRP(IrpSp);
ExInterlockedInsertTailList(
&(IRP_DEVICE_CONTEXT(IrpSp)->IrpCompletionQueue),
&Irp->Tail.Overlay.ListEntry,
&(IRP_DEVICE_CONTEXT(IrpSp)->Interlock));
}
} /* NbfDerefReceiveIrpLocked */
#endif
VOID
NbfCompleteReceiveIrp(
IN PIRP Irp,
IN NTSTATUS Status,
IN ULONG Information
)
/*++
Routine Description:
This routine completes a transport receive IRP.
NOTE: THIS ROUTINE MUST BE CALLED WITH THE CONNECTION SPINLOCK
HELD.
Arguments:
Irp - Pointer to a receive IRP.
Status - Actual return status to be assigned to the request. This
value may be overridden if the timed-out bitflag is set in the request.
Information - the information field for the I/O Status Block.
Return Value:
none.
--*/
{
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PTP_CONNECTION Connection;
ASSERT (Status != STATUS_PENDING);
Connection = IRP_RECEIVE_CONNECTION(IrpSp);
IF_NBFDBG (NBF_DEBUG_REQUEST) {
NbfPrint2 ("NbfCompleteReceiveIrp: Entered IRP %lx, connection %lx\n",
Irp, Connection);
}
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = Information;
NbfDereferenceReceiveIrpLocked ("Complete", IrpSp, RREF_CREATION); // remove creation reference.
} /* NbfCompleteReceiveIrp */