[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 if (AdapterContext->OpenCount != 0)
178 {
179 /* An open for read-write is exclusive,
180 * so we can't have any other open handles */
181 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
182 Status = STATUS_INVALID_PARAMETER;
183 }
184 else
185 {
186 /* Add a reference */
187 ReferenceAdapterContext(AdapterContext);
188 Status = STATUS_SUCCESS;
189 }
190 }
191 else
192 {
193 /* Invalid device name */
194 Status = STATUS_INVALID_PARAMETER;
195 }
196
197 /* Check that the bind succeeded */
198 if (NT_SUCCESS(Status))
199 {
200 OpenEntry = ExAllocatePool(NonPagedPool, sizeof(*OpenEntry));
201 if (OpenEntry)
202 {
203 /* Set the file object pointer */
204 OpenEntry->FileObject = FileObject;
205
206 /* Set the permissions */
207 OpenEntry->WriteOnly = FALSE;
208
209 /* Associate this FO with the adapter */
210 FileObject->FsContext = AdapterContext;
211 FileObject->FsContext2 = OpenEntry;
212
213 /* Add it to the adapter's list */
214 InsertTailList(&AdapterContext->OpenEntryList,
215 &OpenEntry->ListEntry);
216
217 /* Success */
218 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
219 Status = STATUS_SUCCESS;
220 }
221 else
222 {
223 /* Remove the reference we added */
224 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
225 DereferenceAdapterContext(AdapterContext, NULL);
226 Status = STATUS_NO_MEMORY;
227 }
228 }
229 }
230 else
231 {
232 /* Invalid device name */
233 Status = STATUS_INVALID_PARAMETER;
234 }
235
236 Irp->IoStatus.Status = Status;
237 Irp->IoStatus.Information = 0;
238
239 IoCompleteRequest(Irp, IO_NO_INCREMENT);
240
241 return Status;
242 }
243
244 NTSTATUS
245 OpenDeviceWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp)
246 {
247 PFILE_OBJECT FileObject = IrpSp->FileObject;
248 UNICODE_STRING DeviceName;
249 ULONG NameLength;
250 NTSTATUS Status;
251 PNDISUIO_ADAPTER_CONTEXT AdapterContext;
252 PNDISUIO_OPEN_ENTRY OpenEntry;
253 KIRQL OldIrql;
254
255 NameLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
256 if (NameLength != 0)
257 {
258 DeviceName.MaximumLength = DeviceName.Length = NameLength;
259 DeviceName.Buffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
260
261 /* Check if this already has a context */
262 AdapterContext = FindAdapterContextByName(&DeviceName);
263 if (AdapterContext != NULL)
264 {
265 /* Reference the adapter context */
266 KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql);
267 ReferenceAdapterContext(AdapterContext);
268 Status = STATUS_SUCCESS;
269 }
270 else
271 {
272 /* Invalid device name */
273 Status = STATUS_INVALID_PARAMETER;
274 }
275
276 /* Check that the bind succeeded */
277 if (NT_SUCCESS(Status))
278 {
279 OpenEntry = ExAllocatePool(NonPagedPool, sizeof(*OpenEntry));
280 if (OpenEntry)
281 {
282 /* Set the file object pointer */
283 OpenEntry->FileObject = FileObject;
284
285 /* Associate this FO with the adapter */
286 FileObject->FsContext = AdapterContext;
287 FileObject->FsContext2 = OpenEntry;
288
289 /* Set permissions */
290 OpenEntry->WriteOnly = TRUE;
291
292 /* Add it to the adapter's list */
293 InsertTailList(&AdapterContext->OpenEntryList,
294 &OpenEntry->ListEntry);
295
296 /* Success */
297 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
298 Status = STATUS_SUCCESS;
299 }
300 else
301 {
302 /* Remove the reference we added */
303 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
304 DereferenceAdapterContext(AdapterContext, NULL);
305 Status = STATUS_NO_MEMORY;
306 }
307 }
308 }
309 else
310 {
311 /* Invalid device name */
312 Status = STATUS_INVALID_PARAMETER;
313 }
314
315 Irp->IoStatus.Status = Status;
316 Irp->IoStatus.Information = 0;
317
318 IoCompleteRequest(Irp, IO_NO_INCREMENT);
319
320 return Status;
321 }
322
323 NTSTATUS
324 NTAPI
325 NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject,
326 PIRP Irp)
327 {
328 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
329 PNDISUIO_OPEN_ENTRY OpenEntry;
330
331 ASSERT(DeviceObject == GlobalDeviceObject);
332
333 /* Handle open IOCTLs first */
334 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
335 {
336 case IOCTL_NDISUIO_OPEN_DEVICE:
337 return OpenDeviceReadWrite(Irp, IrpSp);
338
339 case IOCTL_NDISUIO_OPEN_WRITE_DEVICE:
340 return OpenDeviceWrite(Irp, IrpSp);
341
342 default:
343 /* Fail if this file object has no adapter associated */
344 if (IrpSp->FileObject->FsContext == NULL)
345 {
346 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
347 Irp->IoStatus.Information = 0;
348 IoCompleteRequest(Irp, IO_NO_INCREMENT);
349
350 return STATUS_INVALID_PARAMETER;
351 }
352
353 /* Now handle write IOCTLs */
354 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
355 {
356 case IOCTL_NDISUIO_SET_OID_VALUE:
357 return SetAdapterOid(Irp, IrpSp);
358
359 default:
360 /* Check that we have read permissions */
361 OpenEntry = IrpSp->FileObject->FsContext2;
362 if (OpenEntry->WriteOnly)
363 {
364 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
365 Irp->IoStatus.Information = 0;
366 IoCompleteRequest(Irp, IO_NO_INCREMENT);
367
368 return STATUS_INVALID_PARAMETER;
369 }
370
371 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
372 {
373 case IOCTL_CANCEL_READ:
374 return CancelPacketRead(Irp, IrpSp);
375
376 case IOCTL_NDISUIO_QUERY_OID_VALUE:
377 return QueryAdapterOid(Irp, IrpSp);
378
379 default:
380 DPRINT1("Unimplemented\n");
381 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
382 Irp->IoStatus.Information = 0;
383 IoCompleteRequest(Irp, IO_NO_INCREMENT);
384 break;
385 }
386 }
387 break;
388 }
389 }