xref: /reactos/drivers/network/ndisuio/readwrite.c (revision 53221834)
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