From 9e9a049290c866396b120fc32776438491c68475 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Tue, 3 Jan 2012 17:54:01 +0000 Subject: [PATCH] [NDISUIO] - Implement IOCTL_CANCEL_READ - Implement IRP_MJ_READ and IRP_MJ_WRITE handling - Misc fixes svn path=/branches/wlan-bringup/; revision=54818 --- drivers/network/ndisuio/ioctl.c | 37 +++++++++ drivers/network/ndisuio/misc.c | 108 ++++++++++++++++++++---- drivers/network/ndisuio/ndisuio.h | 4 +- drivers/network/ndisuio/protocol.c | 99 ++++++++++++++++++++-- drivers/network/ndisuio/readwrite.c | 124 +++++++++++++++++++++++++--- 5 files changed, 337 insertions(+), 35 deletions(-) diff --git a/drivers/network/ndisuio/ioctl.c b/drivers/network/ndisuio/ioctl.c index 91665eb3951..df3a638390d 100644 --- a/drivers/network/ndisuio/ioctl.c +++ b/drivers/network/ndisuio/ioctl.c @@ -11,6 +11,40 @@ #define NDEBUG #include +NTSTATUS +CancelPacketRead(PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext; + PNDISUIO_PACKET_ENTRY PacketEntry; + NTSTATUS Status; + + /* Indicate a 0-byte packet on the queue so one read returns 0 */ + PacketEntry = ExAllocatePool(PagedPool, sizeof(NDISUIO_PACKET_ENTRY)); + if (PacketEntry) + { + PacketEntry->PacketLength = 0; + + ExInterlockedInsertTailList(&AdapterContext->PacketList, + &PacketEntry->ListEntry, + &AdapterContext->Spinlock); + + KeSetEvent(&AdapterContext->PacketReadEvent, IO_NO_INCREMENT, FALSE); + + Status = STATUS_SUCCESS; + } + else + { + Status = STATUS_NO_MEMORY; + } + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return Status; +} + NTSTATUS SetAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp) { @@ -232,6 +266,9 @@ NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, /* Now handle other IOCTLs */ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { + case IOCTL_CANCEL_READ: + return CancelPacketRead(Irp, IrpSp); + case IOCTL_NDISUIO_QUERY_OID_VALUE: return QueryAdapterOid(Irp, IrpSp); diff --git a/drivers/network/ndisuio/misc.c b/drivers/network/ndisuio/misc.c index 07c342feab6..67ce9f027a5 100644 --- a/drivers/network/ndisuio/misc.c +++ b/drivers/network/ndisuio/misc.c @@ -11,6 +11,98 @@ #define NDEBUG #include +NDIS_STATUS +AllocateAndChainBuffer(PNDIS_PACKET Packet, PVOID Buffer, ULONG BufferSize, BOOLEAN Front) +{ + NDIS_STATUS Status; + + /* Allocate the NDIS buffer mapping the pool */ + NdisAllocateBuffer(&Status, + &Buffer, + GlobalBufferPoolHandle, + Buffer, + Length); + if (Status != NDIS_STATUS_SUCCESS) + { + DPRINT1("No free buffer descriptors\n"); + return Status; + } + + if (Front) + { + /* Chain the buffer to front */ + NdisChainBufferAtFront(Packet, Buffer); + } + else + { + /* Chain the buffer to back */ + NdisChainBufferAtBack(Packet, Buffer); + } + + /* Return success */ + return NDIS_STATUS_SUCCESS; +} + +PNDIS_PACKET +CreatePacketFromPoolBuffer(PVOID Buffer, ULONG BufferSize) +{ + PNDIS_PACKET Packet; + NDIS_STATUS Status; + + /* Allocate a packet descriptor */ + NdisAllocatePacket(&Status, + &Packet, + GlobalPacketPoolHandle); + if (Status != NDIS_STATUS_SUCCESS) + { + DPRINT1("No free packet descriptors\n"); + return NULL; + } + + /* Use the helper to chain the buffer */ + Status = AllocateAndChainBuffer(Packet, Buffer, BufferSize, TRUE); + if (Status != NDIS_STATUS_SUCCESS) + { + NdisFreePacket(Packet); + return NULL; + } + + /* Return the packet */ + return Packet; +} + +VOID +CleanupAndFreePacket(PNDIS_PACKET Packet, BOOLEAN FreePool) +{ + PNDIS_BUFFER Buffer; + PVOID Data; + ULONG Length; + + /* Free each buffer and its backing pool memory */ + while (TRUE) + { + /* Unchain each buffer */ + NdisUnchainBufferAtFront(Packet, &Buffer); + if (!Buffer) + break; + + /* Get the backing memory */ + NdisQueryBuffer(Buffer, &Data, &Length); + + /* Free the buffer */ + NdisFreeBuffer(Buffer); + + if (FreePool) + { + /* Free the backing memory */ + ExFreePool(Data); + } + } + + /* Free the packet descriptor */ + NdisFreePacket(Packet); +} + PNDISUIO_ADAPTER_CONTEXT FindAdapterContextByName(PNDIS_STRING DeviceName) { @@ -70,19 +162,7 @@ DereferenceAdapterContextWithOpenEntry(PNDISUIO_ADAPTER_CONTEXT AdapterContext, /* Free the open entry */ ExFreePool(OpenEntry); } - - /* See if this binding can be destroyed */ - if (AdapterContext->OpenCount == 0) - { - /* Unlock the context */ - KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); - /* Destroy the adapter context */ - UnbindAdapterByContext(AdapterContext); - } - else - { - /* Still more references on it */ - KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); - } + /* Release the adapter context lock */ + KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); } diff --git a/drivers/network/ndisuio/ndisuio.h b/drivers/network/ndisuio/ndisuio.h index 6c3ca505974..f4a83d19180 100644 --- a/drivers/network/ndisuio/ndisuio.h +++ b/drivers/network/ndisuio/ndisuio.h @@ -28,9 +28,7 @@ struct _NDISUIO_ADAPTER_CONTEXT /* Receive packet list */ LIST_ENTRY PacketList; - - /* Cancel read */ - BOOLEAN CancelRead; + KEVENT PacketReadEvent; /* Global list entry */ LIST_ENTRY ListEntry; diff --git a/drivers/network/ndisuio/protocol.c b/drivers/network/ndisuio/protocol.c index f95cf63e918..eff7a2a9e73 100644 --- a/drivers/network/ndisuio/protocol.c +++ b/drivers/network/ndisuio/protocol.c @@ -48,7 +48,13 @@ NduSendComplete(NDIS_HANDLE ProtocolBindingContext, PNDIS_PACKET Packet, NDIS_STATUS Status) { - /* FIXME: Implement send/receive */ + PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext; + + DPRINT("Asynchronous adapter send completed\n"); + + /* Store the final status and signal the event */ + AdapterContext->AsyncStatus = Status; + KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE); } VOID @@ -58,7 +64,13 @@ NduTransferDataComplete(NDIS_HANDLE ProtocolBindingContext, NDIS_STATUS Status, UINT BytesTransferred) { - /* FIXME: Implement send/receive */ + PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext; + + DPRINT("Asynchronous adapter transfer completed\n"); + + /* Store the final status and signal the event */ + AdapterContext->AsyncStatus = Status; + KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE); } VOID @@ -100,8 +112,82 @@ NduReceive(NDIS_HANDLE ProtocolBindingContext, UINT LookaheadBufferSize, UINT PacketSize) { - /* FIXME: Implement send/receive */ - return NDIS_STATUS_NOT_ACCEPTED; + PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext; + PVOID PacketBuffer; + PNDIS_PACKET Packet; + NDIS_STATUS Status; + ULONG BytesTransferred; + + /* Allocate a buffer to hold the packet data and header */ + PacketBuffer = ExAllocatePool(NonPagedPool, PacketSize); + if (!PacketBuffer) + return NDIS_STATUS_NOT_ACCEPTED; + + /* Allocate the packet descriptor and buffer */ + Packet = CreatePacketFromPoolBuffer((PUCHAR)PacketBuffer + HeaderBufferSize, + PacketSize); + if (!Packet) + { + ExFreePool(PacketBuffer); + return NDIS_STATUS_NOT_ACCEPTED; + } + + /* Transfer the packet data into our data buffer */ + NdisTransferData(&Status, + AdapterContext->BindingHandle, + MacReceiveContext, + 0, + PacketSize, + &BytesTransferred); + if (Status == NDIS_STATUS_PENDING) + { + KeWaitForSingleObject(&AdapterContext->AsyncEvent, + Executive, + KernelMode, + FALSE, + NULL); + Status = AdapterContext->AsyncStatus; + } + if (Status != NDIS_STATUS_SUCCESS) + { + DPRINT1("Failed to transfer data with status 0x%x\n", Status); + CleanupAndFreePacket(Packet, TRUE); + return NDIS_STATUS_NOT_ACCEPTED; + } + + /* Copy the header data */ + RtlCopyMemory(PacketBuffer, HeaderBuffer, HeaderBufferSize); + + /* Free the packet descriptor and buffers + but not the pool because we still need it */ + CleanupAndFreePacket(Packet, FALSE); + + /* Allocate a packet entry from paged pool */ + PacketEntry = ExAllocatePool(PagedPool, sizeof(NDISUIO_PACKET_ENTRY) + BytesTransferred + HeaderBufferSize - 1); + if (!PacketEntry) + { + ExFreePool(PacketBuffer); + return NDIS_STATUS_RESOURCES; + } + + /* Initialize the packet entry and copy in packet data */ + PacketEntry->PacketLength = BytesTransferred + HeaderBufferSize; + RtlCopyMemory(&PacketEntry->PacketData[0], PacketBuffer, PacketEntry->PacketLength); + + /* Free the old non-paged buffer */ + ExFreePool(PacketBuffer); + + /* Insert the packet on the adapter's packet list */ + ExInterlockedInsertTailList(&AdapterContext->PacketList, + &PacketEntry->ListEntry, + &AdapterContext->Spinlock); + + /* Signal the read event */ + KeSetEvent(&AdapterContext->PacketReadEvent, + IO_NETWORK_INCREMENT, + FALSE); + + return NDIS_STATUS_SUCCESS; } VOID @@ -134,7 +220,7 @@ UnbindAdapterByContext(PNDISUIO_ADAPTER_CONTEXT AdapterContext) KIRQL OldIrql; PLIST_ENTRY CurrentOpenEntry; PNDISUIO_OPEN_ENTRY OpenEntry; - + /* Remove the adapter context from the global list */ KeAcquireSpinLock(&GlobalAdapterListLock, &OldIrql); RemoveEntryList(&AdapterContext->ListEntry); @@ -167,7 +253,7 @@ UnbindAdapterByContext(PNDISUIO_ADAPTER_CONTEXT AdapterContext) /* If this fails, we have a refcount mismatch somewhere */ ASSERT(AdapterContext->OpenCount == 0); - + /* Send the close request */ NdisCloseAdapter(Status, AdapterContext->BindingHandle); @@ -206,6 +292,7 @@ BindAdapterByName(PNDIS_STRING DeviceName, PNDISUIO_ADAPTER_CONTEXT *Context) /* Set up the adapter context */ RtlZeroMemory(AdapterContext, sizeof(*AdapterContext)); KeInitializeEvent(&AdapterContext->AsyncEvent, SynchronizationEvent, FALSE); + KeInitializeEvent(&AdapterContext->PacketReadEvent, SynchronizationEvent, FALSE); KeInitializeSpinLock(&AdapterContext->Spinlock); InitializeListHead(&AdapterContext->PacketList); InitializeListHead(&AdapterContext->OpenEntryList); diff --git a/drivers/network/ndisuio/readwrite.c b/drivers/network/ndisuio/readwrite.c index d726ef06213..4e1f0e9fa3b 100644 --- a/drivers/network/ndisuio/readwrite.c +++ b/drivers/network/ndisuio/readwrite.c @@ -11,34 +11,134 @@ #define NDEBUG #include -VOID +NTSTATUS NTAPI NduDispatchRead(PDEVICE_OBJECT DeviceObject, PIRP Irp) { + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext; + KIRQL OldIrql; + NTSTATUS Status; + PLIST_ENTRY ListEntry; + PNDISUIO_PACKET_ENTRY PacketEntry = NULL; + ULONG BytesCopied = 0; + ASSERT(DeviceObject == GlobalDeviceObject); - /* FIXME: Not implemented */ - Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; - Irp->IoStatus.Information = 0; + while (TRUE) + { + KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql); + + /* Check if we have a packet */ + if (IsListEmpty(&AdapterContext->PacketList)) + { + KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); + + /* Wait for a packet (in the context of the calling user thread) */ + Status = KeWaitForSingleObject(&AdapterContext->PacketReadEvent, + UserRequest, + UserMode, + TRUE, + NULL); + if (Status != STATUS_SUCCESS) + break; + } + else + { + /* Remove the first packet in the list */ + ListEntry = RemoveHeadList(&AdapterContext->PacketList); + PacketEntry = CONTAINING_RECORD(ListEntry, NDISUIO_PACKET_ENTRY, ListEntry); + + /* Release the adapter lock */ + KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); + + /* And we're done with this loop */ + Status = STATUS_SUCCESS; + break; + } + } + + /* Check if we got a packet */ + if (PacketEntry != NULL) + { + /* Find the right amount of bytes to copy */ + BytesCopied = PacketEntry->PacketLength; + if (BytesCopied > IrpSp->Parameters.Read.Length) + BytesCopied = IrpSp->Parameters.Read.Length; - IoCompleteRequest(Irp, IO_NO_INCREMENT); + /* Copy the packet */ + RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, + &PacketEntry->PacketBuffer[0], + BytesCopied); + + /* Free the packet entry */ + ExFreePool(PacketEntry); + } + else + { + /* Something failed */ + BytesCopied = 0; + } - return STATUS_NOT_IMPLEMENTED; + /* Complete the IRP */ + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = BytesCopied; + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + return Status; } -VOID +NTSTATUS NTAPI NduDispatchWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp) { + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext; + PNDIS_PACKET Packet; + NDIS_STATUS Status; + ULONG BytesCopied = 0; + ASSERT(DeviceObject == GlobalDeviceObject); + + /* Create a packet and buffer descriptor for this user buffer */ + Packet = CreatePacketFromPoolBuffer(Irp->AssociatedIrp.SystemBuffer, + IrpSp->Parameters.Write.Length); + if (Packet) + { + /* Send it via NDIS */ + NdisSend(&Status, + AdapterContext->BindingHandle, + Packet); + + /* Wait for the send */ + if (Status == NDIS_STATUS_PENDING) + { + KeWaitForSingleObject(&AdapterContext->AsyncEvent, + Executive, + KernelMode, + FALSE, + NULL); + Status = AdapterContext->AsyncStatus; + } + + /* Check if it succeeded */ + if (Status == NDIS_STATUS_SUCCESS) + BytesCopied = IrpSp->Parameters.Write.Length; - /* FIXME: Not implemented */ - Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; - Irp->IoStatus.Information = 0; + CleanupAndFreePacket(Packet); + } + else + { + /* No memory */ + Status = STATUS_NO_MEMORY; + } - IoCompleteRequest(Irp, IO_NO_INCREMENT); + /* Complete the IRP */ + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = BytesCopied; + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); - return STATUS_NOT_IMPLEMENTED; + return Status; } \ No newline at end of file -- 2.17.1