[NDISUIO]
[reactos.git] / drivers / network / ndisuio / ioctl.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NDIS User I/O driver
4 * FILE: ioctl.c
5 * PURPOSE: IOCTL handling
6 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
7 */
8
9 #include "ndisuio.h"
10
11 #define NDEBUG
12 #include <debug.h>
13
14 NTSTATUS
15 CancelPacketRead(PIRP Irp, PIO_STACK_LOCATION IrpSp)
16 {
17 PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
18 PNDISUIO_PACKET_ENTRY PacketEntry;
19 NTSTATUS Status;
20
21 /* Indicate a 0-byte packet on the queue so one read returns 0 */
22 PacketEntry = ExAllocatePool(PagedPool, sizeof(NDISUIO_PACKET_ENTRY));
23 if (PacketEntry)
24 {
25 PacketEntry->PacketLength = 0;
26
27 ExInterlockedInsertTailList(&AdapterContext->PacketList,
28 &PacketEntry->ListEntry,
29 &AdapterContext->Spinlock);
30
31 KeSetEvent(&AdapterContext->PacketReadEvent, IO_NO_INCREMENT, FALSE);
32
33 Status = STATUS_SUCCESS;
34 }
35 else
36 {
37 Status = STATUS_NO_MEMORY;
38 }
39
40 Irp->IoStatus.Status = Status;
41 Irp->IoStatus.Information = 0;
42
43 IoCompleteRequest(Irp, IO_NO_INCREMENT);
44
45 return Status;
46 }
47
48 NTSTATUS
49 SetAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp)
50 {
51 PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
52 PNDISUIO_SET_OID SetOidRequest;
53 NDIS_REQUEST NdisRequest;
54 ULONG RequestLength;
55 NDIS_STATUS Status;
56
57 Irp->IoStatus.Information = 0;
58
59 SetOidRequest = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
60 RequestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
61 if (QueryOidRequest && RequestLength >= sizeof(NDIS_OID))
62 {
63 /* Setup the NDIS request */
64 NdisRequest.RequestType = NdisRequestSetInformation;
65 NdisRequest.Oid = SetOidRequest->Oid;
66 NdisRequest.InformationBuffer = SetOidRequest->Data;
67 NdisRequest.InformationBufferLength = RequestLength - sizeof(NDIS_OID);
68
69 /* Dispatch the request */
70 NdisRequest(&Status,
71 AdapterContext->BindingHandle,
72 &NdisRequest);
73
74 /* Wait for the request */
75 if (Status == NDIS_STATUS_PENDING)
76 {
77 KeWaitForSingleObject(&AdapterContext->AsyncEvent,
78 Executive,
79 KernelMode,
80 FALSE,
81 NULL);
82 Status = AdapterContext->AsyncStatus;
83 }
84
85 /* Return the bytes read */
86 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = NdisRequest.BytesRead;
87 }
88 else
89 {
90 /* Bad parameters */
91 Status = STATUS_INVALID_PARAMETER;
92 }
93
94 Irp->IoStatus.Status = Status;
95
96 IoCompleteRequest(Irp, IO_NO_INCREMENT);
97
98 return Status;
99 }
100
101 NTSTATUS
102 QueryAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp)
103 {
104 PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
105 PNDISUIO_QUERY_OID QueryOidRequest;
106 NDIS_REQUEST NdisRequest;
107 ULONG RequestLength;
108 NDIS_STATUS Status;
109
110 Irp->IoStatus.Information = 0;
111
112 QueryOidRequest = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
113 RequestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
114 if (QueryOidRequest && RequestLength >= sizeof(NDIS_OID))
115 {
116 /* Setup the NDIS request */
117 NdisRequest.RequestType = NdisRequestQueryInformation;
118 NdisRequest.Oid = QueryOidRequest->Oid;
119 NdisRequest.InformationBuffer = QueryOidRequest->Data;
120 NdisRequest.InformationBufferLength = RequestLength - sizeof(NDIS_OID);
121
122 /* Dispatch the request */
123 NdisRequest(&Status,
124 AdapterContext->BindingHandle,
125 &NdisRequest);
126
127 /* Wait for the request */
128 if (Status == NDIS_STATUS_PENDING)
129 {
130 KeWaitForSingleObject(&AdapterContext->AsyncEvent,
131 Executive,
132 KernelMode,
133 FALSE,
134 NULL);
135 Status = AdapterContext->AsyncStatus;
136 }
137
138 /* Return the bytes written */
139 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = NdisRequest.BytesWritten;
140 }
141 else
142 {
143 /* Bad parameters */
144 Status = STATUS_INVALID_PARAMETER;
145 }
146
147 Irp->IoStatus.Status = Status;
148
149 IoCompleteRequest(Irp, IO_NO_INCREMENT);
150
151 return Status;
152 }
153
154 NTSTATUS
155 OpenDeviceReadWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp)
156 {
157 PFILE_OBJECT FileObject = IrpSp->FileObject;
158 UNICODE_STRING DeviceName;
159 ULONG NameLength;
160 NTSTATUS Status;
161 PNDISUIO_ADAPTER_CONTEXT AdapterContext;
162 PNDISUIO_OPEN_ENTRY OpenEntry;
163 KIRQL OldIrql;
164
165 NameLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
166 if (NameLength != 0)
167 {
168 DeviceName.MaximumLength = DeviceName.Length = NameLength;
169 DeviceName.Buffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
170
171 /* Check if this already has a context */
172 AdapterContext = FindAdapterContextByName(&DeviceName);
173 if (AdapterContext != NULL)
174 {
175 /* Reference the adapter context */
176 KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql);
177 ReferenceAdapterContext(AdapterContext);
178 Status = STATUS_SUCCESS;
179 }
180 else
181 {
182 /* Invalid device name */
183 Status = STATUS_INVALID_PARAMETER;
184 }
185
186 /* Check that the bind succeeded */
187 if (NT_SUCCESS(Status))
188 {
189 OpenEntry = ExAllocatePool(NonPagedPool, sizeof(*OpenEntry));
190 if (OpenEntry)
191 {
192 /* Set the file object pointer */
193 OpenEntry->FileObject = FileObject;
194
195 /* Associate this FO with the adapter */
196 FileObject->FsContext = AdapterContext;
197 FileObject->FsContext2 = OpenEntry;
198
199 /* Add it to the adapter's list */
200 InsertTailList(&AdapterContext->OpenEntryList,
201 &OpenEntry->ListEntry);
202
203 /* Success */
204 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
205 Status = STATUS_SUCCESS;
206 }
207 else
208 {
209 /* Remove the reference we added */
210 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
211 DereferenceAdapterContext(AdapterContext, NULL);
212 Status = STATUS_NO_MEMORY;
213 }
214 }
215 }
216 else
217 {
218 /* Invalid device name */
219 Status = STATUS_INVALID_PARAMETER;
220 }
221
222 Irp->IoStatus.Status = Status;
223 Irp->IoStatus.Information = 0;
224
225 IoCompleteRequest(Irp, IO_NO_INCREMENT);
226
227 return Status;
228 }
229
230 NTSTATUS
231 OpenDeviceWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp)
232 {
233 /* FIXME: Handle this correctly */
234 return OpenDeviceReadWrite(Irp, IrpSp);
235 }
236
237 NTSTATUS
238 NTAPI
239 NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject,
240 PIRP Irp)
241 {
242 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
243
244 ASSERT(DeviceObject == GlobalDeviceObject);
245
246 /* Handle open IOCTLs first */
247 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
248 {
249 case IOCTL_NDISUIO_OPEN_DEVICE:
250 return OpenDeviceReadWrite(Irp, IrpSp);
251
252 case IOCTL_NDISUIO_OPEN_WRITE_DEVICE:
253 return OpenDeviceWrite(Irp, IrpSp);
254
255 default:
256 /* Fail if this file object has no adapter associated */
257 if (IrpSp->FileObject->FsContext == NULL)
258 {
259 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
260 Irp->IoStatus.Information = 0;
261 IoCompleteRequest(Irp, IO_NO_INCREMENT);
262
263 return STATUS_INVALID_PARAMETER;
264 }
265
266 /* Now handle other IOCTLs */
267 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
268 {
269 case IOCTL_CANCEL_READ:
270 return CancelPacketRead(Irp, IrpSp);
271
272 case IOCTL_NDISUIO_QUERY_OID_VALUE:
273 return QueryAdapterOid(Irp, IrpSp);
274
275 case IOCTL_NDISUIO_SET_OID_VALUE:
276 return SetAdapterOid(Irp, IrpSp);
277
278 default:
279 DPRINT1("Unimplemented\n");
280 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
281 Irp->IoStatus.Information = 0;
282 IoCompleteRequest(Irp, IO_NO_INCREMENT);
283 break;
284 }
285 break;
286 }
287 }