/*++ 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 #include #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 */