mirror of https://github.com/tongzx/nt5src
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.
1377 lines
34 KiB
1377 lines
34 KiB
/*++
|
|
|
|
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 */
|
|
|