Author: cgutman Date: Tue Jan 3 17:54:01 2012 New Revision: 54818
URL: http://svn.reactos.org/svn/reactos?rev=54818&view=rev Log: [NDISUIO] - Implement IOCTL_CANCEL_READ - Implement IRP_MJ_READ and IRP_MJ_WRITE handling - Misc fixes
Modified: branches/wlan-bringup/drivers/network/ndisuio/ioctl.c branches/wlan-bringup/drivers/network/ndisuio/misc.c branches/wlan-bringup/drivers/network/ndisuio/ndisuio.h branches/wlan-bringup/drivers/network/ndisuio/protocol.c branches/wlan-bringup/drivers/network/ndisuio/readwrite.c
Modified: branches/wlan-bringup/drivers/network/ndisuio/ioctl.c URL: http://svn.reactos.org/svn/reactos/branches/wlan-bringup/drivers/network/ndi... ============================================================================== --- branches/wlan-bringup/drivers/network/ndisuio/ioctl.c [iso-8859-1] (original) +++ branches/wlan-bringup/drivers/network/ndisuio/ioctl.c [iso-8859-1] Tue Jan 3 17:54:01 2012 @@ -12,6 +12,40 @@ #include <debug.h>
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) { PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext; @@ -232,6 +266,9 @@ /* 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);
Modified: branches/wlan-bringup/drivers/network/ndisuio/misc.c URL: http://svn.reactos.org/svn/reactos/branches/wlan-bringup/drivers/network/ndi... ============================================================================== --- branches/wlan-bringup/drivers/network/ndisuio/misc.c [iso-8859-1] (original) +++ branches/wlan-bringup/drivers/network/ndisuio/misc.c [iso-8859-1] Tue Jan 3 17:54:01 2012 @@ -10,6 +10,98 @@
#define NDEBUG #include <debug.h> + +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 @@ /* 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); }
Modified: branches/wlan-bringup/drivers/network/ndisuio/ndisuio.h URL: http://svn.reactos.org/svn/reactos/branches/wlan-bringup/drivers/network/ndi... ============================================================================== --- branches/wlan-bringup/drivers/network/ndisuio/ndisuio.h [iso-8859-1] (original) +++ branches/wlan-bringup/drivers/network/ndisuio/ndisuio.h [iso-8859-1] Tue Jan 3 17:54:01 2012 @@ -28,9 +28,7 @@
/* Receive packet list */ LIST_ENTRY PacketList; - - /* Cancel read */ - BOOLEAN CancelRead; + KEVENT PacketReadEvent;
/* Global list entry */ LIST_ENTRY ListEntry;
Modified: branches/wlan-bringup/drivers/network/ndisuio/protocol.c URL: http://svn.reactos.org/svn/reactos/branches/wlan-bringup/drivers/network/ndi... ============================================================================== --- branches/wlan-bringup/drivers/network/ndisuio/protocol.c [iso-8859-1] (original) +++ branches/wlan-bringup/drivers/network/ndisuio/protocol.c [iso-8859-1] Tue Jan 3 17:54:01 2012 @@ -48,7 +48,13 @@ 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 @@ 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 @@ 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 @@ 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 @@
/* 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 @@ /* 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);
Modified: branches/wlan-bringup/drivers/network/ndisuio/readwrite.c URL: http://svn.reactos.org/svn/reactos/branches/wlan-bringup/drivers/network/ndi... ============================================================================== --- branches/wlan-bringup/drivers/network/ndisuio/readwrite.c [iso-8859-1] (original) +++ branches/wlan-bringup/drivers/network/ndisuio/readwrite.c [iso-8859-1] Tue Jan 3 17:54:01 2012 @@ -11,34 +11,134 @@ #define NDEBUG #include <debug.h>
-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);
- IoCompleteRequest(Irp, IO_NO_INCREMENT); + /* Check if we have a packet */ + if (IsListEmpty(&AdapterContext->PacketList)) + { + KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
- return STATUS_NOT_IMPLEMENTED; + /* 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; + + /* Copy the packet */ + RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, + &PacketEntry->PacketBuffer[0], + BytesCopied); + + /* Free the packet entry */ + ExFreePool(PacketEntry); + } + else + { + /* Something failed */ + BytesCopied = 0; + } + + /* 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);
- /* FIXME: Not implemented */ - Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; - Irp->IoStatus.Information = 0; + /* Wait for the send */ + if (Status == NDIS_STATUS_PENDING) + { + KeWaitForSingleObject(&AdapterContext->AsyncEvent, + Executive, + KernelMode, + FALSE, + NULL); + Status = AdapterContext->AsyncStatus; + }
- IoCompleteRequest(Irp, IO_NO_INCREMENT); + /* Check if it succeeded */ + if (Status == NDIS_STATUS_SUCCESS) + BytesCopied = IrpSp->Parameters.Write.Length;
- return STATUS_NOT_IMPLEMENTED; + CleanupAndFreePacket(Packet); + } + else + { + /* No memory */ + Status = STATUS_NO_MEMORY; + } + + /* Complete the IRP */ + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = BytesCopied; + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + return Status; }