NDIS_STATUS NdisuioReceive( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID pHeaderBuffer, IN UINT HeaderBufferSize, IN PVOID pLookaheadBuffer, IN UINT LookaheadBufferSize, IN UINT PacketSize ) /*++ Routine Description: Our protocol receive handler called by NDIS, typically if we have a miniport below that doesn't indicate packets. We make a local packet/buffer copy of this data, queue it up, and kick off the read service routine. Arguments: ProtocolBindingContext - pointer to open context MacReceiveContext - for use in NdisTransferData pHeaderBuffer - pointer to data header HeaderBufferSize - size of the above pLookaheadBuffer - pointer to buffer containing lookahead data LookaheadBufferSize - size of the above PacketSize - size of the entire packet, minus header size. Return Value: NDIS_STATUS_NOT_ACCEPTED - if this packet is uninteresting NDIS_STATUS_SUCCESS - if we processed this successfully --*/ { PNDISUIO_OPEN_CONTEXT pOpenContext; NDIS_STATUS Status; PNDISUIO_ETH_HEADER pEthHeader; PNDIS_PACKET pRcvPacket; PUCHAR pRcvData; UINT BytesTransferred; PNDIS_BUFFER pOriginalNdisBuffer, pPartialNdisBuffer; PIRP pIrp; PLIST_ENTRY pIrpEntry; ULONG BytesRemaining; // at pDst PPACKET_GROUP pGroup; //ULONG pDst; pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext; NUIO_STRUCT_ASSERT(pOpenContext, oc); pRcvPacket = NULL; pRcvData = NULL; Status = NDIS_STATUS_SUCCESS; DEBUGP(DL_LOUD, ("Receive: Open %p, LookaheadBufferSize %d, PacketSize %d\n", pOpenContext, LookaheadBufferSize, PacketSize)); NdisInterlockedAddLargeStatistic((PLARGE_INTEGER)&pOpenContext->ReceivedPackets, 1); do { if (HeaderBufferSize != sizeof(NDISUIO_ETH_HEADER)) { Status = NDIS_STATUS_NOT_ACCEPTED; break; } pEthHeader = (PNDISUIO_ETH_HEADER)pHeaderBuffer; NUIO_ACQUIRE_LOCK(&pOpenContext->Lock); // // Someone is reading, and this is the first packet. // if (!NUIO_IS_LIST_EMPTY(&pOpenContext->PendedReads) && NUIO_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue)) { // // Get the first pended Read IRP // pIrpEntry = pOpenContext->PendedReads.Flink; pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry); // // We don't have to worry about the situation where the IRP is cancelled // after we remove it from the queue and before we reset the cancel // routine because the cancel routine has been coded to cancel an IRP // only if it's in the queue. // IoSetCancelRoutine(pIrp, NULL); NUIO_REMOVE_ENTRY_LIST(pIrpEntry); pOpenContext->PendedReadCount--; NUIO_RELEASE_LOCK(&pOpenContext->Lock); NUIO_DEREF_OPEN(pOpenContext); // Service: dequeue rcv packet // // Copy as much data as possible from the receive packet to // the IRP MDL. // #ifndef WIN9X pGroup = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); //NUIO_ASSERT(pDst != NULL); // since it was already mapped #else pGroup = MmGetSystemAddressForMdl(pIrp->MdlAddress); // Win9x #endif BytesRemaining = MmGetMdlByteCount(pIrp->MdlAddress); BytesRemaining -= sizeof(PACKET_GROUP); // // copy the ethernet header into the actual readbuffer // NdisMoveMappedMemory(pGroup->Data, pHeaderBuffer, HeaderBufferSize); if (PacketSize == LookaheadBufferSize) { BytesTransferred = MIN(LookaheadBufferSize, BytesRemaining); NdisCopyLookaheadData(pGroup->Data + HeaderBufferSize, pLookaheadBuffer, BytesTransferred, pOpenContext->MacOptions); pGroup->Length = BytesTransferred + HeaderBufferSize; pIrp->IoStatus.Information = pGroup->Length + sizeof(PACKET_GROUP); pIrp->IoStatus.Status = STATUS_SUCCESS; DEBUGP(DL_LOUD, ("Receive: %d bytes\n", pIrp->IoStatus.Information)); IoCompleteRequest(pIrp, IO_NO_INCREMENT); } else { BytesTransferred = 0; NdisAllocatePacket( &Status, &pRcvPacket, pOpenContext->RecvBufferPool ); if (Status != NDIS_STATUS_SUCCESS) goto ERROR; // // Allocate an MDL to map the portion of the buffer following the // header // pPartialNdisBuffer = IoAllocateMdl(pGroup->Data, BytesRemaining, FALSE, FALSE, NULL); if (pPartialNdisBuffer == NULL) { NdisFreePacket(pRcvPacket); Status = NDIS_STATUS_RESOURCES; goto ERROR; } // // Build the mdl to point to the the portion of the buffer following // the header // IoBuildPartialMdl( pIrp->MdlAddress, pPartialNdisBuffer, pGroup->Data + HeaderBufferSize, 0); // // Clear the next link in the new MDL // pPartialNdisBuffer->Next = NULL; // // Get a pointer to the packet itself. // NUIO_IRP_FROM_RCV_PKT(pRcvPacket) = pIrp; NUIO_RCV_PKT_TO_ORIGINAL_BUFFER(pRcvPacket) = pPartialNdisBuffer; // // Attach our partial MDL to the packet // NdisChainBufferAtFront(pRcvPacket, pPartialNdisBuffer); // // Call the Mac to transfer the packet // NdisTransferData( &Status, pOpenContext->BindingHandle, MacReceiveContext, 0, // ByteOffset PacketSize, pRcvPacket, &BytesTransferred); ERROR: // // If it didn't pend, call the completeion routine now // if (Status != NDIS_STATUS_PENDING) { NdisuioTransferDataComplete( (NDIS_HANDLE)pOpenContext, pRcvPacket, Status, BytesTransferred); } } break; } NUIO_RELEASE_LOCK(&pOpenContext->Lock); // // Allocate resources for queueing this up. // pRcvPacket = ndisuioAllocateReceivePacket( pOpenContext, PacketSize + HeaderBufferSize, &pRcvData ); if (pRcvPacket == NULL) { Status = NDIS_STATUS_NOT_ACCEPTED; break; } NdisMoveMappedMemory(pRcvData, pHeaderBuffer, HeaderBufferSize); // // Check if the entire packet is within the lookahead. // if (PacketSize == LookaheadBufferSize) { NdisCopyLookaheadData(pRcvData + HeaderBufferSize, pLookaheadBuffer, LookaheadBufferSize, pOpenContext->MacOptions); // // Queue this up for receive processing, and // try to complete some read IRPs. // ndisuioQueueReceivePacket(pOpenContext, pRcvPacket); } else { // // Allocate an NDIS buffer to map the receive area // at an offset "HeaderBufferSize" from the current // start. This is so that NdisTransferData can copy // in at the right point in the destination buffer. // NdisAllocateBuffer( &Status, &pPartialNdisBuffer, pOpenContext->RecvBufferPool, pRcvData + HeaderBufferSize, PacketSize); if (Status == NDIS_STATUS_SUCCESS) { // // Unlink and save away the original NDIS Buffer // that maps the full receive buffer. // NdisUnchainBufferAtFront(pRcvPacket, &pOriginalNdisBuffer); NUIO_RCV_PKT_TO_ORIGINAL_BUFFER(pRcvPacket) = pOriginalNdisBuffer; NUIO_IRP_FROM_RCV_PKT(pRcvPacket) = NULL; // // Link in the partial buffer for NdisTransferData to // operate on. // NdisChainBufferAtBack(pRcvPacket, pPartialNdisBuffer); DEBUGP(DL_LOUD, ("Receive: setting up for TransferData:" " Pkt %p, OriginalBuf %p, PartialBuf %p\n", pRcvPacket, pOriginalNdisBuffer, pPartialNdisBuffer)); NdisTransferData( &Status, pOpenContext->BindingHandle, MacReceiveContext, 0, // ByteOffset PacketSize, pRcvPacket, &BytesTransferred); } else { // // Failure handled below in TransferDataComplete. // BytesTransferred = 0; } if (Status != NDIS_STATUS_PENDING) { NdisuioTransferDataComplete( (NDIS_HANDLE)pOpenContext, pRcvPacket, Status, BytesTransferred); } } } while (FALSE); if (Status != NDIS_STATUS_SUCCESS && Status != NDIS_STATUS_PENDING) NdisInterlockedAddLargeStatistic((PLARGE_INTEGER)&pOpenContext->DroppedPackets, 1); return Status; }
BOOLEAN USBSTOR_QueueAddIrp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PDRIVER_CANCEL OldDriverCancel; KIRQL OldLevel; PFDO_DEVICE_EXTENSION FDODeviceExtension; BOOLEAN IrpListFreeze; BOOLEAN SrbProcessing; PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp); PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; // // get FDO device extension // FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // sanity check // ASSERT(FDODeviceExtension->Common.IsFDO); // // mark irp pending // IoMarkIrpPending(Irp); // // acquire lock // KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel); // // check if there are irp pending // SrbProcessing = FDODeviceExtension->IrpPendingCount != 0; if (SrbProcessing) { // // add irp to queue // InsertTailList(&FDODeviceExtension->IrpListHead, &Irp->Tail.Overlay.ListEntry); } // // increment pending count // FDODeviceExtension->IrpPendingCount++; // // clear the no requests pending event // KeClearEvent(&FDODeviceExtension->NoPendingRequests); // // check if queue is freezed // IrpListFreeze = FDODeviceExtension->IrpListFreeze; // // release list lock // KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel); // // synchronize with cancellations by holding the cancel lock // IoAcquireCancelSpinLock(&Irp->CancelIrql); // // now set the driver cancel routine // if (SrbProcessing) { ASSERT(FDODeviceExtension->ActiveSrb != NULL); OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_Cancel); } else { ASSERT(FDODeviceExtension->ActiveSrb == NULL); FDODeviceExtension->ActiveSrb = Request; OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_CancelIo); } // // check if the irp has already been cancelled // if (Irp->Cancel && OldDriverCancel == NULL) { // // cancel irp // Irp->CancelRoutine(DeviceObject, Irp); // // irp was cancelled // return FALSE; } // // release the cancel lock // IoReleaseCancelSpinLock(Irp->CancelIrql); // // if list is freezed, dont start this packet // DPRINT("IrpListFreeze: %lu IrpPendingCount %lu\n", IrpListFreeze, FDODeviceExtension->IrpPendingCount); return (IrpListFreeze || SrbProcessing); }
// When user-mode file system application returns EventInformation, // search corresponding pending IRP and complete it NTSTATUS DokanCompleteIrp( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { KIRQL oldIrql; PLIST_ENTRY thisEntry, nextEntry, listHead; PIRP_ENTRY irpEntry; PDokanVCB vcb; PEVENT_INFORMATION eventInfo; eventInfo = (PEVENT_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ASSERT(eventInfo != NULL); //DDbgPrint("==> DokanCompleteIrp [EventInfo #%X]\n", eventInfo->SerialNumber); vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB) { return STATUS_INVALID_PARAMETER; } //DDbgPrint(" Lock IrpList.ListLock\n"); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KeAcquireSpinLock(&vcb->Dcb->PendingIrp.ListLock, &oldIrql); // search corresponding IRP through pending IRP list listHead = &vcb->Dcb->PendingIrp.ListHead; for (thisEntry = listHead->Flink; thisEntry != listHead; thisEntry = nextEntry) { PIRP irp; PIO_STACK_LOCATION irpSp; nextEntry = thisEntry->Flink; irpEntry = CONTAINING_RECORD(thisEntry, IRP_ENTRY, ListEntry); // check whether this is corresponding IRP //DDbgPrint("SerialNumber irpEntry %X eventInfo %X\n", irpEntry->SerialNumber, eventInfo->SerialNumber); // this irpEntry must be freed in this if statement if (irpEntry->SerialNumber != eventInfo->SerialNumber) { continue; } RemoveEntryList(thisEntry); irp = irpEntry->Irp; if (irp == NULL) { // this IRP is already canceled ASSERT(irpEntry->CancelRoutineFreeMemory == FALSE); DokanFreeIrpEntry(irpEntry); irpEntry = NULL; break; } if (IoSetCancelRoutine(irp, NULL) == NULL) { // Cancel routine will run as soon as we release the lock InitializeListHead(&irpEntry->ListEntry); irpEntry->CancelRoutineFreeMemory = TRUE; break; } // IRP is not canceled yet irpSp = irpEntry->IrpSp; ASSERT(irpSp != NULL); // IrpEntry is saved here for CancelRoutine // Clear it to prevent to be completed by CancelRoutine twice irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_IRP_ENTRY] = NULL; KeReleaseSpinLock(&vcb->Dcb->PendingIrp.ListLock, oldIrql); switch (irpSp->MajorFunction) { case IRP_MJ_DIRECTORY_CONTROL: DokanCompleteDirectoryControl(irpEntry, eventInfo); break; case IRP_MJ_READ: DokanCompleteRead(irpEntry, eventInfo); break; case IRP_MJ_WRITE: DokanCompleteWrite(irpEntry, eventInfo); break; case IRP_MJ_QUERY_INFORMATION: DokanCompleteQueryInformation(irpEntry, eventInfo); break; case IRP_MJ_QUERY_VOLUME_INFORMATION: DokanCompleteQueryVolumeInformation(irpEntry, eventInfo); break; case IRP_MJ_CREATE: DokanCompleteCreate(irpEntry, eventInfo); break; case IRP_MJ_CLEANUP: DokanCompleteCleanup(irpEntry, eventInfo); break; case IRP_MJ_LOCK_CONTROL: DokanCompleteLock(irpEntry, eventInfo); break; case IRP_MJ_SET_INFORMATION: DokanCompleteSetInformation(irpEntry, eventInfo); break; case IRP_MJ_FLUSH_BUFFERS: DokanCompleteFlush(irpEntry, eventInfo); break; case IRP_MJ_QUERY_SECURITY: DokanCompleteQuerySecurity(irpEntry, eventInfo); break; case IRP_MJ_SET_SECURITY: DokanCompleteSetSecurity(irpEntry, eventInfo); break; default: DDbgPrint("Unknown IRP %d\n", irpSp->MajorFunction); // TODO: in this case, should complete this IRP break; } DokanFreeIrpEntry(irpEntry); irpEntry = NULL; return STATUS_SUCCESS; } KeReleaseSpinLock(&vcb->Dcb->PendingIrp.ListLock, oldIrql); //DDbgPrint("<== AACompleteIrp [EventInfo #%X]\n", eventInfo->SerialNumber); // TODO: should return error return STATUS_SUCCESS; }
NTSTATUS NTAPI NpSetDisconnectedPipeState(IN PNP_CCB Ccb, IN PLIST_ENTRY List) { PIRP Irp; PNP_NONPAGED_CCB NonPagedCcb; NTSTATUS Status; PLIST_ENTRY NextEntry; PNP_EVENT_BUFFER EventBuffer; NonPagedCcb = Ccb->NonPagedCcb; switch (Ccb->NamedPipeState) { case FILE_PIPE_DISCONNECTED_STATE: Status = STATUS_PIPE_DISCONNECTED; break; case FILE_PIPE_LISTENING_STATE: while (!IsListEmpty(&Ccb->IrpList)) { NextEntry = RemoveHeadList(&Ccb->IrpList); Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry); if (IoSetCancelRoutine(Irp, NULL)) { Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED; InsertTailList(List, NextEntry); } else { InitializeListHead(NextEntry); } } Status = STATUS_SUCCESS; break; case FILE_PIPE_CONNECTED_STATE: EventBuffer = NonPagedCcb->EventBuffer[FILE_PIPE_CLIENT_END]; while (Ccb->DataQueue[FILE_PIPE_INBOUND].QueueState != Empty) { Irp = NpRemoveDataQueueEntry(&Ccb->DataQueue[FILE_PIPE_INBOUND], FALSE, List); if (Irp) { Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED; InsertTailList(List, &Irp->Tail.Overlay.ListEntry); } } while (Ccb->DataQueue[FILE_PIPE_OUTBOUND].QueueState != Empty) { Irp = NpRemoveDataQueueEntry(&Ccb->DataQueue[FILE_PIPE_OUTBOUND], FALSE, List); if (Irp) { Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED; InsertTailList(List, &Irp->Tail.Overlay.ListEntry); } } if (EventBuffer) KeSetEvent(EventBuffer->Event, IO_NO_INCREMENT, FALSE); // drop down on purpose... queue will be empty so flush code is nop ASSERT(Ccb->DataQueue[FILE_PIPE_OUTBOUND].QueueState == Empty); case FILE_PIPE_CLOSING_STATE: EventBuffer = NonPagedCcb->EventBuffer[FILE_PIPE_CLIENT_END]; while (Ccb->DataQueue[FILE_PIPE_INBOUND].QueueState != Empty) { Irp = NpRemoveDataQueueEntry(&Ccb->DataQueue[FILE_PIPE_INBOUND], FALSE, List); if (Irp) { Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED; InsertTailList(List, &Irp->Tail.Overlay.ListEntry); } } ASSERT(Ccb->DataQueue[FILE_PIPE_OUTBOUND].QueueState == Empty); NpDeleteEventTableEntry(&NpVcb->EventTable, EventBuffer); NonPagedCcb->EventBuffer[FILE_PIPE_CLIENT_END] = NULL; NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE); Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL; NpUninitializeSecurity(Ccb); if (Ccb->ClientSession) { ExFreePool(Ccb->ClientSession); Ccb->ClientSession = NULL; } Status = STATUS_SUCCESS; break; default: NpBugCheck(Ccb->NamedPipeState, 0, 0); break; } Ccb->NamedPipeState = FILE_PIPE_DISCONNECTED_STATE; return Status; }
NTSTATUS RegisterPendingIrpMain(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in ULONG SerialNumber, __in PIRP_LIST IrpList, __in ULONG Flags, __in ULONG CheckMount) { PIRP_ENTRY irpEntry; PIO_STACK_LOCATION irpSp; KIRQL oldIrql; PDokanVCB vcb = NULL; DDbgPrint("==> DokanRegisterPendingIrpMain\n"); if (GetIdentifierType(DeviceObject->DeviceExtension) == VCB) { vcb = DeviceObject->DeviceExtension; if (CheckMount && IsUnmountPendingVcb(vcb)) { DDbgPrint(" device is not mounted\n"); return STATUS_NO_SUCH_DEVICE; } } irpSp = IoGetCurrentIrpStackLocation(Irp); // Allocate a record and save all the event context. irpEntry = DokanAllocateIrpEntry(); if (NULL == irpEntry) { DDbgPrint(" can't allocate IRP_ENTRY\n"); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(irpEntry, sizeof(IRP_ENTRY)); InitializeListHead(&irpEntry->ListEntry); irpEntry->SerialNumber = SerialNumber; irpEntry->FileObject = irpSp->FileObject; irpEntry->Irp = Irp; irpEntry->IrpSp = irpSp; irpEntry->IrpList = IrpList; irpEntry->Flags = Flags; // Update the irp timeout for the entry if (vcb) { ExAcquireResourceExclusiveLite(&vcb->Dcb->Resource, TRUE); DokanUpdateTimeout(&irpEntry->TickCount, vcb->Dcb->IrpTimeout); ExReleaseResourceLite(&vcb->Dcb->Resource); } else { DokanUpdateTimeout(&irpEntry->TickCount, DOKAN_IRP_PENDING_TIMEOUT); } // DDbgPrint(" Lock IrpList.ListLock\n"); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KeAcquireSpinLock(&IrpList->ListLock, &oldIrql); IoSetCancelRoutine(Irp, DokanIrpCancelRoutine); if (Irp->Cancel) { if (IoSetCancelRoutine(Irp, NULL) != NULL) { // DDbgPrint(" Release IrpList.ListLock %d\n", __LINE__); KeReleaseSpinLock(&IrpList->ListLock, oldIrql); DokanFreeIrpEntry(irpEntry); return STATUS_CANCELLED; } } IoMarkIrpPending(Irp); InsertTailList(&IrpList->ListHead, &irpEntry->ListEntry); irpEntry->CancelRoutineFreeMemory = FALSE; // save the pointer in order to be accessed by cancel routine Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_IRP_ENTRY] = irpEntry; KeSetEvent(&IrpList->NotEmpty, IO_NO_INCREMENT, FALSE); // DDbgPrint(" Release IrpList.ListLock\n"); KeReleaseSpinLock(&IrpList->ListLock, oldIrql); DDbgPrint("<== DokanRegisterPendingIrpMain\n"); return STATUS_PENDING; }
NTSTATUS NdisProtWrite( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) /*++ Routine Description: Dispatch routine to handle IRP_MJ_WRITE. Arguments: pDeviceObject - pointer to our device object pIrp - Pointer to request packet Return Value: NT status code. --*/ { PIO_STACK_LOCATION pIrpSp; ULONG DataLength; NTSTATUS NtStatus; NDIS_STATUS Status; PNDISPROT_OPEN_CONTEXT pOpenContext; PNDIS_PACKET pNdisPacket; PNDIS_BUFFER pNdisBuffer; NDISPROT_ETH_HEADER UNALIGNED *pEthHeader; #ifdef NDIS51 PVOID CancelId; #endif UNREFERENCED_PARAMETER(pDeviceObject); pIrpSp = IoGetCurrentIrpStackLocation(pIrp); pOpenContext = pIrpSp->FileObject->FsContext; pNdisPacket = NULL; do { if (pOpenContext == NULL) { DEBUGP(DL_WARN, ("Write: FileObject %p not yet associated with a device\n", pIrpSp->FileObject)); NtStatus = STATUS_INVALID_HANDLE; break; } NPROT_STRUCT_ASSERT(pOpenContext, oc); if (pIrp->MdlAddress == NULL) { DEBUGP(DL_FATAL, ("Write: NULL MDL address on IRP %p\n", pIrp)); NtStatus = STATUS_INVALID_PARAMETER; break; } // // Try to get a virtual address for the MDL. // pEthHeader = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); if (pEthHeader == NULL) { DEBUGP(DL_FATAL, ("Write: MmGetSystemAddr failed for" " IRP %p, MDL %p\n", pIrp, pIrp->MdlAddress)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } // // Sanity-check the length. // DataLength = MmGetMdlByteCount(pIrp->MdlAddress); if (DataLength < sizeof(NDISPROT_ETH_HEADER)) { DEBUGP(DL_WARN, ("Write: too small to be a valid packet (%d bytes)\n", DataLength)); NtStatus = STATUS_BUFFER_TOO_SMALL; break; } if (DataLength > (pOpenContext->MaxFrameSize + sizeof(NDISPROT_ETH_HEADER))) { DEBUGP(DL_WARN, ("Write: Open %p: data length (%d)" " larger than max frame size (%d)\n", pOpenContext, DataLength, pOpenContext->MaxFrameSize)); NtStatus = STATUS_INVALID_BUFFER_SIZE; break; } // // To prevent applications from sending packets with spoofed // mac address, we will do the following check to make sure the source // address in the packet is same as the current MAC address of the NIC. // if ((pIrp->RequestorMode == UserMode) && !NPROT_MEM_CMP(pEthHeader->SrcAddr, pOpenContext->CurrentAddress, NPROT_MAC_ADDR_LEN)) { DEBUGP(DL_WARN, ("Write: Failing with invalid Source address")); NtStatus = STATUS_INVALID_PARAMETER; break; } NPROT_ACQUIRE_LOCK(&pOpenContext->Lock); if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE)) { NPROT_RELEASE_LOCK(&pOpenContext->Lock); DEBUGP(DL_FATAL, ("Write: Open %p is not bound" " or in low power state\n", pOpenContext)); NtStatus = STATUS_INVALID_HANDLE; break; } // // Allocate a send packet. // NPROT_ASSERT(pOpenContext->SendPacketPool != NULL); NdisAllocatePacket( &Status, &pNdisPacket, pOpenContext->SendPacketPool); if (Status != NDIS_STATUS_SUCCESS) { NPROT_RELEASE_LOCK(&pOpenContext->Lock); DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send pkt\n", pOpenContext)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } // // Allocate a send buffer if necessary. // if (pOpenContext->bRunningOnWin9x) { NdisAllocateBuffer( &Status, &pNdisBuffer, pOpenContext->SendBufferPool, pEthHeader, DataLength); if (Status != NDIS_STATUS_SUCCESS) { NPROT_RELEASE_LOCK(&pOpenContext->Lock); NdisFreePacket(pNdisPacket); DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send buf\n", pOpenContext)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } } else { pNdisBuffer = pIrp->MdlAddress; } NdisInterlockedIncrement((PLONG)&pOpenContext->PendedSendCount); NPROT_REF_OPEN(pOpenContext); // pended send IoMarkIrpPending(pIrp); // // Initialize the packet ref count. This packet will be freed // when this count goes to zero. // NPROT_SEND_PKT_RSVD(pNdisPacket)->RefCount = 1; #ifdef NDIS51 // // NDIS 5.1 supports cancelling sends. We set up a cancel ID on // each send packet (which maps to a Write IRP), and save the // packet pointer in the IRP. If the IRP gets cancelled, we use // NdisCancelSendPackets() to cancel the packet. // CancelId = NPROT_GET_NEXT_CANCEL_ID(); NDIS_SET_PACKET_CANCEL_ID(pNdisPacket, CancelId); pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext; pIrp->Tail.Overlay.DriverContext[1] = (PVOID)pNdisPacket; NPROT_INSERT_TAIL_LIST(&pOpenContext->PendedWrites, &pIrp->Tail.Overlay.ListEntry); IoSetCancelRoutine(pIrp, NdisProtCancelWrite); #endif // NDIS51 NPROT_RELEASE_LOCK(&pOpenContext->Lock); // // Set a back pointer from the packet to the IRP. // NPROT_IRP_FROM_SEND_PKT(pNdisPacket) = pIrp; NtStatus = STATUS_PENDING; pNdisBuffer->Next = NULL; NdisChainBufferAtFront(pNdisPacket, pNdisBuffer); #if SEND_DBG { PUCHAR pData; pData = MmGetSystemAddressForMdlSafe(pNdisBuffer, NormalPagePriority); NPROT_ASSERT(pEthHeader == pData); DEBUGP(DL_VERY_LOUD, ("Write: MDL %p, MdlFlags %x, SystemAddr %p, %d bytes\n", pIrp->MdlAddress, pIrp->MdlAddress->MdlFlags, pData, DataLength)); DEBUGPDUMP(DL_VERY_LOUD, pData, MIN(DataLength, 48)); } #endif // SEND_DBG NdisSendPackets(pOpenContext->BindingHandle, &pNdisPacket, 1); } while (FALSE); if (NtStatus != STATUS_PENDING) { pIrp->IoStatus.Status = NtStatus; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } return (NtStatus); }
NTSTATUS divert_read( IN PDEVICE_OBJECT pDeviceObject, IN PIRP Irp ) { PIO_STACK_LOCATION irpStack; NTSTATUS rc = STATUS_SUCCESS; struct divert_packet *dp; irpStack = IoGetCurrentIrpStackLocation(Irp); if (Irp->MdlAddress == NULL) { DbgPrint("f**k\n"); rc = STATUS_INVALID_PARAMETER; IoCompleteRequest(Irp, IO_NO_INCREMENT); return rc; } /* DbgPrint("Addr %p\n", currentAddress); DbgPrint("AO %d %d\n", irpStack->Parameters.Read.ByteOffset.LowPart, irpStack->Parameters.Read.Length); RtlMoveMemory(currentAddress, driverExtension->buffer+irpStack->Parameters.Read.ByteOffset.LowPart, irpStack->Parameters.Read.Length); */ lock(); dp = _packet_queue.dp_next; if (!dp) { if (_pending) DbgPrint("pending already set!"); _pending = Irp; IoMarkIrpPending(Irp); IoSetCancelRoutine(Irp, divert_read_cancel); unlock(); return STATUS_PENDING; } rc = STATUS_SUCCESS; divert_do_recv(Irp); unlock(); return rc; }
void ssh_interceptor_iodevice_complete_ioctl(SshInterceptorIoDevice iodevice, SshIoctlRequest ioctl_req, SshIoctlStatus status) { SshIoDeviceIoctlRequest ioctl; SshIoDeviceIoctlHandler handler; PIRP irp; SSH_ASSERT(iodevice != NULL); SSH_ASSERT(ioctl_req != NULL); SSH_ASSERT(ioctl_req->device == iodevice); ioctl = CONTAINING_RECORD(ioctl_req, SshIoDeviceIoctlRequestStruct, public_data); NdisAcquireSpinLock(&iodevice->ioctl_req_list_lock); RemoveEntryList(&ioctl->private_data.link); NdisReleaseSpinLock(&iodevice->ioctl_req_list_lock); handler = ioctl->public_data.context; irp = ioctl->private_data.irp; #pragma warning(disable: 4311 4312) IoSetCancelRoutine(irp, NULL); #pragma warning(default: 4311 4312) switch (status) { case SSH_IOCTL_RESULT_SUCCESS: irp->IoStatus.Status = STATUS_SUCCESS; irp->IoStatus.Information = ioctl->public_data.bytes_written; IoCompleteRequest(irp, IO_NO_INCREMENT); break; case SSH_IOCTL_RESULT_FAILURE: irp->IoStatus.Status = STATUS_UNSUCCESSFUL; irp->IoStatus.Information = 0; IoCompleteRequest(irp, IO_NO_INCREMENT); break; case SSH_IOCTL_RESULT_CANCELLED: irp->IoStatus.Status = STATUS_CANCELLED; irp->IoStatus.Information = 0; IoCompleteRequest(irp, IO_NO_INCREMENT); break; default: SSH_NOTREACHED; break; } InterlockedDecrement(&handler->ref_count); ssh_free(ioctl); }
static NTSTATUS NTAPI StreamSocketConnectComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context) { NTSTATUS Status = Irp->IoStatus.Status; PAFD_FCB FCB = (PAFD_FCB)Context; PLIST_ENTRY NextIrpEntry; PIRP NextIrp; AFD_DbgPrint(MID_TRACE,("Called: FCB %p, FO %p\n", Context, FCB->FileObject)); /* I was wrong about this before as we can have pending writes to a not * yet connected socket */ if( !SocketAcquireStateLock( FCB ) ) return STATUS_FILE_CLOSED; AFD_DbgPrint(MID_TRACE,("Irp->IoStatus.Status = %x\n", Irp->IoStatus.Status)); ASSERT(FCB->ConnectIrp.InFlightRequest == Irp); FCB->ConnectIrp.InFlightRequest = NULL; if( FCB->State == SOCKET_STATE_CLOSED ) { /* Cleanup our IRP queue because the FCB is being destroyed */ while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_CONNECT] ) ) { NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_CONNECT]); NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry); NextIrp->IoStatus.Status = STATUS_FILE_CLOSED; NextIrp->IoStatus.Information = 0; if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) ); (void)IoSetCancelRoutine(NextIrp, NULL); IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT ); } SocketStateUnlock( FCB ); return STATUS_FILE_CLOSED; } if( !NT_SUCCESS(Irp->IoStatus.Status) ) { FCB->PollState |= AFD_EVENT_CONNECT_FAIL; FCB->PollStatus[FD_CONNECT_BIT] = Irp->IoStatus.Status; AFD_DbgPrint(MID_TRACE,("Going to bound state\n")); FCB->State = SOCKET_STATE_BOUND; PollReeval( FCB->DeviceExt, FCB->FileObject ); } /* Succeed pending irps on the FUNCTION_CONNECT list */ while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_CONNECT] ) ) { NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_CONNECT]); NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry); AFD_DbgPrint(MID_TRACE,("Completing connect %p\n", NextIrp)); NextIrp->IoStatus.Status = Status; NextIrp->IoStatus.Information = NT_SUCCESS(Status) ? ((ULONG_PTR)FCB->Connection.Handle) : 0; if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) ); (void)IoSetCancelRoutine(NextIrp, NULL); IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT ); } if( NT_SUCCESS(Status) ) { Status = MakeSocketIntoConnection( FCB ); if( !NT_SUCCESS(Status) ) { SocketStateUnlock( FCB ); return Status; } FCB->FilledConnectData = MIN(FCB->ConnectReturnInfo->UserDataLength, FCB->ConnectDataSize); if (FCB->FilledConnectData) { RtlCopyMemory(FCB->ConnectData, FCB->ConnectReturnInfo->UserData, FCB->FilledConnectData); } FCB->FilledConnectOptions = MIN(FCB->ConnectReturnInfo->OptionsLength, FCB->ConnectOptionsSize); if (FCB->FilledConnectOptions) { RtlCopyMemory(FCB->ConnectOptions, FCB->ConnectReturnInfo->Options, FCB->FilledConnectOptions); } if( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) { NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]); NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry); AFD_DbgPrint(MID_TRACE,("Launching send request %p\n", NextIrp)); Status = AfdConnectedSocketWriteData ( DeviceObject, NextIrp, IoGetCurrentIrpStackLocation( NextIrp ), FALSE ); } if( Status == STATUS_PENDING ) Status = STATUS_SUCCESS; } SocketStateUnlock( FCB ); AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status)); return Status; }
NTSTATUS ssh_interceptor_iodevice_dispatch_ioctl(PDEVICE_OBJECT device, PIRP irp) { #ifdef HAS_IOCTL_HANDLERS PIO_STACK_LOCATION io_stack = IoGetCurrentIrpStackLocation(irp); ULONG ioctl_code = io_stack->Parameters.DeviceIoControl.IoControlCode; SshInterceptorIoDevice io_dev = SSH_NTDEV_TO_SSHDEV(device); SshIoDeviceIoctlHandler handler = NULL; PLIST_ENTRY entry; NdisAcquireSpinLock(&io_dev->ioctl_handler_list_lock); entry = io_dev->ioctl_handler_list.Flink; while (entry != &io_dev->ioctl_handler_list) { SshIoDeviceIoctlHandler h; h = CONTAINING_RECORD(entry, SshIoDeviceIoctlHandlerStruct, link); if (h->ioctl_code == ioctl_code) { handler = h; InterlockedIncrement(&handler->ref_count); break; } entry = entry->Flink; } NdisReleaseSpinLock(&io_dev->ioctl_handler_list_lock); if (handler != NULL) { SshIoDeviceIoctlRequest ioctl; ioctl = ssh_calloc(1, sizeof(*ioctl)); if (ioctl == NULL) { irp->IoStatus.Status = STATUS_UNSUCCESSFUL; irp->IoStatus.Information = 0; IoCompleteRequest(irp, IO_NO_INCREMENT); return STATUS_UNSUCCESSFUL; } /* Initialize te IOCTL request */ ioctl->public_data.device = io_dev; ioctl->public_data.ioctl_code = ioctl_code; ioctl->public_data.context = handler; ioctl->public_data.cancel_id = ioctl; ioctl->public_data.input_buf_len = io_stack->Parameters.DeviceIoControl.InputBufferLength; ioctl->public_data.output_buf_len = io_stack->Parameters.DeviceIoControl.OutputBufferLength; switch (ioctl_code & 0x00000003) { case METHOD_BUFFERED: ioctl->public_data.input_buf = irp->AssociatedIrp.SystemBuffer; ioctl->public_data.output_buf = irp->AssociatedIrp.SystemBuffer; break; case METHOD_NEITHER: ioctl->public_data.input_buf = io_stack->Parameters.DeviceIoControl.Type3InputBuffer; ioctl->public_data.output_buf = irp->UserBuffer; break; case METHOD_IN_DIRECT: case METHOD_OUT_DIRECT: default: SSH_NOTREACHED; break; } ioctl->public_data.bytes_read = 0; ioctl->public_data.bytes_written = 0; ioctl->private_data.irp = irp; NdisAcquireSpinLock(&io_dev->ioctl_req_list_lock); InsertTailList(&io_dev->active_ioctl_req_list, &ioctl->private_data.link); NdisReleaseSpinLock(&io_dev->ioctl_req_list_lock); irp->IoStatus.Status = STATUS_PENDING; IoMarkIrpPending(irp); #pragma warning(disable: 4311 4312) IoSetCancelRoutine(irp, ssh_interceptor_iodevice_cancel_queued_ioctl); #pragma warning(default: 4311 4312) (*(handler->ioctl_handler))(handler->context, &ioctl->public_data); return STATUS_PENDING; } #endif /* HAS_IOCTL_HANDLERS */ irp->IoStatus.Status = STATUS_NOT_SUPPORTED; irp->IoStatus.Information = 0; IoCompleteRequest(irp, IO_NO_INCREMENT); return STATUS_NOT_SUPPORTED; }
static void ssh_interceptor_iodevice_do_reads(SshInterceptorIoDevice io_dev) { SshDeviceBuffer buffer; PIO_STACK_LOCATION irp_stack = NULL; char *dest = NULL; char *base_addr = NULL; PIRP irp = NULL; NdisAcquireSpinLock(&io_dev->output_queue_lock); buffer = io_dev->current_read_buf; NdisReleaseSpinLock(&io_dev->output_queue_lock); /* Complete as many queued output buffers and pending reads as possible */ while (TRUE) { PLIST_ENTRY entry; unsigned bytes_copied; /* Try to find some data to write */ if (buffer == NULL) { NdisAcquireSpinLock(&io_dev->output_queue_lock); if (!IsListEmpty(&io_dev->output_queue)) { entry = RemoveHeadList(&io_dev->output_queue); buffer = CONTAINING_RECORD(entry, SshDeviceBufferStruct, link); /* If this is an unreliable message, it must also be removed from the unreliable_output_queue! */ if (buffer->reliable == 0) RemoveEntryList(&buffer->unreliable_list_link); } io_dev->current_read_buf = buffer; NdisReleaseSpinLock(&io_dev->output_queue_lock); /* Exit the loop if no data was available in output queue */ if (buffer == NULL) goto complete; } /* Try to find queued read IRP */ if (irp == NULL) { entry = NdisInterlockedRemoveHeadList(&io_dev->read_queue, &io_dev->read_queue_lock); if (entry) { irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry); irp_stack = IoGetCurrentIrpStackLocation(irp); /* There is no need to check for canceled status, because cancelation is protected by the same lock as the queue itself. We may actually pop off an IRP for which cancel has already been issued, but we can complete it as usual. */ #pragma warning(disable: 4311 4312) IoSetCancelRoutine(irp, NULL); #pragma warning(default: 4311 4312) irp->IoStatus.Information = 0; irp->IoStatus.Status = STATUS_SUCCESS; base_addr = ssh_iodevice_map_buffer(irp->MdlAddress); if (base_addr == NULL) { /* Mapping of user-mode buffer could fail if the system is very low on resources. */ IoCompleteRequest(irp, IO_NETWORK_INCREMENT); irp = NULL; continue; } dest = base_addr; } else { /* No read IRPs available, exit the loop */ goto complete; } } /* We copy either the whole buffer or part of it if there isn't enough space left in the currently processed read IRP. */ bytes_copied = buffer->len; if (irp->IoStatus.Information + bytes_copied > irp_stack->Parameters.Read.Length) { bytes_copied = irp_stack->Parameters.Read.Length - (unsigned int)irp->IoStatus.Information; } NdisMoveMemory(dest, buffer->addr + buffer->offset, bytes_copied); buffer->offset += bytes_copied; buffer->len -= bytes_copied; if (buffer->len == 0) { NdisAcquireSpinLock(&io_dev->output_queue_lock); io_dev->current_read_buf = NULL; NdisReleaseSpinLock(&io_dev->output_queue_lock); ssh_iodevice_buffer_free(io_dev, buffer); buffer = NULL; } irp->IoStatus.Information += bytes_copied; dest += bytes_copied; /* If the IRP is now "full", complete the request */ if (irp->IoStatus.Information == irp_stack->Parameters.Read.Length) { ssh_iodevice_unmap_buffer(base_addr, irp->MdlAddress); IoCompleteRequest(irp, IO_NETWORK_INCREMENT); irp = NULL; base_addr = NULL; } } complete: /* We should also complete the partially filled IRP, if any */ if (irp) { ssh_iodevice_unmap_buffer(base_addr, irp->MdlAddress); IoCompleteRequest(irp, IO_NETWORK_INCREMENT); } }
int body() { if (nondet()) { // haven't stopped yet, lets do so ntStatus = t1394Diag_PnpStopDevice(DeviceObject, Irp); } ntStatus = IoSetDeviceInterfaceState(); // lets free up any crom data structs we've allocated... keA = 1; keA = 0; KeAcquireSpinLock(&lock3, &Irql); k1 = nondet(); while (k1>0) { CromData = nondet(); // get struct off list k1--; // need to free up everything associated with this allocate... if (CromData) { if (nondet()) ExFreePool0(); if (nondet()) IoFreeMdl(); // we already checked CromData ExFreePool1(CromData); } } keR = 1; keR = 0; KeReleaseSpinLock(&lock3, Irql); keA = 1; keA = 0; KeAcquireSpinLock(&lock1, &Irql); k2 = nondet(); while (k2>0) { AsyncAddressData = nondet(); // get struct off list AsyncAddressData = nondet(); k2--; // need to free up everything associated with this allocate... if (nondet()) IoFreeMdl(); if (nondet()) ExFreePool0(); if (nondet()) ExFreePool0(); if (AsyncAddressData) ExFreePool0(); } keR = 1; keR = 0; KeReleaseSpinLock(&lock1, Irql); // free up any attached isoch buffers while (TRUE) { keA = 1; keA = 0; KeAcquireSpinLock(&lock4, &Irql); k3 = nondet(); if (k3>0) { IsochDetachData = nondet(); i = nondet(); IsochDetachData = nondet(); k3--; KeCancelTimer(); keR = 1; keR = 0; KeReleaseSpinLock(&lock4, Irql); t1394_IsochCleanup(IsochDetachData); } else { keR = 1; keR = 0; KeReleaseSpinLock(&lock4, Irql); break; } } // remove any isoch resource data k4 = nondet(); while (TRUE) { keA = 1; keA = 0; KeAcquireSpinLock(&lock5, &Irql); if (k4>0) { IsochResourceData = nondet(); k4--; keR = 1; keR = 0; KeReleaseSpinLock(&lock5, Irql); if (IsochResourceData) { pIrb = nondet(); ResourceIrp = nondet(); StackSize = nondet(); ResourceIrp = IoAllocateIrp(StackSize, FALSE); if (ResourceIrp == NULL) { } else { pIrb = ExAllocatePool(NonPagedPool, sizeof(IRB)); if (!pIrb) { IoFreeIrp(ResourceIrp); } else { RtlZeroMemory (pIrb, sizeof (IRB)); ntStatus = t1394_SubmitIrpSynch(ResourceIrp, pIrb); ExFreePool1(pIrb); IoFreeIrp(ResourceIrp); } } } } else { keR = 1; keR = 0; KeReleaseSpinLock(&lock5, Irql); break; } } // get rid of any pending bus reset notify requests keA = 1; keA = 0; KeAcquireSpinLock(&lock6, &Irql); k5 = nondet(); while (k5>0) { prevCancel = NULL; // get the irp off of the list BusResetIrp = nondet(); k5--; // make this irp non-cancelable... prevCancel = IoSetCancelRoutine(NULL); // and complete it... IoCompleteRequest(IO_NO_INCREMENT); ExFreePool1(BusResetIrp); } keR = 1; keR = 0; KeReleaseSpinLock(&lock6, Irql); // free up the symbolic link while(1); } // t1394Diag_PnpRemoveDevice
VOID NbiProcessDatagram( IN NDIS_HANDLE MacBindingHandle, IN NDIS_HANDLE MacReceiveContext, IN PIPX_LOCAL_TARGET RemoteAddress, IN ULONG MacOptions, IN PUCHAR LookaheadBuffer, IN UINT LookaheadBufferSize, IN UINT LookaheadBufferOffset, IN UINT PacketSize, IN BOOLEAN Broadcast ) /*++ Routine Description: This routine handles datagram indications. Arguments: MacBindingHandle - A handle to use when calling NdisTransferData. MacReceiveContext - A context to use when calling NdisTransferData. RemoteAddress - The local target this packet was received from. MacOptions - The MAC options for the underlying NDIS binding. LookaheadBuffer - The lookahead buffer, starting at the IPX header. LookaheadBufferSize - The length of the lookahead data. LookaheadBufferOffset - The offset to add when calling NdisTransferData. PacketSize - The total length of the packet, starting at the IPX header. Broadcast - TRUE if the frame was a broadcast datagram. Return Value: None. --*/ { PADDRESS Address; NDIS_STATUS NdisStatus; PUCHAR NetbiosName; NB_CONNECTIONLESS UNALIGNED * Connectionless = (NB_CONNECTIONLESS UNALIGNED *)LookaheadBuffer; PDEVICE Device = NbiDevice; PSINGLE_LIST_ENTRY s; PNB_RECEIVE_RESERVED ReceiveReserved; PNB_RECEIVE_BUFFER ReceiveBuffer; ULONG DataOffset; UINT BytesTransferred; PNDIS_PACKET Packet; CTELockHandle LockHandle; // // See if there is an address that might want this. // if (Broadcast) { NetbiosName = (PVOID)-1; } else { NetbiosName = (PUCHAR)Connectionless->Datagram.DestinationName; if (Device->AddressCounts[NetbiosName[0]] == 0) { return; } } DataOffset = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM); #if defined(_PNP_POWER) if ((PacketSize < DataOffset) || (PacketSize > DataOffset + Device->CurMaxReceiveBufferSize)) { #else if ((PacketSize < DataOffset) || (PacketSize > DataOffset + Device->Bind.LineInfo.MaximumPacketSize)) { #endif _PNP_POWER NB_DEBUG (DATAGRAM, ("Datagram length %d discarded\n", PacketSize)); return; } Address = NbiFindAddress (Device, NetbiosName); if (Address == NULL) { return; } // // We need to cache the remote name if the packet came across the router. // This allows this machine to get back to the RAS client which might // have sent this datagram. We currently dont allow broadcasts to go out // on the dial-in line. // Dont cache some of the widely used group names, that would be too much // to store in cache. // #if 0 if ( Connectionless->IpxHeader.TransportControl && !( (Address->NetbiosAddress.NetbiosName[15] == 0x0 ) && (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) && !( (Address->NetbiosAddress.NetbiosName[15] == 0x01 ) && (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) && !( (Address->NetbiosAddress.NetbiosName[15] == 0x1E ) && (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) ) { #endif if ( Connectionless->IpxHeader.TransportControl && ( (Address->NetbiosAddress.NetbiosName[15] == 0x1c ) && (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) ) { PNETBIOS_CACHE CacheName; NB_GET_LOCK (&Device->Lock, &LockHandle); if ( FindInNetbiosCacheTable ( Device->NameCache, Connectionless->Datagram.SourceName, &CacheName ) != STATUS_SUCCESS ) { CacheName = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry"); if (CacheName ) { RtlCopyMemory (CacheName->NetbiosName, Connectionless->Datagram.SourceName, 16); CacheName->Unique = TRUE; CacheName->ReferenceCount = 1; RtlCopyMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12); CacheName->NetworksAllocated = 1; CacheName->NetworksUsed = 1; CacheName->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork); CacheName->Networks[0].LocalTarget = *RemoteAddress; NB_DEBUG2 (CACHE, ("Alloc new cache from Datagram %lx for <%.16s>\n", CacheName, CacheName->NetbiosName)); CacheName->TimeStamp = Device->CacheTimeStamp; InsertInNetbiosCacheTable( Device->NameCache, CacheName); } } else if ( CacheName->Unique ) { // // We already have an entry for this remote. We should update // the address. This is so that if the ras client dials-out // then dials-in again and gets a new address, we dont end up // caching the old address. // if ( !RtlEqualMemory( &CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12) ) { RtlCopyMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12); CacheName->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork); CacheName->Networks[0].LocalTarget = *RemoteAddress; } } NB_FREE_LOCK (&Device->Lock, LockHandle); } // // We need to allocate a packet and buffer for the transfer. // s = NbiPopReceivePacket (Device); if (s == NULL) { NbiDereferenceAddress (Address, AREF_FIND); return; } ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage); s = NbiPopReceiveBuffer (Device); if (s == NULL) { ExInterlockedPushEntrySList( &Device->ReceivePacketList, &ReceiveReserved->PoolLinkage, &NbiGlobalPoolInterlock); NbiDereferenceAddress (Address, AREF_FIND); return; } ReceiveBuffer = CONTAINING_RECORD (s, NB_RECEIVE_BUFFER, PoolLinkage); Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]); ReceiveReserved->u.RR_DG.ReceiveBuffer = ReceiveBuffer; // // Now that we have a packet and a buffer, set up the transfer. // The indication to the TDI clients will happen at receive // complete time. // NdisChainBufferAtFront (Packet, ReceiveBuffer->NdisBuffer); ReceiveBuffer->Address = Address; ReceiveReserved->Type = RECEIVE_TYPE_DATAGRAM; CTEAssert (!ReceiveReserved->TransferInProgress); ReceiveReserved->TransferInProgress = TRUE; TdiCopyLookaheadData( &ReceiveBuffer->RemoteName, Connectionless->Datagram.SourceName, 16, (MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) ? TDI_RECEIVE_COPY_LOOKAHEAD : 0); (*Device->Bind.TransferDataHandler) ( &NdisStatus, MacBindingHandle, MacReceiveContext, LookaheadBufferOffset + DataOffset, PacketSize - DataOffset, Packet, &BytesTransferred); if (NdisStatus != NDIS_STATUS_PENDING) { #if DBG if (NdisStatus == STATUS_SUCCESS) { CTEAssert (BytesTransferred == PacketSize - DataOffset); } #endif NbiTransferDataComplete( Packet, NdisStatus, BytesTransferred); } } /* NbiProcessDatagram */ VOID NbiIndicateDatagram( IN PADDRESS Address, IN PUCHAR RemoteName, IN PUCHAR Data, IN ULONG DataLength ) /*++ Routine Description: This routine indicates a datagram to clients on the specified address. It is called from NbiReceiveComplete. Arguments: Address - The address the datagram was sent to. RemoteName - The source netbios address of the datagram. Data - The data. DataLength - The length of the data. Return Value: None. --*/ { PLIST_ENTRY p, q; PIRP Irp; ULONG IndicateBytesCopied; PREQUEST Request; TA_NETBIOS_ADDRESS SourceName; PTDI_CONNECTION_INFORMATION RemoteInformation; PADDRESS_FILE AddressFile, ReferencedAddressFile; PTDI_CONNECTION_INFORMATION DatagramInformation; TDI_ADDRESS_NETBIOS UNALIGNED * DatagramAddress; PDEVICE Device = NbiDevice; NB_DEFINE_LOCK_HANDLE (LockHandle) CTELockHandle CancelLH; // // Update our statistics. // ++Device->Statistics.DatagramsReceived; ADD_TO_LARGE_INTEGER( &Device->Statistics.DatagramBytesReceived, DataLength); // // Call the client's ReceiveDatagram indication handler. He may // want to accept the datagram that way. // TdiBuildNetbiosAddress (RemoteName, FALSE, &SourceName); ReferencedAddressFile = NULL; NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle); for (p = Address->AddressFileDatabase.Flink; p != &Address->AddressFileDatabase; p = p->Flink) { // // Find the next open address file in the list. // AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage); if (AddressFile->State != ADDRESSFILE_STATE_OPEN) { continue; } NbiReferenceAddressFileLock (AddressFile, AFREF_INDICATION); // // do we have a datagram receive request outstanding? If so, we will // satisfy it first. We run through the receive datagram queue // until we find a datagram with no remote address or with // this sender's address as its remote address. // for (q = AddressFile->ReceiveDatagramQueue.Flink; q != &AddressFile->ReceiveDatagramQueue; q = q->Flink) { Request = LIST_ENTRY_TO_REQUEST (q); DatagramInformation = ((PTDI_REQUEST_KERNEL_RECEIVEDG) REQUEST_PARAMETERS(Request))->ReceiveDatagramInformation; if (DatagramInformation && (DatagramInformation->RemoteAddress) && (DatagramAddress = NbiParseTdiAddress(DatagramInformation->RemoteAddress, FALSE)) && (!RtlEqualMemory( RemoteName, DatagramAddress->NetbiosName, 16))) { continue; } break; } if (q != &AddressFile->ReceiveDatagramQueue) { RemoveEntryList (q); NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle); if (ReferencedAddressFile != NULL) { NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION); } ReferencedAddressFile = AddressFile; // // Do this deref now, we hold another one so it // will stick around. // NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM); IndicateBytesCopied = 0; // // Fall past the else to copy the data. // } else { NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle); if (ReferencedAddressFile != NULL) { NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION); } ReferencedAddressFile = AddressFile; // // No receive datagram requests; is there a kernel client? // if (AddressFile->RegisteredHandler[TDI_EVENT_RECEIVE_DATAGRAM]) { IndicateBytesCopied = 0; if ((*AddressFile->ReceiveDatagramHandler)( AddressFile->HandlerContexts[TDI_EVENT_RECEIVE_DATAGRAM], sizeof (TA_NETBIOS_ADDRESS), &SourceName, 0, NULL, TDI_RECEIVE_COPY_LOOKAHEAD, DataLength, // indicated DataLength, // available &IndicateBytesCopied, Data, &Irp) != STATUS_MORE_PROCESSING_REQUIRED) { // // The client did not return a request, go to the // next address file. // NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle); continue; } Request = NbiAllocateRequest (Device, Irp); IF_NOT_ALLOCATED(Request) { Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle); continue; } } else { // // The client has nothing posted and no handler, // go on to the next address file. // NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle); continue; } } // // We have a request; copy the actual user data. // if ( REQUEST_NDIS_BUFFER (Request) ) { REQUEST_STATUS(Request) = TdiCopyBufferToMdl ( Data, IndicateBytesCopied, DataLength - IndicateBytesCopied, REQUEST_NDIS_BUFFER (Request), 0, &REQUEST_INFORMATION (Request)); } else { // // No buffer specified in the request // REQUEST_INFORMATION (Request) = 0; // // If there was any data to be copied, return error o/w success // REQUEST_STATUS(Request) = ( (DataLength - IndicateBytesCopied) ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS ); } // // Copy the addressing information. // RemoteInformation = ((PTDI_REQUEST_KERNEL_RECEIVEDG) REQUEST_PARAMETERS(Request))->ReturnDatagramInformation; if (RemoteInformation != NULL) { RtlCopyMemory( (PTA_NETBIOS_ADDRESS)RemoteInformation->RemoteAddress, &SourceName, (RemoteInformation->RemoteAddressLength < sizeof(TA_NETBIOS_ADDRESS)) ? RemoteInformation->RemoteAddressLength : sizeof(TA_NETBIOS_ADDRESS)); } NB_GET_CANCEL_LOCK( &CancelLH ); IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL); NB_FREE_CANCEL_LOCK( CancelLH ); NbiCompleteRequest (Request); NbiFreeRequest (Device, Request); NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle); } // end of for loop through the address files
NTSTATUS NdisuioRead( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) /*++ Routine Description: Dispatch routine to handle IRP_MJ_READ. Arguments: pDeviceObject - pointer to our device object pIrp - Pointer to request packet Return Value: NT status code. --*/ { PIO_STACK_LOCATION pIrpSp; NTSTATUS NtStatus; PNDISUIO_OPEN_CONTEXT pOpenContext; pIrpSp = IoGetCurrentIrpStackLocation(pIrp); pOpenContext = pIrpSp->FileObject->FsContext; do { if (pOpenContext == NULL) { DEBUGP(DL_FATAL, ("Read: NULL FsContext on FileObject %p\n", pIrpSp->FileObject)); NtStatus = STATUS_INVALID_HANDLE; break; } NUIO_STRUCT_ASSERT(pOpenContext, oc); if (pIrp->MdlAddress == NULL) { DEBUGP(DL_FATAL, ("Read: NULL MDL address on IRP %p\n", pIrp)); NtStatus = STATUS_INVALID_PARAMETER; break; } // // Try to get a virtual address for the MDL. // #ifndef WIN9X if (MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority) == NULL) { DEBUGP(DL_FATAL, ("Read: MmGetSystemAddr failed for IRP %p, MDL %p\n", pIrp, pIrp->MdlAddress)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } #endif NUIO_ACQUIRE_LOCK(&pOpenContext->Lock); if (!NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE)) { NUIO_RELEASE_LOCK(&pOpenContext->Lock); NtStatus = STATUS_INVALID_HANDLE; break; } NtStatus = NdisuioDoFastRead(pOpenContext, pIrp); if (NtStatus == STATUS_SUCCESS) { // if successful, lock already unlocked return NtStatus; } // // Add this IRP to the list of pended Read IRPs // NUIO_INSERT_TAIL_LIST(&pOpenContext->PendedReads, &pIrp->Tail.Overlay.ListEntry); NUIO_REF_OPEN(pOpenContext); // pended read IRP pOpenContext->PendedReadCount++; // // Set up the IRP for possible cancellation. // pIrp->Tail.Overlay.DriverContext[0] = pOpenContext; IoMarkIrpPending(pIrp); IoSetCancelRoutine(pIrp, NdisuioCancelRead); NUIO_RELEASE_LOCK(&pOpenContext->Lock); NtStatus = STATUS_PENDING; } while (FALSE); if (NtStatus != STATUS_PENDING) { NUIO_ASSERT(NtStatus != STATUS_SUCCESS); pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = NtStatus; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } return (NtStatus); }
VOID ndisprotServiceReads( IN PNDISPROT_OPEN_CONTEXT pOpenContext ) /*++ Routine Description: Utility routine to copy received data into user buffers and complete READ IRPs. Arguments: pOpenContext - pointer to open context Return Value: None --*/ { PIRP pIrp = NULL; PLIST_ENTRY pIrpEntry; PNET_BUFFER_LIST pRcvNetBufList; PLIST_ENTRY pRcvNetBufListEntry; PUCHAR pSrc, pDst; ULONG BytesRemaining; // at pDst PMDL pMdl; ULONG BytesAvailable; BOOLEAN FoundPendingIrp = FALSE; ULONG SrcTotalLength = 0; // Source NetBuffer DataLenght ULONG Offset = 0; // CurrentMdlOffset ULONG BytesToCopy = 0; DEBUGP(DL_VERY_LOUD, ("ServiceReads: open %p/%x\n", pOpenContext, pOpenContext->Flags)); NPROT_REF_OPEN(pOpenContext); // temp ref - service reads NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE); while (!NPROT_IS_LIST_EMPTY(&pOpenContext->PendedReads) && !NPROT_IS_LIST_EMPTY(&pOpenContext->RecvNetBufListQueue)) { FoundPendingIrp = FALSE; // // Get the first pended Read IRP // pIrpEntry = pOpenContext->PendedReads.Flink; while (pIrpEntry != &pOpenContext->PendedReads) { pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry); // // Check to see if it is being cancelled. // if (IoSetCancelRoutine(pIrp, NULL)) { // // It isn't being cancelled, and can't be cancelled henceforth. // NPROT_REMOVE_ENTRY_LIST(pIrpEntry); FoundPendingIrp = TRUE; break; // // NOTE: we decrement PendedReadCount way below in the // while loop, to avoid letting through a thread trying // to unbind. // } else { // // The IRP is being cancelled; let the cancel routine handle it. // DEBUGP(DL_INFO, ("ServiceReads: open %p, skipping cancelled IRP %p\n", pOpenContext, pIrp)); pIrpEntry = pIrpEntry->Flink; } } if (FoundPendingIrp == FALSE) { break; } // // Get the first queued receive packet // pRcvNetBufListEntry = pOpenContext->RecvNetBufListQueue.Flink; NPROT_REMOVE_ENTRY_LIST(pRcvNetBufListEntry); pOpenContext->RecvNetBufListCount --; NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); NPROT_DEREF_OPEN(pOpenContext); // Service: dequeue rcv packet pRcvNetBufList = NPROT_RCV_NBL_FROM_LIST_ENTRY(pRcvNetBufListEntry); NPROT_ASSERT(pRcvNetBufList != NULL); _Analysis_assume_(pRcvNetBufList != NULL); NPROT_RCV_NBL_FROM_LIST_ENTRY(pRcvNetBufListEntry) = NULL; // // Copy as much data as possible from the receive packet to // the IRP MDL. // pDst = NULL; NdisQueryMdl(pIrp->MdlAddress, &pDst, &BytesRemaining, NormalPagePriority); NPROT_ASSERT(pDst != NULL); // since it was already mapped _Analysis_assume_(pDst != NULL); pMdl = NET_BUFFER_CURRENT_MDL(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList)); // // Copy the data in the received packet into the buffer provided by the client. // If the length of the receive packet is greater than length of the given buffer, // we just copy as many bytes as we can. Once the buffer is full, we just discard // the rest of the data, and complete the IRP sucessfully even we only did a partial copy. // SrcTotalLength = NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList)); Offset = NET_BUFFER_CURRENT_MDL_OFFSET(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList)); while (BytesRemaining && (pMdl != NULL) && SrcTotalLength) { pSrc = NULL; NdisQueryMdl(pMdl, &pSrc, &BytesAvailable, NormalPagePriority); if (pSrc == NULL) { DEBUGP(DL_FATAL, ("ServiceReads: Open %p, NdisQueryMdl failed for MDL %p\n", pOpenContext, pMdl)); break; } NPROT_ASSERT(BytesAvailable > Offset); BytesToCopy = MIN(BytesAvailable - Offset, BytesRemaining); BytesToCopy = MIN(BytesToCopy, SrcTotalLength); NPROT_COPY_MEM(pDst, pSrc + Offset, BytesToCopy); BytesRemaining -= BytesToCopy; pDst += BytesToCopy; SrcTotalLength -= BytesToCopy; // // CurrentMdlOffset is used only for the first Mdl processed. For the remaining Mdls, it is 0. // Offset = 0; NdisGetNextMdl(pMdl, &pMdl); } // // Complete the IRP. // pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = MmGetMdlByteCount(pIrp->MdlAddress) - BytesRemaining; DEBUGP(DL_INFO, ("ServiceReads: Open %p, IRP %p completed with %d bytes\n", pOpenContext, pIrp, (ULONG)pIrp->IoStatus.Information)); IoCompleteRequest(pIrp, IO_NO_INCREMENT); ndisprotFreeReceiveNetBufferList(pOpenContext, pRcvNetBufList,FALSE); NPROT_DEREF_OPEN(pOpenContext); // took out pended Read NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE); pOpenContext->PendedReadCount--; } NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); NPROT_DEREF_OPEN(pOpenContext); // temp ref - service reads }
VOID SoundAddIrpToCancellableQ( PLIST_ENTRY QueueHead, PIRP Irp, BOOLEAN Head ) /*++ Routine Description: Add the Irp to the queue and set the cancel routine under the protection of the cancel spin lock. Arguments: QueueHead - the queue to add it to Irp - the Irp Head - if TRUE insert at the head of the queue Return Value: None. --*/ { KIRQL OldIrql; // // Get the cancel spin lock so we can mess with the cancel stuff // IoAcquireCancelSpinLock(&OldIrql); // // Well, it may ALREADY be cancelled! // if (Irp->Cancel) { dprintf2(("Irp already cancelled")); // // Release the cancel spin lock // IoReleaseCancelSpinLock(OldIrql); // // Set status and complete // Irp->IoStatus.Status = STATUS_CANCELLED; IoCompleteRequest(Irp, IO_NO_INCREMENT); return; } // // Set the cancel routine // IoSetCancelRoutine(Irp, SoundRemoveAndComplete); // // Insert it in the queue // if (Head) { InsertHeadList(QueueHead, &Irp->Tail.Overlay.ListEntry); } else { InsertTailList(QueueHead, &Irp->Tail.Overlay.ListEntry); } // // Free the spin lock // IoReleaseCancelSpinLock(OldIrql); }
NTSTATUS NdisprotRead( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) /*++ Routine Description: Dispatch routine to handle IRP_MJ_READ. Arguments: pDeviceObject - pointer to our device object pIrp - Pointer to request packet Return Value: NT status code. --*/ { PIO_STACK_LOCATION pIrpSp; NTSTATUS NtStatus; PNDISPROT_OPEN_CONTEXT pOpenContext; UNREFERENCED_PARAMETER(pDeviceObject); pIrpSp = IoGetCurrentIrpStackLocation(pIrp); pOpenContext = pIrpSp->FileObject->FsContext; do { // // Validate! // if (pOpenContext == NULL) { DEBUGP(DL_FATAL, ("Read: NULL FsContext on FileObject %p\n", pIrpSp->FileObject)); NtStatus = STATUS_INVALID_HANDLE; break; } NPROT_STRUCT_ASSERT(pOpenContext, oc); if (pIrp->MdlAddress == NULL) { DEBUGP(DL_FATAL, ("Read: NULL MDL address on IRP %p\n", pIrp)); NtStatus = STATUS_INVALID_PARAMETER; break; } // // Try to get a virtual address for the MDL. // if (MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority) == NULL) { DEBUGP(DL_FATAL, ("Read: MmGetSystemAddr failed for IRP %p, MDL %p\n", pIrp, pIrp->MdlAddress)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE); if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE)) { NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); NtStatus = STATUS_INVALID_HANDLE; break; } IoSetCancelRoutine(pIrp, NdisprotCancelRead); if (pIrp->Cancel && IoSetCancelRoutine(pIrp, NULL)) { // // IRP has been canceled but the I/O manager did not manage to call our cancel routine. This // code is safe referencing the Irp->Cancel field without locks because of the memory barriers // in the interlocked exchange sequences used by IoSetCancelRoutine. // NtStatus = STATUS_CANCELLED; // IRP should be completed after releasing the lock } else { // // Add this IRP to the list of pended Read IRPs // NPROT_INSERT_TAIL_LIST(&pOpenContext->PendedReads, &pIrp->Tail.Overlay.ListEntry); pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext; NPROT_REF_OPEN(pOpenContext); // pended read IRP pOpenContext->PendedReadCount++; IoMarkIrpPending(pIrp); NtStatus = STATUS_PENDING; } NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); // // Run the service routine for reads. // ndisprotServiceReads(pOpenContext); } while (FALSE); if (NtStatus != STATUS_PENDING) { NPROT_ASSERT(NtStatus != STATUS_SUCCESS); pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = NtStatus; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } return (NtStatus); }
VOID SoundFreePendingIrps( PLIST_ENTRY QueueHead, PFILE_OBJECT FileObject ) { KIRQL OldIrql; // // Free anyone waiting for the volume to change whose file object // is the one about to be closed. // PLIST_ENTRY ListEntry, Next; // // Our list is cancellable so do this under the cancel spin // lock // IoAcquireCancelSpinLock(&OldIrql); for (ListEntry = QueueHead->Flink; ListEntry != QueueHead; ListEntry = Next) { PIRP IrpList; IrpList = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry); Next = ListEntry->Flink; ASSERT(IoGetCurrentIrpStackLocation(IrpList)->MajorFunction == IRP_MJ_DEVICE_CONTROL); if (FileObject == IoGetCurrentIrpStackLocation(IrpList)->FileObject) { RemoveEntryList(ListEntry); // // Make sure our cancel routine doesn't get in! // IoSetCancelRoutine(IrpList, NULL); // // Free the spin lock in case IoCompleteRequest doesn't // like us to hold it // IoReleaseCancelSpinLock(OldIrql); IrpList->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(IrpList, IO_NO_INCREMENT); IoAcquireCancelSpinLock(&OldIrql); // // The world may have changed so restart // Next = QueueHead->Flink; } } IoReleaseCancelSpinLock(OldIrql); }
VOID NdisProtSendComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET pNdisPacket, IN NDIS_STATUS Status ) /*++ Routine Description: NDIS entry point called to signify completion of a packet send. We pick up and complete the Write IRP corresponding to this packet. NDIS 5.1: Arguments: ProtocolBindingContext - pointer to open context pNdisPacket - packet that completed send Status - status of send Return Value: None --*/ { PIRP pIrp; PIO_STACK_LOCATION pIrpSp; PNDISPROT_OPEN_CONTEXT pOpenContext; pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext; NPROT_STRUCT_ASSERT(pOpenContext, oc); pIrp = NPROT_IRP_FROM_SEND_PKT(pNdisPacket); if (pOpenContext->bRunningOnWin9x) { // // We would have attached our own NDIS_BUFFER. Take it out // and free it. // #ifndef NDIS51 PNDIS_BUFFER pNdisBuffer; PVOID VirtualAddr; UINT BufferLength; UINT TotalLength; #endif #ifdef NDIS51 NPROT_ASSERT(FALSE); // NDIS 5.1 not on Win9X! #else NdisGetFirstBufferFromPacket( pNdisPacket, &pNdisBuffer, &VirtualAddr, &BufferLength, &TotalLength); NPROT_ASSERT(pNdisBuffer != NULL); NdisFreeBuffer(pNdisBuffer); #endif } #ifdef NDIS51 IoSetCancelRoutine(pIrp, NULL); NPROT_ACQUIRE_LOCK(&pOpenContext->Lock); NPROT_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry); NPROT_RELEASE_LOCK(&pOpenContext->Lock); #endif // // We are done with the NDIS_PACKET: // NPROT_DEREF_SEND_PKT(pNdisPacket); // // Complete the Write IRP with the right status. // pIrpSp = IoGetCurrentIrpStackLocation(pIrp); if (Status == NDIS_STATUS_SUCCESS) { pIrp->IoStatus.Information = pIrpSp->Parameters.Write.Length; pIrp->IoStatus.Status = STATUS_SUCCESS; } else { pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; } DEBUGP(DL_INFO, ("SendComplete: packet %p/IRP %p/Length %d " "completed with status %x\n", pNdisPacket, pIrp, pIrp->IoStatus.Information, pIrp->IoStatus.Status)); IoCompleteRequest(pIrp, IO_NO_INCREMENT); NdisInterlockedDecrement((PLONG)&pOpenContext->PendedSendCount); NPROT_DEREF_OPEN(pOpenContext); // send complete - dequeued send IRP }
NTSTATUS NbfTdiReceiveDatagram( IN PIRP Irp ) /*++ Routine Description: This routine performs the TdiReceiveDatagram request for the transport provider. Receive datagrams just get queued up to an address, and are completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at the address. Arguments: Irp - I/O Request Packet for this request. Return Value: NTSTATUS - status of operation. --*/ { NTSTATUS status; KIRQL oldirql; PTP_ADDRESS address; PTP_ADDRESS_FILE addressFile; PIO_STACK_LOCATION irpSp; KIRQL cancelIrql; // // verify that the operation is taking place on an address. At the same // time we do this, we reference the address. This ensures it does not // get removed out from under us. Note also that we do the address // lookup within a try/except clause, thus protecting ourselves against // really bogus handles // irpSp = IoGetCurrentIrpStackLocation (Irp); addressFile = irpSp->FileObject->FsContext; status = NbfVerifyAddressObject (addressFile); if (!NT_SUCCESS (status)) { return status; } #if DBG if (((PTDI_REQUEST_KERNEL_RECEIVEDG)(&irpSp->Parameters))->ReceiveLength > 0) { ASSERT (Irp->MdlAddress != NULL); } #endif address = addressFile->Address; IoAcquireCancelSpinLock(&cancelIrql); ACQUIRE_SPIN_LOCK (&address->SpinLock,&oldirql); if ((address->Flags & (ADDRESS_FLAGS_STOPPING | ADDRESS_FLAGS_CONFLICT)) != 0) { RELEASE_SPIN_LOCK (&address->SpinLock,oldirql); IoReleaseCancelSpinLock(cancelIrql); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = (address->Flags & ADDRESS_FLAGS_STOPPING) ? STATUS_NETWORK_NAME_DELETED : STATUS_DUPLICATE_NAME; IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); } else { // // If this IRP has been cancelled, then call the // cancel routine. // if (Irp->Cancel) { RELEASE_SPIN_LOCK (&address->SpinLock, oldirql); IoReleaseCancelSpinLock(cancelIrql); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_CANCELLED; IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); } else { IoSetCancelRoutine(Irp, NbfCancelReceiveDatagram); NbfReferenceAddress ("Receive datagram", address, AREF_REQUEST); InsertTailList (&addressFile->ReceiveDatagramQueue,&Irp->Tail.Overlay.ListEntry); RELEASE_SPIN_LOCK (&address->SpinLock,oldirql); IoReleaseCancelSpinLock(cancelIrql); } } NbfDereferenceAddress ("Temp rcv datagram", address, AREF_VERIFY); return STATUS_PENDING; } /* TdiReceiveDatagram */
NTSTATUS NTAPI NpSetClosingPipeState(IN PNP_CCB Ccb, IN PIRP Irp, IN ULONG NamedPipeEnd, IN PLIST_ENTRY List) { PNP_NONPAGED_CCB NonPagedCcb; PNP_FCB Fcb; PLIST_ENTRY NextEntry; PNP_DATA_QUEUE ReadQueue, WriteQueue, DataQueue; PNP_EVENT_BUFFER EventBuffer; PIRP ListIrp; NonPagedCcb = Ccb->NonPagedCcb; Fcb = Ccb->Fcb; switch (Ccb->NamedPipeState) { case FILE_PIPE_LISTENING_STATE: ASSERT(NamedPipeEnd == FILE_PIPE_SERVER_END); while (!IsListEmpty(&Ccb->IrpList)) { NextEntry = RemoveHeadList(&Ccb->IrpList); ListIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry); if (IoSetCancelRoutine(ListIrp, NULL)) { ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN; InsertTailList(List, NextEntry); } else { InitializeListHead(NextEntry); } } // Drop on purpose case FILE_PIPE_DISCONNECTED_STATE: ASSERT(NamedPipeEnd == FILE_PIPE_SERVER_END); NpSetFileObject(Ccb->FileObject[FILE_PIPE_SERVER_END], NULL, NULL, TRUE); Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL; NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE); Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL; NpDeleteCcb(Ccb, List); if (!Fcb->CurrentInstances) NpDeleteFcb(Fcb, List); break; case FILE_PIPE_CLOSING_STATE: if (NamedPipeEnd == FILE_PIPE_SERVER_END) { DataQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND]; } else { DataQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND]; } NpSetFileObject(Ccb->FileObject[FILE_PIPE_SERVER_END], NULL, NULL, TRUE); Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL; NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE); Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL; while (DataQueue->QueueState != Empty) { ListIrp = NpRemoveDataQueueEntry(DataQueue, FALSE, List); if (ListIrp) { ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN; InsertTailList(List, &ListIrp->Tail.Overlay.ListEntry); } } NpUninitializeSecurity(Ccb); if (Ccb->ClientSession) { ExFreePool(Ccb->ClientSession); Ccb->ClientSession = NULL; } NpDeleteCcb(Ccb, List); if (!Fcb->CurrentInstances) NpDeleteFcb(Fcb, List); break; case FILE_PIPE_CONNECTED_STATE: if (NamedPipeEnd == FILE_PIPE_SERVER_END) { ReadQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND]; WriteQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND]; NpSetFileObject(Ccb->FileObject[FILE_PIPE_SERVER_END], NULL, NULL, TRUE); Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL; } else { ReadQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND]; WriteQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND]; NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE); Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL; } EventBuffer = NonPagedCcb->EventBuffer[NamedPipeEnd]; Ccb->NamedPipeState = FILE_PIPE_CLOSING_STATE; while (ReadQueue->QueueState != Empty) { ListIrp = NpRemoveDataQueueEntry(ReadQueue, FALSE, List); if (ListIrp) { ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN; InsertTailList(List, &ListIrp->Tail.Overlay.ListEntry); } } while (WriteQueue->QueueState == ReadEntries) { ListIrp = NpRemoveDataQueueEntry(WriteQueue, FALSE, List); if (ListIrp) { ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN; InsertTailList(List, &ListIrp->Tail.Overlay.ListEntry); } } if (EventBuffer) KeSetEvent(EventBuffer->Event, IO_NO_INCREMENT, FALSE); break; default: NpBugCheck(Ccb->NamedPipeState, 0, 0); break; } return STATUS_SUCCESS; }
NTSTATUS NbfTdiReceive( IN PIRP Irp ) /*++ Routine Description: This routine performs the TdiReceive request for the transport provider. Arguments: Irp - I/O Request Packet for this request. Return Value: NTSTATUS - status of operation. --*/ { NTSTATUS status; PTP_CONNECTION connection; KIRQL oldirql; PIO_STACK_LOCATION irpSp; // // verify that the operation is taking place on a connection. At the same // time we do this, we reference the connection. This ensures it does not // get removed out from under us. Note also that we do the connection // lookup within a try/except clause, thus protecting ourselves against // really bogus handles // irpSp = IoGetCurrentIrpStackLocation (Irp); connection = irpSp->FileObject->FsContext; // // Check that this is really a connection. // if ((connection->Size != sizeof (TP_CONNECTION)) || (connection->Type != NBF_CONNECTION_SIGNATURE)) { #if DBG NbfPrint2 ("TdiReceive: Invalid Connection %lx Irp %lx\n", connection, Irp); #endif return STATUS_INVALID_CONNECTION; } // // Initialize bytes transferred here. // Irp->IoStatus.Information = 0; // reset byte transfer count. // This reference is removed by NbfDestroyRequest. KeRaiseIrql (DISPATCH_LEVEL, &oldirql); ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock); if ((connection->Flags & CONNECTION_FLAGS_READY) == 0) { RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock); Irp->IoStatus.Status = connection->Status; IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); status = STATUS_PENDING; } else { KIRQL cancelIrql; // // Once the reference is in, LinkSpinLock will be valid. // NbfReferenceConnection("TdiReceive request", connection, CREF_RECEIVE_IRP); RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock); IoAcquireCancelSpinLock(&cancelIrql); ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock); IRP_RECEIVE_IRP(irpSp) = Irp; IRP_RECEIVE_REFCOUNT(irpSp) = 1; #if DBG NbfReceives[NbfReceivesNext].Irp = Irp; NbfReceives[NbfReceivesNext].Request = NULL; NbfReceives[NbfReceivesNext].Connection = (PVOID)connection; NbfReceivesNext = (NbfReceivesNext++) % TRACK_TDI_LIMIT; #endif // // If this IRP has been cancelled, complete it now. // if (Irp->Cancel) { #if DBG NbfCompletedReceives[NbfCompletedReceivesNext].Irp = Irp; NbfCompletedReceives[NbfCompletedReceivesNext].Request = NULL; NbfCompletedReceives[NbfCompletedReceivesNext].Status = STATUS_CANCELLED; { ULONG i,j,k; PUCHAR va; PMDL mdl; mdl = Irp->MdlAddress; NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = (UCHAR)0; i = 1; while (i<TRACK_TDI_CAPTURE) { if (mdl == NULL) break; va = MmGetSystemAddressForMdl (mdl); j = MmGetMdlByteCount (mdl); for (i=i,k=0;i<TRACK_TDI_CAPTURE&k<j;i++,k++) { NbfCompletedReceives[NbfCompletedReceivesNext].Contents[i] = *va++; } mdl = mdl->Next; } } NbfCompletedReceivesNext = (NbfCompletedReceivesNext++) % TRACK_TDI_LIMIT; #endif // // It is safe to do this with locks held. // NbfCompleteReceiveIrp (Irp, STATUS_CANCELLED, 0); RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock); IoReleaseCancelSpinLock(cancelIrql); } else { // // Insert onto the receive queue, and make the IRP // cancellable. // InsertTailList (&connection->ReceiveQueue,&Irp->Tail.Overlay.ListEntry); IoSetCancelRoutine(Irp, NbfCancelReceive); // // Release the cancel spinlock out of order. Since we were // already at dpc level when it was acquired, we don't // need to swap irqls. // ASSERT(cancelIrql == DISPATCH_LEVEL); IoReleaseCancelSpinLock(cancelIrql); // // This call releases the link spinlock, and references the // connection first if it needs to access it after // releasing the lock. // AwakenReceive (connection); // awaken if sleeping. } status = STATUS_PENDING; } KeLowerIrql (oldirql); return status; } /* TdiReceive */
VOID NotificationLoop( __in PIRP_LIST PendingIrp, __in PIRP_LIST NotifyEvent ) { PDRIVER_EVENT_CONTEXT driverEventContext; PLIST_ENTRY listHead; PIRP_ENTRY irpEntry; LIST_ENTRY completeList; NTSTATUS status; KIRQL irpIrql; KIRQL notifyIrql; PIRP irp; ULONG eventLen; ULONG bufferLen; PVOID buffer; //DDbgPrint("=> NotificationLoop\n"); InitializeListHead(&completeList); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KeAcquireSpinLock(&PendingIrp->ListLock, &irpIrql); KeAcquireSpinLock(&NotifyEvent->ListLock, ¬ifyIrql); while (!IsListEmpty(&PendingIrp->ListHead) && !IsListEmpty(&NotifyEvent->ListHead)) { listHead = RemoveHeadList(&NotifyEvent->ListHead); driverEventContext = CONTAINING_RECORD( listHead, DRIVER_EVENT_CONTEXT, ListEntry); listHead = RemoveHeadList(&PendingIrp->ListHead); irpEntry = CONTAINING_RECORD(listHead, IRP_ENTRY, ListEntry); eventLen = driverEventContext->EventContext.Length; // ensure this eventIrp is not cancelled irp = irpEntry->Irp; if (irp == NULL) { // this IRP has already been canceled ASSERT(irpEntry->CancelRoutineFreeMemory == FALSE); ExFreePool(irpEntry); // push back InsertTailList(&NotifyEvent->ListHead, &driverEventContext->ListEntry); continue; } if (IoSetCancelRoutine(irp, NULL) == NULL) { // Cancel routine will run as soon as we release the lock InitializeListHead(&irpEntry->ListEntry); irpEntry->CancelRoutineFreeMemory = TRUE; // push back InsertTailList(&NotifyEvent->ListHead, &driverEventContext->ListEntry); continue; } // available size that is used for event notification bufferLen = irpEntry->IrpSp->Parameters.DeviceIoControl.OutputBufferLength; // buffer that is used to inform Event buffer = irp->AssociatedIrp.SystemBuffer; // buffer is not specified or short of length if (bufferLen == 0 || buffer == NULL || bufferLen < eventLen) { DDbgPrint("EventNotice : STATUS_INSUFFICIENT_RESOURCES\n"); DDbgPrint(" bufferLen: %d, eventLen: %d\n", bufferLen, eventLen); // push back InsertTailList(&NotifyEvent->ListHead, &driverEventContext->ListEntry); // marks as STATUS_INSUFFICIENT_RESOURCES irpEntry->SerialNumber = 0; } else { // let's copy EVENT_CONTEXT RtlCopyMemory(buffer, &driverEventContext->EventContext, eventLen); // save event length irpEntry->SerialNumber = eventLen; ExFreePool(driverEventContext); } InsertTailList(&completeList, &irpEntry->ListEntry); } KeClearEvent(&NotifyEvent->NotEmpty); KeClearEvent(&PendingIrp->NotEmpty); KeReleaseSpinLock(&NotifyEvent->ListLock, notifyIrql); KeReleaseSpinLock(&PendingIrp->ListLock, irpIrql); while (!IsListEmpty(&completeList)) { listHead = RemoveHeadList(&completeList); irpEntry = CONTAINING_RECORD(listHead, IRP_ENTRY, ListEntry); irp = irpEntry->Irp; if (irpEntry->SerialNumber == 0) { irp->IoStatus.Information = 0; irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; } else { irp->IoStatus.Information = irpEntry->SerialNumber; irp->IoStatus.Status = STATUS_SUCCESS; } ExFreePool(irpEntry); IoCompleteRequest(irp, IO_NO_INCREMENT); } //DDbgPrint("<= NotificationLoop\n"); }
NTSTATUS Notification_Recieve(NOTIFICATION_QUEUE *queue, PIRP irp) { PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(irp); KIRQL irq; if(irpstack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(PBNOTIFICATION)) { irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; irp->IoStatus.Information = 0; IoCompleteRequest(irp, IO_NO_INCREMENT); return STATUS_BUFFER_TOO_SMALL; } KeAcquireSpinLock(&queue->lock, &irq); if(IsListEmpty(&queue->notification_list)) { PBIRPNODE *irpnode; KIRQL crirq; irpnode = ExAllocateFromNPagedLookasideList(&queue->lookaside); InitializeListHead(&irpnode->entry); irpnode->irp = irp; //irp->Tail.Overlay.DriverContext[0] = irpnode; InsertTailList(&queue->irp_list, &irpnode->entry); IoMarkIrpPending(irp); IoAcquireCancelSpinLock(&crirq); #pragma warning(push) #pragma warning(disable:4311 4312) //IoSetCancelRoutine generates warnings in 32-bit due to silly macroisms. IoSetCancelRoutine(irp, Notification_OnCancel); #pragma warning(pop) IoReleaseCancelSpinLock(crirq); KeReleaseSpinLock(&queue->lock, irq); return STATUS_PENDING; } else { PBNOTIFYNODE *notifynode = (PBNOTIFYNODE*)RemoveHeadList(&queue->notification_list); PBNOTIFICATION *notification = irp->AssociatedIrp.SystemBuffer; RtlCopyMemory(notification, ¬ifynode->notification, sizeof(PBNOTIFICATION)); ExFreeToNPagedLookasideList(&queue->lookaside, notifynode); --queue->queued; KeReleaseSpinLock(&queue->lock, irq); irp->IoStatus.Status = STATUS_SUCCESS; irp->IoStatus.Information = sizeof(PBNOTIFICATION); IoCompleteRequest(irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } }
static VOID MainThreadProc (PVOID threadArg) { EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg; PLIST_ENTRY listEntry; EncryptedIoQueueItem *item; LARGE_INTEGER fragmentOffset; ULONG dataRemaining; PUCHAR activeFragmentBuffer = queue->FragmentBufferA; PUCHAR dataBuffer; EncryptedIoRequest *request; uint64 intersectStart; uint32 intersectLength; ULONGLONG addResult; HRESULT hResult; if (IsEncryptionThreadPoolRunning()) KeSetPriorityThread (KeGetCurrentThread(), LOW_REALTIME_PRIORITY); while (!queue->ThreadExitRequested) { if (!NT_SUCCESS (KeWaitForSingleObject (&queue->MainThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL))) continue; while ((listEntry = ExInterlockedRemoveHeadList (&queue->MainThreadQueue, &queue->MainThreadQueueLock))) { PIRP irp = CONTAINING_RECORD (listEntry, IRP, Tail.Overlay.ListEntry); PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp); if (queue->Suspended) KeWaitForSingleObject (&queue->QueueResumedEvent, Executive, KernelMode, FALSE, NULL); item = GetPoolBuffer (queue, sizeof (EncryptedIoQueueItem)); if (!item) { TCCompleteDiskIrp (irp, STATUS_INSUFFICIENT_RESOURCES, 0); DecrementOutstandingIoCount (queue); IoReleaseRemoveLock (&queue->RemoveLock, irp); continue; } item->Queue = queue; item->OriginalIrp = irp; item->Status = STATUS_SUCCESS; IoSetCancelRoutine (irp, NULL); if (irp->Cancel) { CompleteOriginalIrp (item, STATUS_CANCELLED, 0); continue; } switch (irpSp->MajorFunction) { case IRP_MJ_READ: item->Write = FALSE; item->OriginalOffset = irpSp->Parameters.Read.ByteOffset; item->OriginalLength = irpSp->Parameters.Read.Length; break; case IRP_MJ_WRITE: item->Write = TRUE; item->OriginalOffset = irpSp->Parameters.Write.ByteOffset; item->OriginalLength = irpSp->Parameters.Write.Length; break; default: CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0); continue; } #ifdef TC_TRACE_IO_QUEUE item->OriginalIrpOffset = item->OriginalOffset; #endif // Handle misaligned read operations to work around a bug in Windows System Assessment Tool which does not follow FILE_FLAG_NO_BUFFERING requirements when benchmarking disk devices if (queue->IsFilterDevice && !item->Write && item->OriginalLength > 0 && (item->OriginalLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) == 0 && (item->OriginalOffset.QuadPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0) { byte *buffer; ULONG alignedLength; LARGE_INTEGER alignedOffset; hResult = ULongAdd(item->OriginalLength, ENCRYPTION_DATA_UNIT_SIZE, &alignedLength); if (hResult != S_OK) { CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0); continue; } alignedOffset.QuadPart = item->OriginalOffset.QuadPart & ~((LONGLONG) ENCRYPTION_DATA_UNIT_SIZE - 1); buffer = TCalloc (alignedLength); if (!buffer) { CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0); continue; } item->Status = TCReadDevice (queue->LowerDeviceObject, buffer, alignedOffset, alignedLength); if (NT_SUCCESS (item->Status)) { UINT64_STRUCT dataUnit; dataBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe (irp->MdlAddress, HighPagePriority); if (!dataBuffer) { TCfree (buffer); CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0); continue; } if (queue->EncryptedAreaStart != -1 && queue->EncryptedAreaEnd != -1) { GetIntersection (alignedOffset.QuadPart, alignedLength, queue->EncryptedAreaStart, queue->EncryptedAreaEnd, &intersectStart, &intersectLength); if (intersectLength > 0) { dataUnit.Value = intersectStart / ENCRYPTION_DATA_UNIT_SIZE; DecryptDataUnits (buffer + (intersectStart - alignedOffset.QuadPart), &dataUnit, intersectLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo); } } memcpy (dataBuffer, buffer + (item->OriginalOffset.LowPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)), item->OriginalLength); } TCfree (buffer); CompleteOriginalIrp (item, item->Status, NT_SUCCESS (item->Status) ? item->OriginalLength : 0); continue; } // Validate offset and length if (item->OriginalLength == 0 || (item->OriginalLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0 || (item->OriginalOffset.QuadPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0 || ( !queue->IsFilterDevice && ( (S_OK != ULongLongAdd(item->OriginalOffset.QuadPart, item->OriginalLength, &addResult)) || (addResult > (ULONGLONG) queue->VirtualDeviceLength) ) ) ) { CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0); continue; } #ifdef TC_TRACE_IO_QUEUE Dump ("Q %I64d [%I64d] %c len=%d\n", item->OriginalOffset.QuadPart, GetElapsedTime (&queue->LastPerformanceCounter), item->Write ? 'W' : 'R', item->OriginalLength); #endif if (!queue->IsFilterDevice) { // Adjust the offset for host file or device if (queue->CryptoInfo->hiddenVolume) hResult = ULongLongAdd(item->OriginalOffset.QuadPart, queue->CryptoInfo->hiddenVolumeOffset, &addResult); else hResult = ULongLongAdd(item->OriginalOffset.QuadPart, queue->CryptoInfo->volDataAreaOffset, &addResult); if (hResult != S_OK) { CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0); continue; } else item->OriginalOffset.QuadPart = addResult; // Hidden volume protection if (item->Write && queue->CryptoInfo->bProtectHiddenVolume) { // If there has already been a write operation denied in order to protect the // hidden volume (since the volume mount time) if (queue->CryptoInfo->bHiddenVolProtectionAction) { // Do not allow writing to this volume anymore. This is to fake a complete volume // or system failure (otherwise certain kinds of inconsistency within the file // system could indicate that this volume has used hidden volume protection). CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0); continue; } // Verify that no byte is going to be written to the hidden volume area if (RegionsOverlap ((unsigned __int64) item->OriginalOffset.QuadPart, (unsigned __int64) item->OriginalOffset.QuadPart + item->OriginalLength - 1, queue->CryptoInfo->hiddenVolumeOffset, (unsigned __int64) queue->CryptoInfo->hiddenVolumeOffset + queue->CryptoInfo->hiddenVolumeProtectedSize - 1)) { Dump ("Hidden volume protection triggered: write %I64d-%I64d (protected %I64d-%I64d)\n", item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, queue->CryptoInfo->hiddenVolumeOffset, queue->CryptoInfo->hiddenVolumeOffset + queue->CryptoInfo->hiddenVolumeProtectedSize - 1); queue->CryptoInfo->bHiddenVolProtectionAction = TRUE; // Deny this write operation to prevent the hidden volume from being overwritten CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0); continue; } } } else if (item->Write && RegionsOverlap (item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET, TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET + TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE - 1)) { // Prevent inappropriately designed software from damaging important data that may be out of sync with the backup on the Rescue Disk (such as the end of the encrypted area). Dump ("Preventing write to the system encryption key data area\n"); CompleteOriginalIrp (item, STATUS_MEDIA_WRITE_PROTECTED, 0); continue; } else if (item->Write && IsHiddenSystemRunning() && (RegionsOverlap (item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, TC_SECTOR_SIZE_BIOS, TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS - 1) || RegionsOverlap (item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, GetBootDriveLength(), _I64_MAX))) { Dump ("Preventing write to boot loader or host protected area\n"); CompleteOriginalIrp (item, STATUS_MEDIA_WRITE_PROTECTED, 0); continue; } dataBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe (irp->MdlAddress, HighPagePriority); if (dataBuffer == NULL) { CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0); continue; } // Divide data block to fragments to enable efficient overlapping of encryption and IO operations dataRemaining = item->OriginalLength; fragmentOffset = item->OriginalOffset; while (dataRemaining > 0) { BOOL isLastFragment = dataRemaining <= TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE; ULONG dataFragmentLength = isLastFragment ? dataRemaining : TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE; activeFragmentBuffer = (activeFragmentBuffer == queue->FragmentBufferA ? queue->FragmentBufferB : queue->FragmentBufferA); InterlockedIncrement (&queue->IoThreadPendingRequestCount); // Create IO request request = GetPoolBuffer (queue, sizeof (EncryptedIoRequest)); if (!request) { CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0); break; } request->Item = item; request->CompleteOriginalIrp = isLastFragment; request->Offset = fragmentOffset; request->Data = activeFragmentBuffer; request->OrigDataBufferFragment = dataBuffer; request->Length = dataFragmentLength; if (queue->IsFilterDevice) { if (queue->EncryptedAreaStart == -1 || queue->EncryptedAreaEnd == -1) { request->EncryptedLength = 0; } else { // Get intersection of data fragment with encrypted area GetIntersection (fragmentOffset.QuadPart, dataFragmentLength, queue->EncryptedAreaStart, queue->EncryptedAreaEnd, &intersectStart, &intersectLength); request->EncryptedOffset = intersectStart - fragmentOffset.QuadPart; request->EncryptedLength = intersectLength; } } else { request->EncryptedOffset = 0; request->EncryptedLength = dataFragmentLength; } AcquireFragmentBuffer (queue, activeFragmentBuffer); if (item->Write) { // Encrypt data memcpy (activeFragmentBuffer, dataBuffer, dataFragmentLength); if (request->EncryptedLength > 0) { UINT64_STRUCT dataUnit; ASSERT (request->EncryptedOffset + request->EncryptedLength <= request->Offset.QuadPart + request->Length); dataUnit.Value = (request->Offset.QuadPart + request->EncryptedOffset) / ENCRYPTION_DATA_UNIT_SIZE; if (queue->CryptoInfo->bPartitionInInactiveSysEncScope) dataUnit.Value += queue->CryptoInfo->FirstDataUnitNo.Value; else if (queue->RemapEncryptedArea) dataUnit.Value += queue->RemappedAreaDataUnitOffset; EncryptDataUnits (activeFragmentBuffer + request->EncryptedOffset, &dataUnit, request->EncryptedLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo); } } // Queue IO request ExInterlockedInsertTailList (&queue->IoThreadQueue, &request->ListEntry, &queue->IoThreadQueueLock); KeSetEvent (&queue->IoThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE); if (isLastFragment) break; dataRemaining -= TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE; dataBuffer += TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE; fragmentOffset.QuadPart += TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE; } } } PsTerminateSystemThread (STATUS_SUCCESS); }
NTSTATUS NTAPI AfdSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp ) { NTSTATUS Status = STATUS_NO_MEMORY; PAFD_FCB FCB; PFILE_OBJECT FileObject; PAFD_POLL_INFO PollReq = Irp->AssociatedIrp.SystemBuffer; PAFD_DEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension; KIRQL OldIrql; UINT i, Signalled = 0; ULONG Exclusive = PollReq->Exclusive; UNREFERENCED_PARAMETER(IrpSp); AFD_DbgPrint(MID_TRACE,("Called (HandleCount %u Timeout %d)\n", PollReq->HandleCount, (INT)(PollReq->Timeout.QuadPart))); SET_AFD_HANDLES(PollReq, LockHandles( PollReq->Handles, PollReq->HandleCount )); if( !AFD_HANDLES(PollReq) ) { Irp->IoStatus.Status = STATUS_NO_MEMORY; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_NETWORK_INCREMENT ); return STATUS_NO_MEMORY; } if( Exclusive ) { for( i = 0; i < PollReq->HandleCount; i++ ) { if( !AFD_HANDLES(PollReq)[i].Handle ) continue; KillSelectsForFCB( DeviceExt, (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle, TRUE ); } } KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql ); for( i = 0; i < PollReq->HandleCount; i++ ) { if( !AFD_HANDLES(PollReq)[i].Handle ) continue; FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle; FCB = FileObject->FsContext; AFD_DbgPrint(MID_TRACE, ("AFD: Select Events: ")); PrintEvents( PollReq->Handles[i].Events ); AFD_DbgPrint(MID_TRACE,("\n")); PollReq->Handles[i].Status = PollReq->Handles[i].Events & FCB->PollState; if( PollReq->Handles[i].Status ) { AFD_DbgPrint(MID_TRACE,("Signalling %p with %x\n", FCB, FCB->PollState)); Signalled++; } } if( Signalled ) { Status = STATUS_SUCCESS; Irp->IoStatus.Status = Status; SignalSocket( NULL, Irp, PollReq, Status ); } else { PAFD_ACTIVE_POLL Poll = NULL; Poll = ExAllocatePool( NonPagedPool, sizeof(AFD_ACTIVE_POLL) ); if (Poll){ Poll->Irp = Irp; Poll->DeviceExt = DeviceExt; Poll->Exclusive = Exclusive; KeInitializeTimerEx( &Poll->Timer, NotificationTimer ); KeInitializeDpc( (PRKDPC)&Poll->TimeoutDpc, SelectTimeout, Poll ); InsertTailList( &DeviceExt->Polls, &Poll->ListEntry ); KeSetTimer( &Poll->Timer, PollReq->Timeout, &Poll->TimeoutDpc ); Status = STATUS_PENDING; IoMarkIrpPending( Irp ); (void)IoSetCancelRoutine(Irp, AfdCancelHandler); } else { AFD_DbgPrint(MAX_TRACE, ("FIXME: do something with the IRP!\n")); Status = STATUS_NO_MEMORY; } } KeReleaseSpinLock( &DeviceExt->Lock, OldIrql ); AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status)); return Status; }
VOID NTAPI USBSTOR_StartIo( PDEVICE_OBJECT DeviceObject, PIRP Irp) { PIO_STACK_LOCATION IoStack; PFDO_DEVICE_EXTENSION FDODeviceExtension; PPDO_DEVICE_EXTENSION PDODeviceExtension; KIRQL OldLevel; BOOLEAN ResetInProgress; DPRINT("USBSTOR_StartIo\n"); // // get FDO device extension // FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // sanity check // ASSERT(FDODeviceExtension->Common.IsFDO); // // acquire cancel spinlock // IoAcquireCancelSpinLock(&OldLevel); // // set cancel routine to zero // IoSetCancelRoutine(Irp, NULL); // // check if the irp has been cancelled // if (Irp->Cancel) { // // irp has been cancelled, release cancel spinlock // IoReleaseCancelSpinLock(OldLevel); // // irp is cancelled // Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; // // terminate request // USBSTOR_QueueTerminateRequest(DeviceObject, Irp); // // complete request // IoCompleteRequest(Irp, IO_NO_INCREMENT); // // queue next request // USBSTOR_QueueNextRequest(DeviceObject); // // done // return; } // // release cancel spinlock // IoReleaseCancelSpinLock(OldLevel); // // acquire lock // KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel); // // check reset is in progress // ResetInProgress = FDODeviceExtension->ResetInProgress; ASSERT(ResetInProgress == FALSE); // // release lock // KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel); // // get current irp stack location // IoStack = IoGetCurrentIrpStackLocation(Irp); // // get pdo device extension // PDODeviceExtension = (PPDO_DEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension; // // sanity check // ASSERT(PDODeviceExtension->Common.IsFDO == FALSE); // // is a reset in progress // if (ResetInProgress) { // // hard reset is in progress // Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; USBSTOR_QueueTerminateRequest(DeviceObject, Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); return; } // // execute scsi // USBSTOR_HandleExecuteSCSI(IoStack->DeviceObject, Irp, 0); // // FIXME: handle error // }
NTSTATUS ReleaseTimeoutPendingIrp( __in PDokanDCB Dcb ) { KIRQL oldIrql; PLIST_ENTRY thisEntry, nextEntry, listHead; PIRP_ENTRY irpEntry; LARGE_INTEGER tickCount; LIST_ENTRY completeList; PIRP irp; DDbgPrint("==> ReleaseTimeoutPendingIRP\n"); InitializeListHead(&completeList); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KeAcquireSpinLock(&Dcb->PendingIrp.ListLock, &oldIrql); // when IRP queue is empty, there is nothing to do if (IsListEmpty(&Dcb->PendingIrp.ListHead)) { KeReleaseSpinLock(&Dcb->PendingIrp.ListLock, oldIrql); DDbgPrint(" IrpQueue is Empty\n"); return STATUS_SUCCESS; } KeQueryTickCount(&tickCount); // search timeout IRP through pending IRP list listHead = &Dcb->PendingIrp.ListHead; for (thisEntry = listHead->Flink; thisEntry != listHead; thisEntry = nextEntry) { nextEntry = thisEntry->Flink; irpEntry = CONTAINING_RECORD(thisEntry, IRP_ENTRY, ListEntry); // this IRP is NOT timeout yet if (tickCount.QuadPart < irpEntry->TickCount.QuadPart) { break; } RemoveEntryList(thisEntry); DDbgPrint(" timeout Irp #%X\n", irpEntry->SerialNumber); irp = irpEntry->Irp; if (irp == NULL) { // this IRP has already been canceled ASSERT(irpEntry->CancelRoutineFreeMemory == FALSE); DokanFreeIrpEntry(irpEntry); continue; } // this IRP is not canceled yet if (IoSetCancelRoutine(irp, NULL) == NULL) { // Cancel routine will run as soon as we release the lock InitializeListHead(&irpEntry->ListEntry); irpEntry->CancelRoutineFreeMemory = TRUE; continue; } // IrpEntry is saved here for CancelRoutine // Clear it to prevent to be completed by CancelRoutine twice irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_IRP_ENTRY] = NULL; InsertTailList(&completeList, &irpEntry->ListEntry); } if (IsListEmpty(&Dcb->PendingIrp.ListHead)) { KeClearEvent(&Dcb->PendingIrp.NotEmpty); } KeReleaseSpinLock(&Dcb->PendingIrp.ListLock, oldIrql); while (!IsListEmpty(&completeList)) { listHead = RemoveHeadList(&completeList); irpEntry = CONTAINING_RECORD(listHead, IRP_ENTRY, ListEntry); irp = irpEntry->Irp; irp->IoStatus.Information = 0; irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; DokanFreeIrpEntry(irpEntry); IoCompleteRequest(irp, IO_NO_INCREMENT); } DDbgPrint("<== ReleaseTimeoutPendingIRP\n"); return STATUS_SUCCESS; }
// user assinged bigger buffer that is enough to return WriteEventContext NTSTATUS DokanEventWrite( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { KIRQL oldIrql; PLIST_ENTRY thisEntry, nextEntry, listHead; PIRP_ENTRY irpEntry; PDokanVCB vcb; PEVENT_INFORMATION eventInfo; PIRP writeIrp; eventInfo = (PEVENT_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ASSERT(eventInfo != NULL); DDbgPrint("==> DokanEventWrite [EventInfo #%X]\n", eventInfo->SerialNumber); vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB) { return STATUS_INVALID_PARAMETER; } ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KeAcquireSpinLock(&vcb->Dcb->PendingIrp.ListLock, &oldIrql); // search corresponding write IRP through pending IRP list listHead = &vcb->Dcb->PendingIrp.ListHead; for (thisEntry = listHead->Flink; thisEntry != listHead; thisEntry = nextEntry) { PIO_STACK_LOCATION writeIrpSp, eventIrpSp; PEVENT_CONTEXT eventContext; ULONG info = 0; NTSTATUS status; nextEntry = thisEntry->Flink; irpEntry = CONTAINING_RECORD(thisEntry, IRP_ENTRY, ListEntry); // check whehter this is corresponding IRP //DDbgPrint("SerialNumber irpEntry %X eventInfo %X\n", irpEntry->SerialNumber, eventInfo->SerialNumber); if (irpEntry->SerialNumber != eventInfo->SerialNumber) { continue; } // do NOT free irpEntry here writeIrp = irpEntry->Irp; if (writeIrp == NULL) { // this IRP has already been canceled ASSERT(irpEntry->CancelRoutineFreeMemory == FALSE); DokanFreeIrpEntry(irpEntry); continue; } if (IoSetCancelRoutine(writeIrp, DokanIrpCancelRoutine) == NULL) { //if (IoSetCancelRoutine(writeIrp, NULL) != NULL) { // Cancel routine will run as soon as we release the lock InitializeListHead(&irpEntry->ListEntry); irpEntry->CancelRoutineFreeMemory = TRUE; continue; } writeIrpSp = irpEntry->IrpSp; eventIrpSp = IoGetCurrentIrpStackLocation(Irp); ASSERT(writeIrpSp != NULL); ASSERT(eventIrpSp != NULL); eventContext = (PEVENT_CONTEXT)writeIrp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT]; ASSERT(eventContext != NULL); // short of buffer length if (eventIrpSp->Parameters.DeviceIoControl.OutputBufferLength < eventContext->Length) { DDbgPrint(" EventWrite: STATUS_INSUFFICIENT_RESOURCE\n"); status = STATUS_INSUFFICIENT_RESOURCES; } else { PVOID buffer; //DDbgPrint(" EventWrite CopyMemory\n"); //DDbgPrint(" EventLength %d, BufLength %d\n", eventContext->Length, // eventIrpSp->Parameters.DeviceIoControl.OutputBufferLength); if (Irp->MdlAddress) buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); else buffer = Irp->AssociatedIrp.SystemBuffer; ASSERT(buffer != NULL); RtlCopyMemory(buffer, eventContext, eventContext->Length); info = eventContext->Length; status = STATUS_SUCCESS; } DokanFreeEventContext(eventContext); writeIrp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = 0; KeReleaseSpinLock(&vcb->Dcb->PendingIrp.ListLock, oldIrql); Irp->IoStatus.Status = status; Irp->IoStatus.Information = info; // this IRP will be completed by caller function return Irp->IoStatus.Status; } KeReleaseSpinLock(&vcb->Dcb->PendingIrp.ListLock, oldIrql); return STATUS_SUCCESS; }
VOID ndisuioServiceReads( IN PNDISUIO_OPEN_CONTEXT pOpenContext ) /*++ Routine Description: Utility routine to copy received data into user buffers and complete READ IRPs. Arguments: pOpenContext - pointer to open context Return Value: None --*/ { PIRP pIrp; PLIST_ENTRY pIrpEntry; DEBUGP(DL_VERY_LOUD, ("ServiceReads: open %p/%x\n", pOpenContext, pOpenContext->Flags)); NUIO_REF_OPEN(pOpenContext); // temp ref - service reads NUIO_ACQUIRE_LOCK(&pOpenContext->Lock); while (!NUIO_IS_LIST_EMPTY(&pOpenContext->PendedReads) && !NUIO_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue)) { // // Get the first pended Read IRP // pIrpEntry = pOpenContext->PendedReads.Flink; pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry); // // Check to see if it is being cancelled. // if (IoSetCancelRoutine(pIrp, NULL)) { // // It isn't being cancelled, and can't be cancelled henceforth. // NUIO_REMOVE_ENTRY_LIST(pIrpEntry); // // NOTE: we decrement PendedReadCount way below in the // while loop, to avoid letting through a thread trying // to unbind. // } else { // // The IRP is being cancelled; let the cancel routine handle it. // __RAIN: I think this can never happened, because when cancelling // the irp, the pOpenContext is locked. // DEBUGP(DL_INFO, ("ServiceReads: open %p, skipping cancelled IRP %p\n", pOpenContext, pIrp)); continue; } NdisuioDoFastRead(pOpenContext, pIrp); NUIO_DEREF_OPEN(pOpenContext); // took out pended Read NUIO_ACQUIRE_LOCK(&pOpenContext->Lock); pOpenContext->PendedReadCount--; } NUIO_RELEASE_LOCK(&pOpenContext->Lock); NUIO_DEREF_OPEN(pOpenContext); // temp ref - service reads }