reactos/drivers/network/ndisuio/readwrite.c
2021-06-11 15:33:08 +03:00

210 lines
6.2 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS NDIS User I/O driver
* FILE: readwrite.c
* PURPOSE: Handles IRP_MJ_READ and IRP_MJ_WRITE
* PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
*/
#include "ndisuio.h"
#define NDEBUG
#include <debug.h>
static
VOID
NTAPI
ReadIrpCancel(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
PNDISUIO_PACKET_ENTRY PacketEntry;
/* Release the cancel spin lock */
IoReleaseCancelSpinLock(Irp->CancelIrql);
/* Indicate a 0-byte packet on the queue to cancel the read */
PacketEntry = ExAllocatePool(NonPagedPool, sizeof(NDISUIO_PACKET_ENTRY));
if (PacketEntry)
{
PacketEntry->PacketLength = 0;
ExInterlockedInsertHeadList(&AdapterContext->PacketList,
&PacketEntry->ListEntry,
&AdapterContext->Spinlock);
KeSetEvent(&AdapterContext->PacketReadEvent, IO_NO_INCREMENT, FALSE);
}
}
NTSTATUS
NTAPI
NduDispatchRead(PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
PNDISUIO_OPEN_ENTRY OpenEntry = IrpSp->FileObject->FsContext2;
KIRQL OldIrql, OldCancelIrql;
NTSTATUS Status;
PLIST_ENTRY ListEntry;
PNDISUIO_PACKET_ENTRY PacketEntry = NULL;
ULONG BytesCopied = 0;
ASSERT(DeviceObject == GlobalDeviceObject);
if (OpenEntry->WriteOnly)
{
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INVALID_PARAMETER;
}
/* Make the read cancellable */
IoAcquireCancelSpinLock(&OldCancelIrql);
IoSetCancelRoutine(Irp, ReadIrpCancel);
if (Irp->Cancel)
{
IoReleaseCancelSpinLock(OldCancelIrql);
/* Indicate a 0 byte read */
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
IoReleaseCancelSpinLock(OldCancelIrql);
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)
{
/* Remove the cancel routine */
IoAcquireCancelSpinLock(&OldCancelIrql);
IoSetCancelRoutine(Irp, NULL);
IoReleaseCancelSpinLock(OldCancelIrql);
break;
}
}
else
{
/* Remove the cancel routine */
IoAcquireCancelSpinLock(&OldCancelIrql);
IoSetCancelRoutine(Irp, NULL);
IoReleaseCancelSpinLock(OldCancelIrql);
/* 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->PacketData[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;
}
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(AdapterContext,
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;
CleanupAndFreePacket(Packet, FALSE);
}
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;
}