[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 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(Irp->AssociatedIrp.SystemBuffer,
171 IrpSp->Parameters.Write.Length);
172 if (Packet)
173 {
174 /* Send it via NDIS */
175 NdisSend(&Status,
176 AdapterContext->BindingHandle,
177 Packet);
178
179 /* Wait for the send */
180 if (Status == NDIS_STATUS_PENDING)
181 {
182 KeWaitForSingleObject(&AdapterContext->AsyncEvent,
183 Executive,
184 KernelMode,
185 FALSE,
186 NULL);
187 Status = AdapterContext->AsyncStatus;
188 }
189
190 /* Check if it succeeded */
191 if (Status == NDIS_STATUS_SUCCESS)
192 BytesCopied = IrpSp->Parameters.Write.Length;
193
194 CleanupAndFreePacket(Packet, TRUE);
195 }
196 else
197 {
198 /* No memory */
199 Status = STATUS_NO_MEMORY;
200 }
201
202 /* Complete the IRP */
203 Irp->IoStatus.Status = Status;
204 Irp->IoStatus.Information = BytesCopied;
205 IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
206
207 return Status;
208 }