1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS NDIS User I/O driver 4 * FILE: readwrite.c 5 * PURPOSE: Handles IRP_MJ_READ and IRP_MJ_WRITE 6 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org) 7 */ 8 9 #include "ndisuio.h" 10 11 #define NDEBUG 12 #include <debug.h> 13 14 static 15 VOID 16 NTAPI 17 ReadIrpCancel(PDEVICE_OBJECT DeviceObject, PIRP Irp) 18 { 19 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 20 PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext; 21 PNDISUIO_PACKET_ENTRY PacketEntry; 22 23 /* Release the cancel spin lock */ 24 IoReleaseCancelSpinLock(Irp->CancelIrql); 25 26 /* Indicate a 0-byte packet on the queue to cancel the read */ 27 PacketEntry = ExAllocatePool(NonPagedPool, sizeof(NDISUIO_PACKET_ENTRY)); 28 if (PacketEntry) 29 { 30 PacketEntry->PacketLength = 0; 31 32 ExInterlockedInsertHeadList(&AdapterContext->PacketList, 33 &PacketEntry->ListEntry, 34 &AdapterContext->Spinlock); 35 36 KeSetEvent(&AdapterContext->PacketReadEvent, IO_NO_INCREMENT, FALSE); 37 } 38 } 39 40 NTSTATUS 41 NTAPI 42 NduDispatchRead(PDEVICE_OBJECT DeviceObject, 43 PIRP Irp) 44 { 45 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 46 PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext; 47 PNDISUIO_OPEN_ENTRY OpenEntry = IrpSp->FileObject->FsContext2; 48 KIRQL OldIrql, OldCancelIrql; 49 NTSTATUS Status; 50 PLIST_ENTRY ListEntry; 51 PNDISUIO_PACKET_ENTRY PacketEntry = NULL; 52 ULONG BytesCopied = 0; 53 54 ASSERT(DeviceObject == GlobalDeviceObject); 55 56 if (OpenEntry->WriteOnly) 57 { 58 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 59 Irp->IoStatus.Information = 0; 60 IoCompleteRequest(Irp, IO_NO_INCREMENT); 61 62 return STATUS_INVALID_PARAMETER; 63 } 64 65 /* Make the read cancellable */ 66 IoAcquireCancelSpinLock(&OldCancelIrql); 67 IoSetCancelRoutine(Irp, ReadIrpCancel); 68 if (Irp->Cancel) 69 { 70 IoReleaseCancelSpinLock(OldCancelIrql); 71 72 /* Indicate a 0 byte read */ 73 Irp->IoStatus.Status = STATUS_SUCCESS; 74 Irp->IoStatus.Information = 0; 75 IoCompleteRequest(Irp, IO_NO_INCREMENT); 76 77 return STATUS_SUCCESS; 78 } 79 IoReleaseCancelSpinLock(OldCancelIrql); 80 81 while (TRUE) 82 { 83 KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql); 84 85 /* Check if we have a packet */ 86 if (IsListEmpty(&AdapterContext->PacketList)) 87 { 88 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); 89 90 /* Wait for a packet (in the context of the calling user thread) */ 91 Status = KeWaitForSingleObject(&AdapterContext->PacketReadEvent, 92 UserRequest, 93 UserMode, 94 TRUE, 95 NULL); 96 if (Status != STATUS_SUCCESS) 97 { 98 /* Remove the cancel routine */ 99 IoAcquireCancelSpinLock(&OldCancelIrql); 100 IoSetCancelRoutine(Irp, NULL); 101 IoReleaseCancelSpinLock(OldCancelIrql); 102 103 break; 104 } 105 } 106 else 107 { 108 /* Remove the cancel routine */ 109 IoAcquireCancelSpinLock(&OldCancelIrql); 110 IoSetCancelRoutine(Irp, NULL); 111 IoReleaseCancelSpinLock(OldCancelIrql); 112 113 /* Remove the first packet in the list */ 114 ListEntry = RemoveHeadList(&AdapterContext->PacketList); 115 PacketEntry = CONTAINING_RECORD(ListEntry, NDISUIO_PACKET_ENTRY, ListEntry); 116 117 /* Release the adapter lock */ 118 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); 119 120 /* And we're done with this loop */ 121 Status = STATUS_SUCCESS; 122 break; 123 } 124 } 125 126 /* Check if we got a packet */ 127 if (PacketEntry != NULL) 128 { 129 /* Find the right amount of bytes to copy */ 130 BytesCopied = PacketEntry->PacketLength; 131 if (BytesCopied > IrpSp->Parameters.Read.Length) 132 BytesCopied = IrpSp->Parameters.Read.Length; 133 134 /* Copy the packet */ 135 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, 136 &PacketEntry->PacketData[0], 137 BytesCopied); 138 139 /* Free the packet entry */ 140 ExFreePool(PacketEntry); 141 } 142 else 143 { 144 /* Something failed */ 145 BytesCopied = 0; 146 } 147 148 /* Complete the IRP */ 149 Irp->IoStatus.Status = Status; 150 Irp->IoStatus.Information = BytesCopied; 151 IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); 152 153 return Status; 154 } 155 156 NTSTATUS 157 NTAPI 158 NduDispatchWrite(PDEVICE_OBJECT DeviceObject, 159 PIRP Irp) 160 { 161 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 162 PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext; 163 PNDIS_PACKET Packet; 164 NDIS_STATUS Status; 165 ULONG BytesCopied = 0; 166 167 ASSERT(DeviceObject == GlobalDeviceObject); 168 169 /* Create a packet and buffer descriptor for this user buffer */ 170 Packet = CreatePacketFromPoolBuffer(AdapterContext, 171 Irp->AssociatedIrp.SystemBuffer, 172 IrpSp->Parameters.Write.Length); 173 if (Packet) 174 { 175 /* Send it via NDIS */ 176 NdisSend(&Status, 177 AdapterContext->BindingHandle, 178 Packet); 179 180 /* Wait for the send */ 181 if (Status == NDIS_STATUS_PENDING) 182 { 183 KeWaitForSingleObject(&AdapterContext->AsyncEvent, 184 Executive, 185 KernelMode, 186 FALSE, 187 NULL); 188 Status = AdapterContext->AsyncStatus; 189 } 190 191 /* Check if it succeeded */ 192 if (Status == NDIS_STATUS_SUCCESS) 193 BytesCopied = IrpSp->Parameters.Write.Length; 194 195 CleanupAndFreePacket(Packet, FALSE); 196 } 197 else 198 { 199 /* No memory */ 200 Status = STATUS_NO_MEMORY; 201 } 202 203 /* Complete the IRP */ 204 Irp->IoStatus.Status = Status; 205 Irp->IoStatus.Information = BytesCopied; 206 IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); 207 208 return Status; 209 } 210