1378 lines
34 KiB
C
1378 lines
34 KiB
C
/*++
|
||
|
||
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 */
|
||
|