BOOLEAN AWEAllocAddBlock(IN POBJECT_CONTEXT Context, IN PBLOCK_DESCRIPTOR Block) { ULONG block_size; PAGED_CODE(); if (Block->Mdl == NULL) return FALSE; block_size = AWEAllocGetPageBaseFromAbsOffset(MmGetMdlByteCount(Block->Mdl)); if (block_size == 0) { KdPrint(("AWEAlloc: Got %u bytes which is too small for page size.\n", MmGetMdlByteCount(Block->Mdl))); MmFreePagesFromMdl(Block->Mdl); ExFreePool(Block->Mdl); Block->Mdl = NULL; return FALSE; } Block->Offset = Context->TotalSize; Block->NextBlock = Context->FirstBlock; Context->FirstBlock = Block; Context->TotalSize += block_size; return TRUE; }
uint64 hax_get_pfn_user(hax_memdesc_user *memdesc, uint64 uva_offset) { PMDL pmdl = NULL; PPFN_NUMBER ppfn = NULL; uint64 len; if (!memdesc) { hax_error("%s: memdesc == NULL\n", __func__); return INVALID_PFN; } if (!memdesc->pmdl) { hax_error("%s: memdesc->pmdl == NULL\n", __func__); return INVALID_PFN; } pmdl = memdesc->pmdl; len = MmGetMdlByteCount(pmdl); if (uva_offset >= len) { hax_error("The uva_offset 0x%llx exceeds the buffer length 0x%llx.\n", uva_offset, len); return INVALID_PFN; } ppfn = MmGetMdlPfnArray(pmdl); if (NULL == ppfn) { hax_error("Get MDL pfn array failed. uva_offset: 0x%llx.\n", uva_offset); return INVALID_PFN; } return (uint64)ppfn[uva_offset >> PG_ORDER_4K]; }
/* * @implemented */ VOID EXPORT NdisMCompleteBufferPhysicalMapping( IN NDIS_HANDLE MiniportAdapterHandle, IN PNDIS_BUFFER Buffer, IN ULONG PhysicalMapRegister) /* * FUNCTION: Complete dma action started by NdisMStartBufferPhysicalMapping * ARGUMENTS: * - MiniportAdapterHandle: handle originally input to MiniportInitialize * - Buffer: NDIS_BUFFER to complete the mapping on * - PhyscialMapRegister: the chosen map register * NOTES: * - May be called at IRQL <= DISPATCH_LEVEL */ { PLOGICAL_ADAPTER Adapter; VOID *CurrentVa; ULONG Length; ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); ASSERT(MiniportAdapterHandle && Buffer); Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle; CurrentVa = MmGetMdlVirtualAddress(Buffer); Length = MmGetMdlByteCount(Buffer); Adapter->NdisMiniportBlock.SystemAdapterObject->DmaOperations->FlushAdapterBuffers( Adapter->NdisMiniportBlock.SystemAdapterObject, Buffer, Adapter->NdisMiniportBlock.MapRegisters[PhysicalMapRegister].MapRegister, CurrentVa, Length, Adapter->NdisMiniportBlock.MapRegisters[PhysicalMapRegister].WriteToDevice); }
/* * -------------------------------------------------------------------------- * FixSegmentHeader * * Fix IP length, IP checksum, TCP sequence number and TCP checksum * in the segment. * -------------------------------------------------------------------------- */ static NDIS_STATUS FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber) { EthHdr *dstEth; IPHdr *dstIP; TCPHdr *dstTCP; PMDL mdl; PUINT8 bufferStart; mdl = NET_BUFFER_FIRST_MDL(nb); bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(mdl, LowPagePriority); if (!bufferStart) { return NDIS_STATUS_RESOURCES; } dstEth = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(nb)); ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb) >= sizeof(EthHdr) + sizeof(IPHdr) + sizeof(TCPHdr)); dstIP = (IPHdr *)((PCHAR)dstEth + sizeof *dstEth); dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4); ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb) >= sizeof(EthHdr) + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP)); /* Fix IP length and checksum */ ASSERT(dstIP->protocol == IPPROTO_TCP); dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP)); dstIP->check = 0; dstIP->check = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0); /* Fix TCP checksum */ dstTCP->seq = htonl(seqNumber); dstTCP->check = IPPseudoChecksum((UINT32 *)&dstIP->saddr, (UINT32 *)&dstIP->daddr, IPPROTO_TCP, segmentSize + TCP_HDR_LEN(dstTCP)); dstTCP->check = CalculateChecksumNB(nb, (UINT16)(NET_BUFFER_DATA_LENGTH(nb) - sizeof *dstEth - dstIP->ihl * 4), sizeof *dstEth + dstIP->ihl * 4); return STATUS_SUCCESS; }
VOID XNdisGetFirstBufferFromPacket(PNDIS_PACKET Packet, PNDIS_BUFFER *FirstBuffer, PVOID *FirstBufferVA, PUINT FirstBufferLength, PUINT TotalBufferLength) { PNDIS_BUFFER _Buffer; _Buffer = (Packet)->Private.Head; *(FirstBuffer) = _Buffer; *(FirstBufferVA) = MmGetMdlVirtualAddress(_Buffer); if (_Buffer != NULL) { *(FirstBufferLength) = MmGetMdlByteCount(_Buffer); _Buffer = _Buffer->Next; } else *(FirstBufferLength) = 0; *(TotalBufferLength) = *(FirstBufferLength); while (_Buffer != NULL) { *(TotalBufferLength) += MmGetMdlByteCount(_Buffer); _Buffer = _Buffer->Next; } }
//--------------------------------------------------------------------------- NTSTATUS DriverRead(IN PDEVICE_OBJECT vDeviceObject, IN PIRP vIrp) { Debug("Enter DriverRead"); if(0 == vIrp->MdlAddress) { vIrp->IoStatus.Information = 0; vIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; IoCompleteRequest(vIrp,IO_NO_INCREMENT); return STATUS_UNSUCCESSFUL; } PVOID tVirtualAddress = MmGetMdlVirtualAddress(vIrp->MdlAddress); ULONG tLength = MmGetMdlByteCount(vIrp->MdlAddress); RtlFillMemory(tVirtualAddress,tLength,'A'); vIrp->IoStatus.Information = tLength; vIrp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(vIrp,IO_NO_INCREMENT); Debug("Leave DriverRead"); return STATUS_SUCCESS; }
VOID BalloonLeak( IN WDFOBJECT WdfDevice, IN size_t num ) { PDEVICE_CONTEXT ctx = GetDeviceContext(WdfDevice); PPAGE_LIST_ENTRY pPageListEntry; PMDL pPageMdl; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__); pPageListEntry = (PPAGE_LIST_ENTRY)PopEntryList(&ctx->PageListHead); if (pPageListEntry == NULL) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "No list entries.\n"); return; } pPageMdl = pPageListEntry->PageMdl; num = MmGetMdlByteCount(pPageMdl) / PAGE_SIZE; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "Deflate balloon with %d pages.\n", num); ctx->num_pfns = num; ctx->num_pages -= ctx->num_pfns; RtlCopyMemory(ctx->pfns_table, MmGetMdlPfnArray(pPageMdl), ctx->num_pfns * sizeof(PFN_NUMBER)); MmFreePagesFromMdl(pPageMdl); ExFreePool(pPageMdl); ExFreeToNPagedLookasideList(&ctx->LookAsideList, pPageListEntry); BalloonTellHost(WdfDevice, ctx->DefVirtQueue); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__); }
NTSTATUS USBPcapBufferHandleReadIrp(PIRP pIrp, PDEVICE_EXTENSION pDevExt, PUINT32 pBytesRead) { PDEVICE_EXTENSION pRootExt; PUSBPCAP_ROOTHUB_DATA pRootData; PVOID buffer; UINT32 bufferLength; UINT32 bytesRead; NTSTATUS status; KIRQL irql; PIO_STACK_LOCATION pStack = NULL; pStack = IoGetCurrentIrpStackLocation(pIrp); *pBytesRead = 0; if (pStack->Parameters.Read.Length == 0) { return STATUS_SUCCESS; } pRootExt = (PDEVICE_EXTENSION)pDevExt->context.control.pRootHubObject->DeviceExtension; pRootData = pRootExt->context.usb.pDeviceData->pRootData; if (pRootData->buffer == NULL) { return STATUS_UNSUCCESSFUL; } /* * Since control device has DO_DIRECT_IO bit set the MDL is already * probed and locked */ buffer = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); if (buffer == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } else { bufferLength = MmGetMdlByteCount(pIrp->MdlAddress); } /* Get data from data queue, if there is no data we put * this IRP to Cancel-Safe queue and return status pending * otherwise complete this IRP then return SUCCESS */ KeAcquireSpinLock(&pRootData->bufferLock, &irql); bytesRead = USBPcapBufferRead(pRootData, buffer, bufferLength); KeReleaseSpinLock(&pRootData->bufferLock, irql); *pBytesRead = bytesRead; if (bytesRead == 0) { IoCsqInsertIrp(&pDevExt->context.control.ioCsq, pIrp, NULL); return STATUS_PENDING; } return STATUS_SUCCESS; }
NTSTATUS USBPcapBufferWritePacket(PUSBPCAP_ROOTHUB_DATA pRootData, PUSBPCAP_BUFFER_PACKET_HEADER header, PVOID buffer) { UINT32 bytes; UINT32 bytesFree; KIRQL irql; NTSTATUS status; PDEVICE_EXTENSION pControlExt; PIRP pIrp = NULL; pcaprec_hdr_t pcapHeader; pControlExt = (PDEVICE_EXTENSION)pRootData->controlDevice->DeviceExtension; ASSERT(pControlExt->deviceMagic == USBPCAP_MAGIC_CONTROL); bytes = header->headerLen + header->dataLength; KeAcquireSpinLock(&pRootData->bufferLock, &irql); USBPcapInitializePcapHeader(pRootData, &pcapHeader, bytes); /* pcapHeader.incl_len contains the number of bytes to write */ bytes = pcapHeader.incl_len; status = STATUS_SUCCESS; bytesFree = USBPcapGetBufferFree(pRootData); if ((pRootData->buffer == NULL) || (bytesFree < sizeof(pcaprec_hdr_t)) || ((bytesFree - sizeof(pcaprec_hdr_t)) < bytes)) { DkDbgStr("No enough free space left."); status = STATUS_INSUFFICIENT_RESOURCES; } else { UINT32 tmp; /* Write Packet Header */ USBPcapBufferWriteUnsafe(pRootData, (PVOID) &pcapHeader, (UINT32) sizeof(pcaprec_hdr_t)); /* Write USBPCAP_BUFFER_PACKET_HEADER */ tmp = min(bytes, (UINT32)header->headerLen); if (tmp > 0) { USBPcapBufferWriteUnsafe(pRootData, (PVOID) header, tmp); } bytes -= tmp; if (bytes > 0 && header->dataLength > 0) { /* Write data */ tmp = min(bytes, header->dataLength); USBPcapBufferWriteUnsafe(pRootData, buffer, tmp); } } KeReleaseSpinLock(&pRootData->bufferLock, irql); if (NT_SUCCESS(status)) { pIrp = IoCsqRemoveNextIrp(&pControlExt->context.control.ioCsq, NULL); if (pIrp != NULL) { PVOID buffer; UINT32 bufferLength; UINT32 bytesRead; /* * Only IRPs with non-zero buffer are being queued. * * Since control device has DO_DIRECT_IO bit set the MDL is already * probed and locked */ buffer = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); if (buffer == NULL) { pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; bytes = 0; } else { UINT32 bufferLength = MmGetMdlByteCount(pIrp->MdlAddress); if (bufferLength != 0) { KeAcquireSpinLock(&pRootData->bufferLock, &irql); bytes = USBPcapBufferRead(pRootData, buffer, bufferLength); KeReleaseSpinLock(&pRootData->bufferLock, irql); } else { bytes = 0; } pIrp->IoStatus.Status = STATUS_SUCCESS; } pIrp->IoStatus.Information = (ULONG_PTR) bytes; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } } return status; }
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 NdisProtEvtIoWrite( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) /*++ Routine Description: Dispatch routine to handle Request_MJ_WRITE. Arguments: Queue - Default queue handle Request - Handle to the read/write request Lenght - Length of the data buffer associated with the request. The default property of the queue is to not dispatch zero lenght read & write requests to the driver and complete is with status success. So we will never get a zero length request. Return Value: VOID --*/ { ULONG DataLength; NTSTATUS NtStatus; PNDISPROT_OPEN_CONTEXT pOpenContext; PNET_BUFFER_LIST pNetBufferList; NDISPROT_ETH_HEADER UNALIGNED *pEthHeader; PVOID CancelId; ULONG SendFlags = 0; PMDL pMdl = NULL; WDFFILEOBJECT fileObject; PREQUEST_CONTEXT reqContext; WDF_OBJECT_ATTRIBUTES attributes; UNREFERENCED_PARAMETER(Queue); fileObject = WdfRequestGetFileObject(Request); pOpenContext = GetFileObjectContext(fileObject)->OpenContext; do { // // Create a context to track the length of transfer and NDIS packet // associated with this request. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT); NtStatus = WdfObjectAllocateContext(Request, &attributes, &reqContext); if(!NT_SUCCESS(NtStatus)){ DEBUGP(DL_WARN, ("Write: WdfObjectAllocateContext failed: %x\n", NtStatus)); NtStatus = STATUS_INVALID_HANDLE; break; } reqContext->Length = (ULONG) Length; if (pOpenContext == NULL) { DEBUGP(DL_WARN, ("Write: FileObject %p not yet associated with a device\n", fileObject)); NtStatus = STATUS_INVALID_HANDLE; break; } NPROT_STRUCT_ASSERT(pOpenContext, oc); NtStatus = WdfRequestRetrieveInputWdmMdl(Request, &pMdl); if (!NT_SUCCESS(NtStatus)) { DEBUGP(DL_FATAL, ("Write: WdfRequestRetrieveInputWdmMdl failed %x\n", NtStatus)); break; } // // Try to get a virtual address for the MDL. // pEthHeader = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority | MdlMappingNoExecute); if (pEthHeader == NULL) { DEBUGP(DL_FATAL, ("Write: MmGetSystemAddr failed for" " Request %p, MDL %p\n", Request, pMdl)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } // // Sanity-check the length. // DataLength = MmGetMdlByteCount(pMdl); 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 ((WdfRequestGetRequestorMode(Request) == 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, FALSE); if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE)) { NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); DEBUGP(DL_FATAL, ("Write: Open %p is not bound" " or in low power state\n", pOpenContext)); NtStatus = STATUS_INVALID_HANDLE; break; } if ((pOpenContext->State == NdisprotPaused) || (pOpenContext->State == NdisprotPausing)) { NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); DEBUGP(DL_INFO, ("Device is paused.\n")); NtStatus = STATUS_UNSUCCESSFUL; break; } NPROT_ASSERT(pOpenContext->SendNetBufferListPool != NULL); pNetBufferList = NdisAllocateNetBufferAndNetBufferList( pOpenContext->SendNetBufferListPool, sizeof(NPROT_SEND_NETBUFLIST_RSVD), //Request control offset delta 0, // back fill size pMdl, 0, // Data offset DataLength); if (pNetBufferList == NULL) { NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send net buffer list\n", pOpenContext)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } pOpenContext->PendedSendCount++; NPROT_REF_OPEN(pOpenContext); // pended send // // Initialize the NetBufferList ref count. This NetBufferList will be freed // when this count goes to zero. // NPROT_SEND_NBL_RSVD(pNetBufferList)->RefCount = 1; // // We set up a cancel ID on each send NetBufferList (which maps to a Write IRP), // and save the NetBufferList pointer in the IRP. If the IRP gets cancelled, we use // NdisCancelSendNetBufferLists() to cancel the NetBufferList. // // Note that this sample code does not implement the cancellation logic. An actual // driver may find value in implementing this. // CancelId = NPROT_GET_NEXT_CANCEL_ID(); NDIS_SET_NET_BUFFER_LIST_CANCEL_ID(pNetBufferList, CancelId); reqContext->NetBufferList = (PVOID)pNetBufferList; NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); // // Set a back pointer from the packet to the IRP. // NPROT_REQUEST_FROM_SEND_NBL(pNetBufferList) = Request; NtStatus = STATUS_PENDING; pNetBufferList->SourceHandle = pOpenContext->BindingHandle; NPROT_ASSERT (pMdl->Next == NULL); SendFlags |= NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK; NdisSendNetBufferLists( pOpenContext->BindingHandle, pNetBufferList, NDIS_DEFAULT_PORT_NUMBER, SendFlags); } while (FALSE); if (NtStatus != STATUS_PENDING) { WdfRequestComplete(Request, NtStatus); } return; }
) { IoFreeMdl(Buffer); } VOID NdisQueryBuffer( IN PNDIS_BUFFER Buffer, OUT PVOID *VirtualAddress OPTIONAL, OUT PUINT Length ) { if ( ARGUMENT_PRESENT(VirtualAddress) ) { *VirtualAddress = MmGetSystemAddressForMdl(Buffer); } *Length = MmGetMdlByteCount(Buffer); } VOID NdisQueryBufferOffset( IN PNDIS_BUFFER Buffer, OUT PUINT Offset, OUT PUINT Length ) { *Offset = MmGetMdlByteOffset(Buffer); *Length = MmGetMdlByteCount(Buffer); } ULONG NDIS_BUFFER_TO_SPAN_PAGES(
NDIS_STATUS CopyBytesFromNetBuffer( PNET_BUFFER_KK NetBuffer, PULONG cbDest, PVOID Dest) /*++ Routine Description: Copies the first cbDest bytes from a NET_BUFFER. In order to show how the various data structures fit together, this implementation copies the data by iterating through the MDLs for the NET_BUFFER. The NdisGetDataBuffer API also allows you to copy a contiguous block of data from a NET_BUFFER. Runs at IRQL <= DISPATCH_LEVEL. Arguments: NetBuffer The NB to read cbDest On input, the number of bytes in the buffer Dest On return, the number of bytes actually copied Dest On return, receives the first cbDest bytes of the network frame in NetBuffer Return Value: None. Notes: If the output buffer is larger than the NB's frame size, *cbDest will contain the number of bytes in the frame size. If the output buffer is smaller than the NB's frame size, only the first *cbDest bytes will be copied (the buffer will receive a truncated copy of the frame). --*/ { NDIS_STATUS Status = NDIS_STATUS_SUCCESS; // // Start copy from current MDL // PMDL CurrentMdl = NET_BUFFER_CURRENT_MDL(NetBuffer); // // Data on current MDL may be offset from start of MDL // ULONG DestOffset = 0; while (DestOffset < *cbDest && CurrentMdl) { // // Map MDL memory to System Address Space. LowPagePriority means mapping may fail if // system is low on memory resources. // PUCHAR SrcMemory = MmGetSystemAddressForMdlSafe(CurrentMdl, LowPagePriority); ULONG Length = MmGetMdlByteCount(CurrentMdl); if (!SrcMemory) { Status = NDIS_STATUS_RESOURCES; break; } if(DestOffset==0) { // // The first MDL segment should be accessed from the current MDL offset // ULONG MdlOffset = NET_BUFFER_CURRENT_MDL_OFFSET(NetBuffer); SrcMemory += MdlOffset; Length -= MdlOffset; } Length = min(Length, *cbDest-DestOffset); // // Copy Memory // NdisMoveMemory((PUCHAR)Dest+DestOffset, SrcMemory, Length); DestOffset += Length; // // Get next MDL (if any available) // CurrentMdl = NDIS_MDL_LINKAGE(CurrentMdl); } if(Status == NDIS_STATUS_SUCCESS) { *cbDest = DestOffset; } return Status; }
VOID BalloonFill( IN WDFOBJECT WdfDevice, IN size_t num) { PDEVICE_CONTEXT ctx = GetDeviceContext(WdfDevice); PHYSICAL_ADDRESS LowAddress; PHYSICAL_ADDRESS HighAddress; PHYSICAL_ADDRESS SkipBytes; PPAGE_LIST_ENTRY pNewPageListEntry; PMDL pPageMdl; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__); ctx->num_pfns = 0; if (IsLowMemory(WdfDevice)) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "Low memory. Allocated pages: %d\n", ctx->num_pages); return; } num = min(num, PAGE_SIZE / sizeof(PFN_NUMBER)); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "Inflate balloon with %d pages.\n", num); LowAddress.QuadPart = 0; HighAddress.QuadPart = (ULONGLONG)-1; SkipBytes.QuadPart = 0; #if (NTDDI_VERSION < NTDDI_WS03SP1) pPageMdl = MmAllocatePagesForMdl(LowAddress, HighAddress, SkipBytes, num * PAGE_SIZE); #else pPageMdl = MmAllocatePagesForMdlEx(LowAddress, HighAddress, SkipBytes, num * PAGE_SIZE, MmNonCached, MM_DONT_ZERO_ALLOCATION); #endif if (pPageMdl == NULL) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "Failed to allocate pages.\n"); return; } if (MmGetMdlByteCount(pPageMdl) != (num * PAGE_SIZE)) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "Not all requested memory was allocated (%d/%d).\n", MmGetMdlByteCount(pPageMdl), num * PAGE_SIZE); MmFreePagesFromMdl(pPageMdl); ExFreePool(pPageMdl); return; } pNewPageListEntry = (PPAGE_LIST_ENTRY)ExAllocateFromNPagedLookasideList( &ctx->LookAsideList); if (pNewPageListEntry == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "Failed to allocate list entry.\n"); MmFreePagesFromMdl(pPageMdl); ExFreePool(pPageMdl); return; } pNewPageListEntry->PageMdl = pPageMdl; PushEntryList(&ctx->PageListHead, &(pNewPageListEntry->SingleListEntry)); ctx->num_pfns = num; ctx->num_pages += ctx->num_pfns; RtlCopyMemory(ctx->pfns_table, MmGetMdlPfnArray(pPageMdl), ctx->num_pfns * sizeof(PFN_NUMBER)); BalloonTellHost(WdfDevice, ctx->InfVirtQueue); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__); }
NTSTATUS WDFEXPORT(WdfDmaTransactionInitializeUsingRequest)( __in PWDF_DRIVER_GLOBALS DriverGlobals, __in WDFDMATRANSACTION DmaTransaction, __in WDFREQUEST Request, __in PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction, __in WDF_DMA_DIRECTION DmaDirection ) { NTSTATUS status; FxDmaTransactionBase* pDmaTrans; FxRequest* pReqObj; MDL* mdl = NULL; PIO_STACK_LOCATION stack; ULONG reqLength; PFX_DRIVER_GLOBALS pFxDriverGlobals; FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), DmaTransaction, FX_TYPE_DMA_TRANSACTION, (PVOID *) &pDmaTrans, &pFxDriverGlobals); FxPointerNotNull(pFxDriverGlobals, EvtProgramDmaFunction); if (DmaDirection != WdfDmaDirectionReadFromDevice && DmaDirection != WdfDmaDirectionWriteToDevice) { status = STATUS_INVALID_PARAMETER; DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, "Initialization of WDFDMATRANSACTION 0x%p using WDFREQUEST %p, " "DmaDirection 0x%x is an invalid value, %!STATUS!", DmaTransaction, Request, DmaDirection, status); return status; } FxObjectHandleGetPtr(pFxDriverGlobals, Request, FX_TYPE_REQUEST, (PVOID *) &pReqObj); reqLength = 0; stack = pReqObj->GetFxIrp()->GetCurrentIrpStackLocation(); // // Get the MDL and Length from the request. // switch (stack->MajorFunction) { case IRP_MJ_READ: if (DmaDirection != WdfDmaDirectionReadFromDevice) { status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION " "0x%p doesn't match with the WDFREQUEST 0x%p type " "%!WDF_REQUEST_TYPE! %!STATUS!", DmaDirection, DmaTransaction, Request, stack->MajorFunction, status); return status; } reqLength = stack->Parameters.Read.Length; status = pReqObj->GetMdl(&mdl); break; case IRP_MJ_WRITE: if (DmaDirection != WdfDmaDirectionWriteToDevice) { status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION " "0x%p doesn't match with the WDFREQUEST 0x%p type " "%!WDF_REQUEST_TYPE! %!STATUS!", DmaDirection, DmaTransaction, Request, stack->MajorFunction, status); return status; } reqLength = stack->Parameters.Write.Length; status = pReqObj->GetMdl(&mdl); break; case IRP_MJ_DEVICE_CONTROL: case IRP_MJ_INTERNAL_DEVICE_CONTROL: switch (METHOD_FROM_CTL_CODE(stack->Parameters.DeviceIoControl.IoControlCode)) { case METHOD_BUFFERED: if (DmaDirection == WdfDmaDirectionWriteToDevice) { reqLength = stack->Parameters.DeviceIoControl.InputBufferLength; } else { reqLength = stack->Parameters.DeviceIoControl.OutputBufferLength; } // // In this case both input buffer and output buffer map // to the same MDL and it's probed for read & write access. // So it's okay for DMA transfer in either direction. // status = pReqObj->GetMdl(&mdl); break; case METHOD_IN_DIRECT: // // For this type, the output buffer is probed for read access. // So the direction of DMA transfer is WdfDmaDirectionWriteToDevice. // if (DmaDirection != WdfDmaDirectionWriteToDevice) { status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION " "0x%p doesn't match with WDFREQUEST 0x%p ioctl type " "METHOD_IN_DIRECT %!STATUS!", DmaDirection, DmaTransaction, Request, status); return status; } reqLength = stack->Parameters.DeviceIoControl.OutputBufferLength; status = pReqObj->GetDeviceControlOutputMdl(&mdl); break; case METHOD_OUT_DIRECT: // // For this type, the output buffer is probed for write access. // So the direction of DMA transfer is WdfDmaDirectionReadFromDevice. // if (DmaDirection != WdfDmaDirectionReadFromDevice) { status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION " "0x%p doesn't match with WDFREQUEST 0x%p ioctl type " "METHOD_OUT_DIRECT %!STATUS!", DmaDirection, DmaTransaction, Request, status); return status; } reqLength = stack->Parameters.DeviceIoControl.OutputBufferLength; status = pReqObj->GetDeviceControlOutputMdl(&mdl); break; default: status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, "Invalid ioctl code in WDFREQUEST 0x%p %!STATUS!", Request, status); FxVerifierDbgBreakPoint(pFxDriverGlobals); break; }// End of switch(ioctType) break; default: status = STATUS_INVALID_DEVICE_REQUEST; break; } if (!NT_SUCCESS(status)) { DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, "Couldn't retrieve mdl from WDFREQUEST 0x%p for " "WDFTRANSACTION 0x%p %!STATUS!", Request, DmaTransaction, status); return status; } if (reqLength == 0) { status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, "Zero length request, %!STATUS!", status); return status; } // // If the DMA enabler is packet based, make sure the virtual address and // the length of transfer are within bounds. Basically, we are checking // to see if the length of data to be transferred doesn't span multiple // MDLs, because packet based DMA doesn't support chained MDLs. // if (pDmaTrans->GetDmaEnabler()->SupportsChainedMdls() == FALSE) { ULONG length; length = MmGetMdlByteCount(mdl); if (reqLength > length) { status = STATUS_INVALID_PARAMETER; DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, "WDFREQUEST %p transfer length (%d) is out of bounds of MDL " "Byte count (%d), %!STATUS!", Request, reqLength, length, status); return status; } } // // Parms appear OK, so initialize this instance. // status = pDmaTrans->Initialize(EvtProgramDmaFunction, DmaDirection, mdl, 0, reqLength); if (!NT_SUCCESS(status)) { DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, "WDFTANSACTION 0x%p initialization failed: " "%!STATUS!", DmaTransaction, status); return status; } // // Set this Request in the new DmaTransaction. The request will // take a reference on this request when it starts executing. // pDmaTrans->SetRequest(pReqObj); return STATUS_SUCCESS; }
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 SioctlDeviceControl( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++ Routine Description: This routine is called by the I/O system to perform a device I/O control function. Arguments: DeviceObject - a pointer to the object that represents the device that I/O is to be done on. Irp - a pointer to the I/O Request Packet for this request. Return Value: NT status code --*/ { PIO_STACK_LOCATION irpSp;// Pointer to current stack location NTSTATUS ntStatus = STATUS_SUCCESS;// Assume success ULONG inBufLength; // Input buffer length ULONG outBufLength; // Output buffer length PCHAR inBuf, outBuf; // pointer to Input and output buffer PCHAR data = "This String is from Device Driver !!!"; size_t datalen = strlen(data)+1;//Length of data including null PMDL mdl = NULL; PCHAR buffer = NULL; UNREFERENCED_PARAMETER(DeviceObject); PAGED_CODE(); irpSp = IoGetCurrentIrpStackLocation( Irp ); inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength; outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength; if (!inBufLength || !outBufLength) { ntStatus = STATUS_INVALID_PARAMETER; goto End; } // // Determine which I/O control code was specified. // switch ( irpSp->Parameters.DeviceIoControl.IoControlCode ) { case IOCTL_SIOCTL_METHOD_BUFFERED: // // In this method the I/O manager allocates a buffer large enough to // to accommodate larger of the user input buffer and output buffer, // assigns the address to Irp->AssociatedIrp.SystemBuffer, and // copies the content of the user input buffer into this SystemBuffer // SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_BUFFERED\n")); PrintIrpInfo(Irp); // // Input buffer and output buffer is same in this case, read the // content of the buffer before writing to it // inBuf = Irp->AssociatedIrp.SystemBuffer; outBuf = Irp->AssociatedIrp.SystemBuffer; // // Read the data from the buffer // SIOCTL_KDPRINT(("\tData from User :"******"\tData to User : "******"Called IOCTL_SIOCTL_METHOD_NEITHER\n")); PrintIrpInfo(Irp); // // A driver may access these buffers directly if it is a highest level // driver whose Dispatch routine runs in the context // of the thread that made this request. The driver should always // check the validity of the user buffer's address range and check whether // the appropriate read or write access is permitted on the buffer. // It must also wrap its accesses to the buffer's address range within // an exception handler in case another user thread deallocates the buffer // or attempts to change the access rights for the buffer while the driver // is accessing memory. // inBuf = irpSp->Parameters.DeviceIoControl.Type3InputBuffer; outBuf = Irp->UserBuffer; // // Access the buffers directly if only if you are running in the // context of the calling process. Only top level drivers are // guaranteed to have the context of process that made the request. // try { // // Before accessing user buffer, you must probe for read/write // to make sure the buffer is indeed an userbuffer with proper access // rights and length. ProbeForRead/Write will raise an exception if it's otherwise. // ProbeForRead( inBuf, inBufLength, sizeof( UCHAR ) ); // // Since the buffer access rights can be changed or buffer can be freed // anytime by another thread of the same process, you must always access // it within an exception handler. // SIOCTL_KDPRINT(("\tData from User :"******"Exception while accessing inBuf 0X%08X in METHOD_NEITHER\n", ntStatus)); break; } // // If you are accessing these buffers in an arbitrary thread context, // say in your DPC or ISR, if you are using it for DMA, or passing these buffers to the // next level driver, you should map them in the system process address space. // First allocate an MDL large enough to describe the buffer // and initilize it. Please note that on a x86 system, the maximum size of a buffer // that an MDL can describe is 65508 KB. // mdl = IoAllocateMdl(inBuf, inBufLength, FALSE, TRUE, NULL); if (!mdl) { ntStatus = STATUS_INSUFFICIENT_RESOURCES; break; } try { // // Probe and lock the pages of this buffer in physical memory. // You can specify IoReadAccess, IoWriteAccess or IoModifyAccess // Always perform this operation in a try except block. // MmProbeAndLockPages will raise an exception if it fails. // MmProbeAndLockPages(mdl, UserMode, IoReadAccess); } except(EXCEPTION_EXECUTE_HANDLER) { ntStatus = GetExceptionCode(); SIOCTL_KDPRINT(( "Exception while locking inBuf 0X%08X in METHOD_NEITHER\n", ntStatus)); IoFreeMdl(mdl); break; } // // Map the physical pages described by the MDL into system space. // Note: double mapping the buffer this way causes lot of // system overhead for large size buffers. // buffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority ); if (!buffer) { ntStatus = STATUS_INSUFFICIENT_RESOURCES; MmUnlockPages(mdl); IoFreeMdl(mdl); break; } // // Now you can safely read the data from the buffer. // SIOCTL_KDPRINT(("\tData from User (SystemAddress) : ")); PrintChars(buffer, inBufLength); // // Once the read is over unmap and unlock the pages. // MmUnlockPages(mdl); IoFreeMdl(mdl); // // The same steps can be followed to access the output buffer. // mdl = IoAllocateMdl(outBuf, outBufLength, FALSE, TRUE, NULL); if (!mdl) { ntStatus = STATUS_INSUFFICIENT_RESOURCES; break; } try { // // Probe and lock the pages of this buffer in physical memory. // You can specify IoReadAccess, IoWriteAccess or IoModifyAccess. // MmProbeAndLockPages(mdl, UserMode, IoWriteAccess); } except(EXCEPTION_EXECUTE_HANDLER) { ntStatus = GetExceptionCode(); SIOCTL_KDPRINT(( "Exception while locking outBuf 0X%08X in METHOD_NEITHER\n", ntStatus)); IoFreeMdl(mdl); break; } buffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority ); if (!buffer) { MmUnlockPages(mdl); IoFreeMdl(mdl); ntStatus = STATUS_INSUFFICIENT_RESOURCES; break; } // // Write to the buffer // RtlCopyBytes(buffer, data, outBufLength); SIOCTL_KDPRINT(("\tData to User : %s\n", buffer)); PrintChars(buffer, datalen); MmUnlockPages(mdl); // // Free the allocated MDL // IoFreeMdl(mdl); // // Assign the length of the data copied to IoStatus.Information // of the Irp and complete the Irp. // Irp->IoStatus.Information = (outBufLength<datalen?outBufLength:datalen); break; case IOCTL_SIOCTL_METHOD_IN_DIRECT: // // In this type of transfer, the I/O manager allocates a system buffer // large enough to accommodatethe User input buffer, sets the buffer address // in Irp->AssociatedIrp.SystemBuffer and copies the content of user input buffer // into the SystemBuffer. For the user output buffer, the I/O manager // probes to see whether the virtual address is readable in the callers // access mode, locks the pages in memory and passes the pointer to // MDL describing the buffer in Irp->MdlAddress. // SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_IN_DIRECT\n")); PrintIrpInfo(Irp); inBuf = Irp->AssociatedIrp.SystemBuffer; SIOCTL_KDPRINT(("\tData from User in InputBuffer: ")); PrintChars(inBuf, inBufLength); // // To access the output buffer, just get the system address // for the buffer. For this method, this buffer is intended for transfering data // from the application to the driver. // buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); if (!buffer) { ntStatus = STATUS_INSUFFICIENT_RESOURCES; break; } SIOCTL_KDPRINT(("\tData from User in OutputBuffer: ")); PrintChars(buffer, outBufLength); // // Return total bytes read from the output buffer. // Note OutBufLength = MmGetMdlByteCount(Irp->MdlAddress) // Irp->IoStatus.Information = MmGetMdlByteCount(Irp->MdlAddress); // // NOTE: Changes made to the SystemBuffer are not copied // to the user input buffer by the I/O manager // break; case IOCTL_SIOCTL_METHOD_OUT_DIRECT: // // In this type of transfer, the I/O manager allocates a system buffer // large enough to accommodate the User input buffer, sets the buffer address // in Irp->AssociatedIrp.SystemBuffer and copies the content of user input buffer // into the SystemBuffer. For the output buffer, the I/O manager // probes to see whether the virtual address is writable in the callers // access mode, locks the pages in memory and passes the pointer to MDL // describing the buffer in Irp->MdlAddress. // SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_OUT_DIRECT\n")); PrintIrpInfo(Irp); inBuf = Irp->AssociatedIrp.SystemBuffer; SIOCTL_KDPRINT(("\tData from User : "******"\tData to User : "******"ERROR: unrecognized IOCTL %x\n", irpSp->Parameters.DeviceIoControl.IoControlCode)); break; } End: // // Finish the I/O operation by simply completing the packet and returning // the same status as in the packet itself. // Irp->IoStatus.Status = ntStatus; IoCompleteRequest( Irp, 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 }
NTSTATUS NICWrite( __in PFDO_DATA FdoData, __in PIRP Irp ) /*++ Routine Description: This routine handles the hardware specific write request. If the device is not ready, fail the request. Otherwise get scatter-gather list for the request buffer and send the list to the hardware for DMA. Arguments: FdoData - Pointer to the device context. Irp - Pointer to the write request. Return Value: NT Status code. --*/ { NTSTATUS returnStatus, status; PVOID virtualAddress; ULONG pageCount = 0, length = 0; PMDL tempMdl, mdl; KIRQL oldIrql; #if defined(DMA_VER2) PVOID sgListBuffer; #endif DebugPrint(TRACE, DBG_WRITE, "--> PciDrvWrite %p\n", Irp); Irp->Tail.Overlay.DriverContext[3] = NULL; Irp->Tail.Overlay.DriverContext[2] = NULL; returnStatus = status = STATUS_SUCCESS; // // Is this adapter ready for sending? // if (MP_SHOULD_FAIL_SEND(FdoData)) { DebugPrint(ERROR, DBG_WRITE, "Device not ready %p\n", Irp); returnStatus = status = STATUS_DEVICE_NOT_READY; goto Error; } tempMdl = mdl = Irp->MdlAddress; // // Check for zero length buffer // if (mdl == NULL || MmGetMdlByteCount(mdl) == 0) { DebugPrint(ERROR, DBG_WRITE, "Zero length buffer %p\n", Irp); status = returnStatus = STATUS_INVALID_DEVICE_REQUEST; goto Error; } // // Calculate the total packet length and the number of pages // spanned by all the buffers by walking the MDL chain. // NOTE: If this driver is used in the miniport configuration, it will // not get chained MDLs because the upper filter (NDISEDGE.SYS) // coalesces the fragements to a single contiguous buffer before presenting // the packet to us. // while(tempMdl != NULL) { virtualAddress = MmGetMdlVirtualAddress(tempMdl); length += MmGetMdlByteCount(tempMdl); pageCount += ADDRESS_AND_SIZE_TO_SPAN_PAGES(virtualAddress, length); tempMdl = tempMdl->Next; } if (length < NIC_MIN_PACKET_SIZE) { // // This will never happen in our case because the ndis-edge // pads smaller size packets with zero to make it NIC_MIN_PACKET_SIZE // long. // DebugPrint(ERROR, DBG_WRITE, "Packet size is less than %d\n", NIC_MIN_PACKET_SIZE); status = returnStatus = STATUS_INVALID_DEVICE_REQUEST; goto Error; } // // Check to see if the packet spans more than the physical pages // our hardware can handle or the pageCount exceeds the total number of // map registers allocated. If so, we should coalesce the scattered // buffers to fit the limit. We can't really break the transfers and // DMA in small chunks because each packets has to be DMA'ed in one shot. // The code on how to colesce the packet for this hardware is present // in the original E100BEX sample. // if (pageCount > NIC_MAX_PHYS_BUF_COUNT || pageCount > FdoData->AllocatedMapRegisters) { // TODO: Packet needs to be coalesced DebugPrint(ERROR, DBG_WRITE, "Packet needs to be coalesced\n"); status = returnStatus = STATUS_INVALID_DEVICE_REQUEST; goto Error; } // // Build a scatter-gather list of the packet buffer and send the packet. // // If DMA_VER2 is not defined, use GetScatterGatherList. If the driver // is meant to work on XP and above, define DMA_VER2, so that you can // use BuildScatterGatherList. // // Since Build/GetScatterGatherList should be called at DISPATCH_LEVEL // let us raise the IRQL. // KeRaiseIrql(DISPATCH_LEVEL, &oldIrql); // // Let us mark the IRP pending, because NICProcessSGList is an asynchronous // callback and we wouldn't know the status of the IRP. This IRP may either // get completed by the DPC handler after the DMA transfer or may // get queued if we are low on resources. So the safest thing // to do for us here is return STATUS_PENDING irrespective of what happens // to the IRP. // IoMarkIrpPending(Irp); returnStatus = STATUS_PENDING; #if defined(DMA_VER2) sgListBuffer = ExAllocateFromNPagedLookasideList( &FdoData->SGListLookasideList); if (sgListBuffer) { Irp->Tail.Overlay.DriverContext[2] = sgListBuffer; status = FdoData->DmaAdapterObject->DmaOperations->BuildScatterGatherList( FdoData->DmaAdapterObject, FdoData->Self, mdl, MmGetMdlVirtualAddress(mdl), length, NICProcessSGList, Irp, TRUE, sgListBuffer, FdoData->ScatterGatherListSize); if (!NT_SUCCESS(status)) { DebugPrint(ERROR, DBG_WRITE, "BuildScatterGatherList %x\n", status); ExFreeToNPagedLookasideList(&FdoData->SGListLookasideList, sgListBuffer); Irp->Tail.Overlay.DriverContext[2] = NULL; } } #else status = FdoData->DmaAdapterObject->DmaOperations->GetScatterGatherList( FdoData->DmaAdapterObject, FdoData->Self, mdl, MmGetMdlVirtualAddress(mdl), length, NICProcessSGList, Irp, TRUE); if (!NT_SUCCESS(status)) { DebugPrint(ERROR, DBG_WRITE, "GetScatterGatherList %x\n", status); } #endif KeLowerIrql(oldIrql); Error: if(!NT_SUCCESS(status)){ // // Our call to get the scatter-gather list failed. We know the // NICProcessSGList is not called for sure in that case. So let us // complete the IRP here with failure status. Since we marked the // IRP pending, we have no choice but to return status-pending // even though we are completing the IRP in the incoming thread // context. // NICCompleteSendRequest(FdoData, Irp, status, 0, FALSE); } DebugPrint(LOUD, DBG_WRITE, "<-- PciDrvWrite %x\n", returnStatus); return returnStatus; }
VOID NICWritePacket( __in PFDO_DATA FdoData, __in PIRP Irp, __in BOOLEAN bFromQueue ) /*++ Routine Description: Do the work to send a packet Assumption: Send spinlock has been acquired Arguments: FdoData Pointer to our FdoData Packet The packet bFromQueue TRUE if it's taken from the send wait queue Return Value: --*/ { PMP_TCB pMpTcb = NULL; ULONG packetLength; PVOID virtualAddress; DebugPrint(TRACE, DBG_WRITE, "--> NICWritePacket, Irp= %p\n", Irp); // // Get the next free TCB and initialize it to represent the // request buffer. // pMpTcb = FdoData->CurrSendTail; ASSERT(!MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE)); // // If the adapter is not ready, fail the request. // if(MP_IS_NOT_READY(FdoData)) { MP_FREE_SEND_PACKET(FdoData, pMpTcb, STATUS_DEVICE_NOT_READY); return; } pMpTcb->FirstBuffer = Irp->MdlAddress; virtualAddress = MmGetMdlVirtualAddress(Irp->MdlAddress); pMpTcb->BufferCount = 1; pMpTcb->PacketLength = packetLength = MmGetMdlByteCount(Irp->MdlAddress); pMpTcb->PhysBufCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(virtualAddress, packetLength); pMpTcb->Irp = Irp; MP_SET_FLAG(pMpTcb, fMP_TCB_IN_USE); // // Call the send handler, it only needs to deal with the frag list // NICSendPacket(FdoData, pMpTcb, Irp->Tail.Overlay.DriverContext[3]); FdoData->nBusySend++; ASSERT(FdoData->nBusySend <= FdoData->NumTcb); FdoData->CurrSendTail = FdoData->CurrSendTail->Next; DebugPrint(TRACE, DBG_WRITE, "<-- NICWritePacket\n"); return; }
NTSTATUS NbfTdiAction( IN PDEVICE_CONTEXT DeviceContext, IN PIRP Irp ) /*++ Routine Description: This routine performs the TdiAction request for the transport provider. Arguments: DeviceContext - The device context for the operation Irp - the Irp for the requested operation. Return Value: NTSTATUS - status of operation. --*/ { NTSTATUS status; PIO_STACK_LOCATION irpSp; PTDI_ACTION_HEADER ActionHeader; LARGE_INTEGER timeout = {0,0}; PTP_REQUEST tpRequest; KIRQL oldirql, cancelirql; ULONG BytesRequired; // // what type of status do we want? // irpSp = IoGetCurrentIrpStackLocation (Irp); if ((!Irp->MdlAddress) || (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(TDI_ACTION_HEADER))) { return STATUS_INVALID_PARAMETER; } ActionHeader = (PTDI_ACTION_HEADER)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); if (!ActionHeader) { return STATUS_INSUFFICIENT_RESOURCES; } // // Make sure we have required number of bytes for this type of request // switch (ActionHeader->ActionCode) { case QUERY_INDICATION_CODE: BytesRequired = sizeof(ACTION_QUERY_INDICATION); break; case DATAGRAM_INDICATION_CODE: BytesRequired = sizeof(ACTION_DATAGRAM_INDICATION); break; default: return STATUS_NOT_IMPLEMENTED; } if (MmGetMdlByteCount(Irp->MdlAddress) < BytesRequired) { return STATUS_INVALID_PARAMETER; } // // Here the request is one of QUERY_INDICATION or DATAGRAM_INDICATION // // // These two requests are sent by RAS to "MABF" // if (!RtlEqualMemory ((PVOID)(&ActionHeader->TransportId), "MABF", 4)) { return STATUS_NOT_SUPPORTED; } // // They should be sent on the control channel // if (irpSp->FileObject->FsContext2 != (PVOID)NBF_FILE_TYPE_CONTROL) { return STATUS_NOT_SUPPORTED; } // // Create a request to describe this. // status = NbfCreateRequest ( Irp, // IRP for this request. DeviceContext, // context. REQUEST_FLAGS_DC, // partial flags. Irp->MdlAddress, MmGetMdlByteCount(Irp->MdlAddress), timeout, &tpRequest); if (NT_SUCCESS (status)) { NbfReferenceDeviceContext ("Action", DeviceContext, DCREF_REQUEST); tpRequest->Owner = DeviceContextType; tpRequest->FrameContext = (USHORT)irpSp->FileObject->FsContext; IoAcquireCancelSpinLock(&cancelirql); ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql); // // Disallow these requests on a stopping device. // if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) { RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql); IoReleaseCancelSpinLock(cancelirql); NbfCompleteRequest (tpRequest, STATUS_DEVICE_NOT_READY, 0); } else { if (ActionHeader->ActionCode == QUERY_INDICATION_CODE) { InsertTailList ( &DeviceContext->QueryIndicationQueue, &tpRequest->Linkage); } else { InsertTailList ( &DeviceContext->DatagramIndicationQueue, &tpRequest->Linkage); } DeviceContext->IndicationQueuesInUse = TRUE; // // If this IRP has been cancelled, then call the // cancel routine. // if (Irp->Cancel) { RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql); Irp->CancelIrql = cancelirql; NbfCancelAction((PDEVICE_OBJECT)DeviceContext, Irp); return STATUS_PENDING; } IoSetCancelRoutine(Irp, NbfCancelAction); RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql); IoReleaseCancelSpinLock(cancelirql); } status = STATUS_PENDING; } return status; }
NTSTATUS DispTdiQueryInformation( PDEVICE_OBJECT DeviceObject, PIRP Irp) /* * FUNCTION: TDI_QUERY_INFORMATION handler * ARGUMENTS: * DeviceObject = Pointer to device object structure * Irp = Pointer to an I/O request packet * RETURNS: * Status of operation */ { PTDI_REQUEST_KERNEL_QUERY_INFORMATION Parameters; PTRANSPORT_CONTEXT TranContext; PIO_STACK_LOCATION IrpSp; TI_DbgPrint(DEBUG_IRP, ("Called.\n")); IrpSp = IoGetCurrentIrpStackLocation(Irp); Parameters = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&IrpSp->Parameters; TranContext = IrpSp->FileObject->FsContext; if (!TranContext) { TI_DbgPrint(MID_TRACE, ("Bad transport context.\n")); return STATUS_INVALID_PARAMETER; } switch (Parameters->QueryType) { case TDI_QUERY_ADDRESS_INFO: { PTDI_ADDRESS_INFO AddressInfo; PADDRESS_FILE AddrFile; PTA_IP_ADDRESS Address; PCONNECTION_ENDPOINT Endpoint = NULL; if (MmGetMdlByteCount(Irp->MdlAddress) < (FIELD_OFFSET(TDI_ADDRESS_INFO, Address.Address[0].Address) + sizeof(TDI_ADDRESS_IP))) { TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n")); return STATUS_BUFFER_TOO_SMALL; } AddressInfo = (PTDI_ADDRESS_INFO)MmGetSystemAddressForMdl(Irp->MdlAddress); Address = (PTA_IP_ADDRESS)&AddressInfo->Address; switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) { case TDI_TRANSPORT_ADDRESS_FILE: AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle; Address->TAAddressCount = 1; Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP; Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP; Address->Address[0].Address[0].sin_port = AddrFile->Port; Address->Address[0].Address[0].in_addr = AddrFile->Address.Address.IPv4Address; RtlZeroMemory( &Address->Address[0].Address[0].sin_zero, sizeof(Address->Address[0].Address[0].sin_zero)); return STATUS_SUCCESS; case TDI_CONNECTION_FILE: Endpoint = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext; Address->TAAddressCount = 1; Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP; Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP; Address->Address[0].Address[0].sin_port = Endpoint->AddressFile->Port; Address->Address[0].Address[0].in_addr = Endpoint->AddressFile->Address.Address.IPv4Address; RtlZeroMemory( &Address->Address[0].Address[0].sin_zero, sizeof(Address->Address[0].Address[0].sin_zero)); return STATUS_SUCCESS; default: TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n")); return STATUS_INVALID_PARAMETER; } } case TDI_QUERY_CONNECTION_INFO: { PTDI_CONNECTION_INFO ConnectionInfo; //PCONNECTION_ENDPOINT Endpoint; if (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(*ConnectionInfo)) { TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n")); return STATUS_BUFFER_TOO_SMALL; } ConnectionInfo = (PTDI_CONNECTION_INFO) MmGetSystemAddressForMdl(Irp->MdlAddress); switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) { case TDI_CONNECTION_FILE: //Endpoint = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext; RtlZeroMemory(ConnectionInfo, sizeof(*ConnectionInfo)); return STATUS_SUCCESS; default: TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n")); return STATUS_INVALID_PARAMETER; } } case TDI_QUERY_MAX_DATAGRAM_INFO: { PTDI_MAX_DATAGRAM_INFO MaxDatagramInfo; if (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(*MaxDatagramInfo)) { TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n")); return STATUS_BUFFER_TOO_SMALL; } MaxDatagramInfo = (PTDI_MAX_DATAGRAM_INFO) MmGetSystemAddressForMdl(Irp->MdlAddress); MaxDatagramInfo->MaxDatagramSize = 0xFFFF; return STATUS_SUCCESS; } } return STATUS_NOT_IMPLEMENTED; }
DECLHIDDEN(int) rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable) { AssertMsgReturn(cb <= _1G, ("%#x\n", cb), VERR_OUT_OF_RANGE); /* for safe size_t -> ULONG */ /* * Try see if we get lucky first... * (We could probably just assume we're lucky on NT4.) */ int rc = rtR0MemObjNativeAllocPage(ppMem, cb, fExecutable); if (RT_SUCCESS(rc)) { size_t iPage = cb >> PAGE_SHIFT; while (iPage-- > 0) if (rtR0MemObjNativeGetPagePhysAddr(*ppMem, iPage) >= _4G) { rc = VERR_NO_LOW_MEMORY; break; } if (RT_SUCCESS(rc)) return rc; /* The following ASSUMES that rtR0MemObjNativeAllocPage returns a completed object. */ RTR0MemObjFree(*ppMem, false); *ppMem = NULL; } #ifndef IPRT_TARGET_NT4 /* * Use MmAllocatePagesForMdl to specify the range of physical addresses we wish to use. */ PHYSICAL_ADDRESS Zero; Zero.QuadPart = 0; PHYSICAL_ADDRESS HighAddr; HighAddr.QuadPart = _4G - 1; PMDL pMdl = MmAllocatePagesForMdl(Zero, HighAddr, Zero, cb); if (pMdl) { if (MmGetMdlByteCount(pMdl) >= cb) { __try { void *pv = MmMapLockedPagesSpecifyCache(pMdl, KernelMode, MmCached, NULL /* no base address */, FALSE /* no bug check on failure */, NormalPagePriority); if (pv) { PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_LOW, pv, cb); if (pMemNt) { pMemNt->fAllocatedPagesForMdl = true; pMemNt->cMdls = 1; pMemNt->apMdls[0] = pMdl; *ppMem = &pMemNt->Core; return VINF_SUCCESS; } MmUnmapLockedPages(pv, pMdl); } } __except(EXCEPTION_EXECUTE_HANDLER) { NTSTATUS rcNt = GetExceptionCode(); Log(("rtR0MemObjNativeAllocLow: Exception Code %#x\n", rcNt)); /* nothing */ } } MmFreePagesFromMdl(pMdl); ExFreePool(pMdl); }
VOID BalloonFill( IN WDFOBJECT WdfDevice, IN size_t num) { PMDL pPageMdl; PHYSICAL_ADDRESS LowAddress; PHYSICAL_ADDRESS HighAddress; PPAGE_LIST_ENTRY pNewPageListEntry; PDEVICE_CONTEXT devCtx = GetDeviceContext(WdfDevice); ULONG pages_per_request = PAGE_SIZE/sizeof(PFN_NUMBER); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__); LowAddress.QuadPart = 0; HighAddress.QuadPart = (ULONGLONG)-1; num = min(num, pages_per_request); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "--> BalloonFill num = %d\n", num); for (devCtx->num_pfns = 0; devCtx->num_pfns < num; devCtx->num_pfns++) { if(IsLowMemory(WdfDevice)) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "LowMemoryCondition event was set to signaled,allocations stops, BalPageCount=%d\n", devCtx->num_pages); break; } pPageMdl = MmAllocatePagesForMdl( LowAddress, HighAddress, LowAddress, PAGE_SIZE ); if (pPageMdl == NULL) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "Balloon MDL Page Allocation Failed!!!, BalPageCount=%d\n", devCtx->num_pages); break; } if (MmGetMdlByteCount(pPageMdl) != PAGE_SIZE) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "Balloon MDL Page Allocation < PAGE_SIZE =%d, Failed!!!, BalPageCount=%d\n",MmGetMdlByteCount(pPageMdl), devCtx->num_pages); MmFreePagesFromMdl(pPageMdl); ExFreePool(pPageMdl); break; } pNewPageListEntry = (PPAGE_LIST_ENTRY)ExAllocateFromNPagedLookasideList(&devCtx->LookAsideList); if (pNewPageListEntry == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "List Entry Allocation Failed!!!\n"); MmFreePagesFromMdl(pPageMdl); ExFreePool(pPageMdl); break; } pNewPageListEntry->PageMdl = pPageMdl; pNewPageListEntry->PagePfn = devCtx->pfns_table[devCtx->num_pfns] = *MmGetMdlPfnArray(pPageMdl); PushEntryList(&devCtx->PageListHead, &(pNewPageListEntry->SingleListEntry)); devCtx->num_pages++; } if (devCtx->num_pfns > 0) { BalloonTellHost(WdfDevice, devCtx->InfVirtQueue); } }
NTSTATUS DispTdiQueryInformationEx( PIRP Irp, PIO_STACK_LOCATION IrpSp) /* * FUNCTION: TDI QueryInformationEx handler * ARGUMENTS: * Irp = Pointer to I/O request packet * IrpSp = Pointer to current stack location of Irp * RETURNS: * Status of operation */ { PTCP_REQUEST_QUERY_INFORMATION_EX InputBuffer; PTRANSPORT_CONTEXT TranContext; PTI_QUERY_CONTEXT QueryContext; PVOID OutputBuffer; TDI_REQUEST Request; UINT Size; UINT InputBufferLength; UINT OutputBufferLength; BOOLEAN InputMdlLocked = FALSE; BOOLEAN OutputMdlLocked = FALSE; PMDL InputMdl = NULL; PMDL OutputMdl = NULL; NTSTATUS Status = STATUS_SUCCESS; TI_DbgPrint(DEBUG_IRP, ("Called.\n")); TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext; switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) { case TDI_TRANSPORT_ADDRESS_FILE: Request.Handle.AddressHandle = TranContext->Handle.AddressHandle; break; case TDI_CONNECTION_FILE: Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext; break; case TDI_CONTROL_CHANNEL_FILE: Request.Handle.ControlChannel = TranContext->Handle.ControlChannel; break; default: TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n")); return STATUS_INVALID_PARAMETER; } InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; /* Validate parameters */ if ((InputBufferLength == sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)) && (OutputBufferLength != 0)) { InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX) IrpSp->Parameters.DeviceIoControl.Type3InputBuffer; OutputBuffer = Irp->UserBuffer; QueryContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(TI_QUERY_CONTEXT), QUERY_CONTEXT_TAG); if (QueryContext) { _SEH2_TRY { InputMdl = IoAllocateMdl(InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX), FALSE, TRUE, NULL); OutputMdl = IoAllocateMdl(OutputBuffer, OutputBufferLength, FALSE, TRUE, NULL); if (InputMdl && OutputMdl) { MmProbeAndLockPages(InputMdl, Irp->RequestorMode, IoModifyAccess); InputMdlLocked = TRUE; MmProbeAndLockPages(OutputMdl, Irp->RequestorMode, IoWriteAccess); OutputMdlLocked = TRUE; RtlCopyMemory(&QueryContext->QueryInfo, InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)); } else Status = STATUS_INSUFFICIENT_RESOURCES; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; if (NT_SUCCESS(Status)) { Size = MmGetMdlByteCount(OutputMdl); QueryContext->Irp = Irp; QueryContext->InputMdl = InputMdl; QueryContext->OutputMdl = OutputMdl; Request.RequestNotifyObject = DispTdiQueryInformationExComplete; Request.RequestContext = QueryContext; Status = InfoTdiQueryInformationEx(&Request, &QueryContext->QueryInfo.ID, OutputMdl, &Size, &QueryContext->QueryInfo.Context); DispTdiQueryInformationExComplete(QueryContext, Status, Size); TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status)); return Status; } /* An error occurred if we get here */ if (InputMdl) { if (InputMdlLocked) MmUnlockPages(InputMdl); IoFreeMdl(InputMdl); } if (OutputMdl) { if (OutputMdlLocked) MmUnlockPages(OutputMdl); IoFreeMdl(OutputMdl); } ExFreePoolWithTag(QueryContext, QUERY_CONTEXT_TAG); } else
VOID LoopCopyData ( IN PMDL Destination, IN PMDL Source, IN ULONG Length ) /*++ Routine Description: This routine copies data from the storage described by one MDL chain into the storage described by another MDL chain. Arguments: Destination - Pointer to first MDL in Destination chain Source - Pointer to first MDL in Source chain Length - Amount of data to copy. Caller must ensure that the Source and Destination chains are at least this long. Return Value: None. --*/ { PCHAR sourceAddress; ULONG sourceLength; PCHAR destinationAddress; ULONG destinationLength; ULONG copyLength; // // Get the virtual address of the first source buffer, mapping it // if necessary. Also get the length of the buffer. // sourceAddress = MmGetSystemAddressForMdl( Source ); sourceLength = MmGetMdlByteCount( Source ); // // Get the virtual address of the first destination buffer, mapping // it if necessary. Also get the length of the buffer. // destinationAddress = MmGetSystemAddressForMdl( Destination ); destinationLength = MmGetMdlByteCount( Destination ); // // Loop copying data. // do { // // The amount to copy in this pass is the minimum of 1) the // amount remaining in the current source buffer, 2) the amount // remaining in the current destination buffer, and 3) the // amount remaining in the overall copy operation. // copyLength = sourceLength; if ( copyLength > destinationLength ) copyLength = destinationLength; if ( copyLength > Length ) copyLength = Length; // // Copy from the source buffer into the destination buffer. // #ifndef TIMING IF_DEBUG(LOOP4) { DbgPrint( " copying %lx bytes from %lx to %lx\n", copyLength, sourceAddress, destinationAddress ); DbgPrint( " source data: %lx, %lx\n", *(PULONG)sourceAddress, *((PULONG)sourceAddress + 1) ); } RtlMoveMemory( destinationAddress, sourceAddress, copyLength ); #else if ( (NtGlobalFlag & 0x20000000) == 0 ) { RtlMoveMemory( destinationAddress, sourceAddress, copyLength ); } else { RtlMoveMemory( destinationAddress, sourceAddress, (copyLength > 200) ? 200 : copyLength ); } #endif // // If all of the requested data has been copied, leave. // Length -= copyLength; if ( Length == 0 ) { return; } // // If we have used up all of the current source buffer, move to // the next buffer. Get the virtual address of the next buffer, // mapping it if necessary. Also get the length of the buffer. // If we haven't used up the current source buffer, simply // update the source pointer and the remaining length. // if ( copyLength == sourceLength ) { Source = Source->Next; sourceAddress = MmGetSystemAddressForMdl( Source ); sourceLength = MmGetMdlByteCount( Source ); } else { sourceAddress += copyLength; sourceLength -= copyLength; } // // If we have used up all of the current destination buffer, // move to the next buffer. Get the virtual address of the next // buffer, mapping it if necessary. Also get the length of the // buffer. If we haven't used up the current destination // buffer, simply update the destination pointer and the // remaining length. // if ( copyLength == destinationLength ) { Destination = Destination->Next; destinationAddress = MmGetSystemAddressForMdl( Destination ); destinationLength = MmGetMdlByteCount( Destination ); } else { destinationAddress += copyLength; destinationLength -= copyLength; } } while ( TRUE ); // // Can't get here. // ASSERTMSG( FALSE, "Can't get here!" ); } // LoopCopyData
void * hax_map_user_pages(hax_memdesc_user *memdesc, uint64 uva_offset, uint64 size, hax_kmap_user *kmap) { ULONG base_size; uint64 uva_offset_low, uva_offset_high; uint64 base_uva, start_uva; PMDL pmdl; PVOID kva; if (!memdesc) { hax_error("%s: memdesc == NULL\n", __func__); return NULL; } if (!memdesc->pmdl) { hax_error("%s: memdesc->pmdl == NULL\n", __func__); return NULL; } if (!kmap) { hax_error("%s: kmap == NULL\n", __func__); return NULL; } // Size of the underlying UVA range base_size = MmGetMdlByteCount(memdesc->pmdl); // Align the lower bound of the UVA subrange to 4KB uva_offset_low = uva_offset & pgmask(PG_ORDER_4K); // Align the upper bound of the UVA subrange to 4KB uva_offset_high = (uva_offset + size + PAGE_SIZE_4K - 1) & pgmask(PG_ORDER_4K); if (uva_offset_high > base_size) { hax_error("%s: Invalid UVA subrange: uva_offset=0x%llx, size=0x%llx," " base_size=0x%llx\n", __func__, uva_offset, size, base_size); return NULL; } // Start of the underlying UVA range base_uva = (uint64)MmGetMdlVirtualAddress(memdesc->pmdl); // Start of the UVA subrange start_uva = base_uva + uva_offset_low; // Recalculate the size of the UVA subrange size = uva_offset_high - uva_offset_low; // Create a new MDL for the UVA subrange pmdl = IoAllocateMdl((PVOID)start_uva, size, FALSE, FALSE, NULL); if (!pmdl) { hax_error("%s: Failed to create MDL for UVA subrange: start_uva=0x%llx," " size=0x%llx\n", __func__, start_uva, size); return NULL; } // Associate the new MDL with the existing MDL IoBuildPartialMdl(memdesc->pmdl, pmdl, (PVOID)start_uva, size); kva = MmGetSystemAddressForMdlSafe(pmdl, NormalPagePriority); if (!kva) { hax_error("%s: Failed to create KVA mapping for UVA subrange:" " start_uva=0x%llx, size=0x%llx\n", __func__, start_uva, size); IoFreeMdl(pmdl); return NULL; } kmap->pmdl = pmdl; return kva; }
static NTSTATUS DumpFilterWrite (PFILTER_EXTENSION filterExtension, PLARGE_INTEGER diskWriteOffset, PMDL writeMdl) { ULONG dataLength = MmGetMdlByteCount (writeMdl); uint64 offset = DumpPartitionOffset.QuadPart + diskWriteOffset->QuadPart; uint64 intersectStart; uint32 intersectLength; PVOID writeBuffer; CSHORT origMdlFlags; if (BootDriveFilterExtension->MagicNumber != TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER) TC_BUG_CHECK (STATUS_CRC_ERROR); if (BootDriveFilterExtension->Queue.EncryptedAreaEndUpdatePending) // Hibernation should always abort the setup thread TC_BUG_CHECK (STATUS_INVALID_PARAMETER); if (BootDriveFilterExtension->Queue.EncryptedAreaStart == -1 || BootDriveFilterExtension->Queue.EncryptedAreaEnd == -1) return STATUS_SUCCESS; if (dataLength > WriteFilterBufferSize) TC_BUG_CHECK (STATUS_BUFFER_OVERFLOW); // Bug check is required as returning an error does not prevent data from being written to disk if ((dataLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0) TC_BUG_CHECK (STATUS_INVALID_PARAMETER); if ((offset & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0) TC_BUG_CHECK (STATUS_INVALID_PARAMETER); writeBuffer = MmGetSystemAddressForMdlSafe (writeMdl, HighPagePriority); if (!writeBuffer) TC_BUG_CHECK (STATUS_INSUFFICIENT_RESOURCES); memcpy (WriteFilterBuffer, writeBuffer, dataLength); GetIntersection (offset, dataLength, BootDriveFilterExtension->Queue.EncryptedAreaStart, BootDriveFilterExtension->Queue.EncryptedAreaEnd, &intersectStart, &intersectLength); if (intersectLength > 0) { UINT64_STRUCT dataUnit; dataUnit.Value = intersectStart / ENCRYPTION_DATA_UNIT_SIZE; if (BootDriveFilterExtension->Queue.RemapEncryptedArea) { diskWriteOffset->QuadPart += BootDriveFilterExtension->Queue.RemappedAreaOffset; dataUnit.Value += BootDriveFilterExtension->Queue.RemappedAreaDataUnitOffset; } EncryptDataUnitsCurrentThread (WriteFilterBuffer + (intersectStart - offset), &dataUnit, intersectLength / ENCRYPTION_DATA_UNIT_SIZE, BootDriveFilterExtension->Queue.CryptoInfo); } origMdlFlags = writeMdl->MdlFlags; MmInitializeMdl (writeMdl, WriteFilterBuffer, dataLength); MmBuildMdlForNonPagedPool (writeMdl); // Instead of using MmGetSystemAddressForMdlSafe(), some buggy custom storage drivers may directly test MDL_MAPPED_TO_SYSTEM_VA flag, // disregarding the fact that other MDL flags may be set by the system or a dump filter (e.g. MDL_SOURCE_IS_NONPAGED_POOL flag only). // Therefore, to work around this issue, the original flags will be restored even if they do not match the new MDL. // MS BitLocker also uses this hack/workaround (it should be safe to use until the MDL structure is changed). writeMdl->MdlFlags = origMdlFlags; return STATUS_SUCCESS; }
NDIS_STATUS PacketReceiveIndicate ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookAheadBuffer, IN UINT LookaheadBufferSize, IN UINT PacketSize ) { POPEN_INSTANCE open; PIO_STACK_LOCATION irpSp; PIRP irp; PLIST_ENTRY packetListEntry; PNDIS_PACKET pPacket; ULONG sizeToTransfer; NDIS_STATUS status; UINT bytesTransfered = 0; ULONG bufferLength; PPACKET_RESERVED reserved; PMDL pMdl; // DebugPrint(("ReceiveIndicate\n")); open= (POPEN_INSTANCE)ProtocolBindingContext; if (HeaderBufferSize > ETHERNET_HEADER_LENGTH) { return NDIS_STATUS_SUCCESS; } // See if there are any pending read that we can satisfy packetListEntry = ExInterlockedRemoveHeadList( &open->RcvList, &open->RcvQSpinLock ); if (packetListEntry == NULL) { // DebugPrint(("No pending read, dropping packets\n")); return NDIS_STATUS_NOT_ACCEPTED; } reserved = CONTAINING_RECORD(packetListEntry,PACKET_RESERVED,ListElement); pPacket = CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved); irp = RESERVED(pPacket)->Irp; irpSp = IoGetCurrentIrpStackLocation(irp); // 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(irp, NULL); bufferLength = irpSp->Parameters.Read.Length-ETHERNET_HEADER_LENGTH; sizeToTransfer = (PacketSize < bufferLength) ? PacketSize : bufferLength; NdisMoveMappedMemory( MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority), HeaderBuffer, HeaderBufferSize ); pMdl=IoAllocateMdl( MmGetMdlVirtualAddress(irp->MdlAddress), MmGetMdlByteCount(irp->MdlAddress), FALSE, FALSE, NULL ); if (pMdl == NULL) { // DebugPrint(("Packet: Read-Failed to allocate Mdl\n")); status = NDIS_STATUS_RESOURCES; goto ERROR; } IoBuildPartialMdl( irp->MdlAddress, pMdl, ((PUCHAR)MmGetMdlVirtualAddress(irp->MdlAddress))+ETHERNET_HEADER_LENGTH, 0 ); pMdl->Next = NULL; RESERVED(pPacket)->pMdl=pMdl; NdisChainBufferAtFront(pPacket,pMdl); NdisTransferData( &status, open->AdapterHandle, MacReceiveContext, 0, sizeToTransfer, pPacket, &bytesTransfered ); if (status == NDIS_STATUS_PENDING) { return NDIS_STATUS_SUCCESS; } ERROR: PacketTransferDataComplete( open, pPacket, status, bytesTransfered ); return NDIS_STATUS_SUCCESS; }
NTSTATUS USBSTOR_SendRequest( IN PDEVICE_OBJECT DeviceObject, IN PIRP OriginalRequest, IN UCHAR CommandLength, IN PUCHAR Command, IN ULONG TransferDataLength, IN PUCHAR TransferData, IN ULONG RetryCount) { PIRP_CONTEXT Context; PPDO_DEVICE_EXTENSION PDODeviceExtension; PFDO_DEVICE_EXTENSION FDODeviceExtension; PIRP Irp; PUCHAR MdlVirtualAddress; // // first allocate irp context // Context = USBSTOR_AllocateIrpContext(); if (!Context) { // // no memory // return STATUS_INSUFFICIENT_RESOURCES; } // // get PDO device extension // PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // get FDO device extension // FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension; // // now build the cbw // USBSTOR_BuildCBW((ULONG)Context->cbw, TransferDataLength, PDODeviceExtension->LUN, CommandLength, Command, Context->cbw); DPRINT("CBW %p\n", Context->cbw); DumpCBW((PUCHAR)Context->cbw); // // now initialize the urb // UsbBuildInterruptOrBulkTransferRequest(&Context->Urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle, Context->cbw, NULL, sizeof(CBW), USBD_TRANSFER_DIRECTION_OUT, NULL); // // initialize rest of context // Context->Irp = OriginalRequest; Context->TransferData = TransferData; Context->TransferDataLength = TransferDataLength; Context->FDODeviceExtension = FDODeviceExtension; Context->PDODeviceExtension = PDODeviceExtension; Context->RetryCount = RetryCount; // // is there transfer data // if (Context->TransferDataLength) { // // check if the original request already does have an mdl associated // if (OriginalRequest) { if ((OriginalRequest->MdlAddress != NULL) && (Context->TransferData == NULL || Command[0] == SCSIOP_READ || Command[0] == SCSIOP_WRITE)) { // // Sanity check that the Mdl does describe the TransferData for read/write // if (CommandLength == UFI_READ_WRITE_CMD_LEN) { MdlVirtualAddress = MmGetMdlVirtualAddress(OriginalRequest->MdlAddress); // // is there an offset // if (MdlVirtualAddress != Context->TransferData) { // // lets build an mdl // Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, MmGetMdlByteCount(OriginalRequest->MdlAddress), FALSE, FALSE, NULL); if (!Context->TransferBufferMDL) { // // failed to allocate MDL // return STATUS_INSUFFICIENT_RESOURCES; } // // now build the partial mdl // IoBuildPartialMdl(OriginalRequest->MdlAddress, Context->TransferBufferMDL, Context->TransferData, Context->TransferDataLength); } } if (!Context->TransferBufferMDL) { // // I/O paging request // Context->TransferBufferMDL = OriginalRequest->MdlAddress; } } else { // // allocate mdl for buffer, buffer must be allocated from NonPagedPool // Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL); if (!Context->TransferBufferMDL) { // // failed to allocate MDL // return STATUS_INSUFFICIENT_RESOURCES; } // // build mdl for nonpaged pool // MmBuildMdlForNonPagedPool(Context->TransferBufferMDL); } } else { // // allocate mdl for buffer, buffer must be allocated from NonPagedPool // Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL); if (!Context->TransferBufferMDL) { // // failed to allocate MDL // return STATUS_INSUFFICIENT_RESOURCES; } // // build mdl for nonpaged pool // MmBuildMdlForNonPagedPool(Context->TransferBufferMDL); } } // // now allocate the request // Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); if (!Irp) { FreeItem(Context->cbw); FreeItem(Context); return STATUS_INSUFFICIENT_RESOURCES; } if (OriginalRequest) { // // mark orignal irp as pending // IoMarkIrpPending(OriginalRequest); } // // send request // USBSTOR_SendCBW(Context, Irp); // // done // return STATUS_PENDING; }