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