2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NDIS User I/O driver
5 * PURPOSE: IOCTL handling
6 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
16 WaitForBind(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
18 /* I've seen several code samples that use this IOCTL but there's
19 * no official documentation on it. I'm just implementing it as a no-op
20 * right now because I don't see any reason we need it. We handle an open
21 * and bind just fine with IRP_MJ_CREATE and IOCTL_NDISUIO_OPEN_DEVICE */
22 DPRINT("Wait for bind complete\n");
24 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
25 Irp
->IoStatus
.Information
= 0;
27 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
29 return STATUS_SUCCESS
;
34 QueryBinding(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
36 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= NULL
;
37 PNDISUIO_QUERY_BINDING QueryBinding
= Irp
->AssociatedIrp
.SystemBuffer
;
38 ULONG BindingLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
40 PLIST_ENTRY CurrentEntry
;
43 ULONG BytesCopied
= 0;
45 if (QueryBinding
&& BindingLength
>= sizeof(NDISUIO_QUERY_BINDING
))
47 KeAcquireSpinLock(&GlobalAdapterListLock
, &OldIrql
);
49 CurrentEntry
= GlobalAdapterList
.Flink
;
50 while (CurrentEntry
!= &GlobalAdapterList
)
52 if (i
== QueryBinding
->BindingIndex
)
54 AdapterContext
= CONTAINING_RECORD(CurrentEntry
, NDISUIO_ADAPTER_CONTEXT
, ListEntry
);
58 CurrentEntry
= CurrentEntry
->Flink
;
60 KeReleaseSpinLock(&GlobalAdapterListLock
, OldIrql
);
63 DPRINT("Query binding for index %d is adapter %wZ\n", i
, &AdapterContext
->DeviceName
);
64 BytesCopied
= sizeof(NDISUIO_QUERY_BINDING
);
65 if (AdapterContext
->DeviceName
.Length
<= BindingLength
- BytesCopied
)
67 QueryBinding
->DeviceNameOffset
= BytesCopied
;
68 QueryBinding
->DeviceNameLength
= AdapterContext
->DeviceName
.Length
;
69 RtlCopyMemory((PUCHAR
)QueryBinding
+ QueryBinding
->DeviceNameOffset
,
70 AdapterContext
->DeviceName
.Buffer
,
71 QueryBinding
->DeviceNameLength
);
72 BytesCopied
+= AdapterContext
->DeviceName
.Length
;
74 /* FIXME: Copy description too */
75 QueryBinding
->DeviceDescrOffset
= BytesCopied
;
76 QueryBinding
->DeviceDescrLength
= 0;
79 Status
= STATUS_SUCCESS
;
83 /* Not enough buffer space */
84 Status
= STATUS_BUFFER_TOO_SMALL
;
90 Status
= STATUS_NO_MORE_ENTRIES
;
95 /* Invalid parameters */
96 Status
= STATUS_INVALID_PARAMETER
;
99 Irp
->IoStatus
.Status
= Status
;
100 Irp
->IoStatus
.Information
= BytesCopied
;
102 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
110 CancelPacketRead(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
112 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
113 PNDISUIO_PACKET_ENTRY PacketEntry
;
116 /* Indicate a 0-byte packet on the queue so one read returns 0 */
117 PacketEntry
= ExAllocatePool(PagedPool
, sizeof(NDISUIO_PACKET_ENTRY
));
120 PacketEntry
->PacketLength
= 0;
122 ExInterlockedInsertHeadList(&AdapterContext
->PacketList
,
123 &PacketEntry
->ListEntry
,
124 &AdapterContext
->Spinlock
);
126 KeSetEvent(&AdapterContext
->PacketReadEvent
, IO_NO_INCREMENT
, FALSE
);
128 Status
= STATUS_SUCCESS
;
132 Status
= STATUS_NO_MEMORY
;
135 Irp
->IoStatus
.Status
= Status
;
136 Irp
->IoStatus
.Information
= 0;
138 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
146 SetAdapterOid(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
148 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
149 PNDISUIO_SET_OID SetOidRequest
;
150 NDIS_REQUEST Request
;
154 Irp
->IoStatus
.Information
= 0;
156 SetOidRequest
= Irp
->AssociatedIrp
.SystemBuffer
;
157 RequestLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
158 if (SetOidRequest
&& RequestLength
>= sizeof(NDIS_OID
))
160 /* Setup the NDIS request */
161 Request
.RequestType
= NdisRequestSetInformation
;
162 Request
.DATA
.SET_INFORMATION
.Oid
= SetOidRequest
->Oid
;
163 Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= RequestLength
- sizeof(NDIS_OID
);
164 if (Request
.DATA
.SET_INFORMATION
.InformationBufferLength
!= 0)
166 Request
.DATA
.SET_INFORMATION
.InformationBuffer
= SetOidRequest
->Data
;
170 Request
.DATA
.SET_INFORMATION
.InformationBuffer
= NULL
;
172 Request
.DATA
.SET_INFORMATION
.BytesRead
= 0;
174 DPRINT("Setting OID 0x%x on adapter %wZ\n", SetOidRequest
->Oid
, &AdapterContext
->DeviceName
);
176 /* Dispatch the request */
178 AdapterContext
->BindingHandle
,
181 /* Wait for the request */
182 if (Status
== NDIS_STATUS_PENDING
)
184 KeWaitForSingleObject(&AdapterContext
->AsyncEvent
,
189 Status
= AdapterContext
->AsyncStatus
;
192 /* Return the bytes read */
193 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= sizeof(NDIS_OID
) + Request
.DATA
.SET_INFORMATION
.BytesRead
;
195 DPRINT("Final request status: 0x%x (%d)\n", Status
, Irp
->IoStatus
.Information
);
200 Status
= STATUS_INVALID_PARAMETER
;
203 Irp
->IoStatus
.Status
= Status
;
205 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
212 QueryAdapterOid(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
214 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
215 PNDISUIO_QUERY_OID QueryOidRequest
;
216 NDIS_REQUEST Request
;
220 Irp
->IoStatus
.Information
= 0;
222 QueryOidRequest
= Irp
->AssociatedIrp
.SystemBuffer
;
223 RequestLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
224 if (QueryOidRequest
&& RequestLength
>= sizeof(NDIS_OID
))
226 /* Setup the NDIS request */
227 Request
.RequestType
= NdisRequestQueryInformation
;
228 Request
.DATA
.QUERY_INFORMATION
.Oid
= QueryOidRequest
->Oid
;
229 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= RequestLength
- sizeof(NDIS_OID
);
230 if (Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
!= 0)
232 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= QueryOidRequest
->Data
;
236 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= NULL
;
238 Request
.DATA
.QUERY_INFORMATION
.BytesWritten
= 0;
240 DPRINT("Querying OID 0x%x on adapter %wZ\n", QueryOidRequest
->Oid
, &AdapterContext
->DeviceName
);
242 /* Dispatch the request */
244 AdapterContext
->BindingHandle
,
247 /* Wait for the request */
248 if (Status
== NDIS_STATUS_PENDING
)
250 KeWaitForSingleObject(&AdapterContext
->AsyncEvent
,
255 Status
= AdapterContext
->AsyncStatus
;
258 /* Return the bytes written */
259 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= sizeof(NDIS_OID
) + Request
.DATA
.QUERY_INFORMATION
.BytesWritten
;
261 DPRINT("Final request status: 0x%x (%d)\n", Status
, Irp
->IoStatus
.Information
);
266 Status
= STATUS_INVALID_PARAMETER
;
269 Irp
->IoStatus
.Status
= Status
;
271 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
278 OpenDeviceReadWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
280 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
281 UNICODE_STRING DeviceName
;
284 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
285 PNDISUIO_OPEN_ENTRY OpenEntry
;
288 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
291 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
292 DeviceName
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
294 /* Check if this already has a context */
295 AdapterContext
= FindAdapterContextByName(&DeviceName
);
296 if (AdapterContext
!= NULL
)
298 DPRINT("Binding file object 0x%x to device %wZ\n", FileObject
, &AdapterContext
->DeviceName
);
300 /* Reference the adapter context */
301 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
302 if (AdapterContext
->OpenCount
!= 0)
304 /* An open for read-write is exclusive,
305 * so we can't have any other open handles */
306 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
307 Status
= STATUS_INVALID_PARAMETER
;
311 /* Add a reference */
312 ReferenceAdapterContext(AdapterContext
);
313 Status
= STATUS_SUCCESS
;
318 /* Invalid device name */
319 Status
= STATUS_INVALID_PARAMETER
;
322 /* Check that the bind succeeded */
323 if (NT_SUCCESS(Status
))
325 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
328 /* Set the file object pointer */
329 OpenEntry
->FileObject
= FileObject
;
331 /* Set the permissions */
332 OpenEntry
->WriteOnly
= FALSE
;
334 /* Associate this FO with the adapter */
335 FileObject
->FsContext
= AdapterContext
;
336 FileObject
->FsContext2
= OpenEntry
;
338 /* Add it to the adapter's list */
339 InsertTailList(&AdapterContext
->OpenEntryList
,
340 &OpenEntry
->ListEntry
);
343 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
344 Status
= STATUS_SUCCESS
;
348 /* Remove the reference we added */
349 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
350 DereferenceAdapterContextWithOpenEntry(AdapterContext
, NULL
);
351 Status
= STATUS_NO_MEMORY
;
357 /* Invalid device name */
358 Status
= STATUS_INVALID_PARAMETER
;
361 Irp
->IoStatus
.Status
= Status
;
362 Irp
->IoStatus
.Information
= 0;
364 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
372 OpenDeviceWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
374 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
375 UNICODE_STRING DeviceName
;
378 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
379 PNDISUIO_OPEN_ENTRY OpenEntry
;
382 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
385 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
386 DeviceName
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
388 /* Check if this already has a context */
389 AdapterContext
= FindAdapterContextByName(&DeviceName
);
390 if (AdapterContext
!= NULL
)
392 /* Reference the adapter context */
393 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
394 ReferenceAdapterContext(AdapterContext
);
395 Status
= STATUS_SUCCESS
;
399 /* Invalid device name */
400 Status
= STATUS_INVALID_PARAMETER
;
403 /* Check that the bind succeeded */
404 if (NT_SUCCESS(Status
))
406 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
409 /* Set the file object pointer */
410 OpenEntry
->FileObject
= FileObject
;
412 /* Associate this FO with the adapter */
413 FileObject
->FsContext
= AdapterContext
;
414 FileObject
->FsContext2
= OpenEntry
;
416 /* Set permissions */
417 OpenEntry
->WriteOnly
= TRUE
;
419 /* Add it to the adapter's list */
420 InsertTailList(&AdapterContext
->OpenEntryList
,
421 &OpenEntry
->ListEntry
);
424 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
425 Status
= STATUS_SUCCESS
;
429 /* Remove the reference we added */
430 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
431 DereferenceAdapterContext(AdapterContext
, NULL
);
432 Status
= STATUS_NO_MEMORY
;
438 /* Invalid device name */
439 Status
= STATUS_INVALID_PARAMETER
;
442 Irp
->IoStatus
.Status
= Status
;
443 Irp
->IoStatus
.Information
= 0;
445 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
453 NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject
,
456 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
457 PNDISUIO_OPEN_ENTRY OpenEntry
;
459 ASSERT(DeviceObject
== GlobalDeviceObject
);
461 /* Handle open IOCTLs first */
462 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
464 case IOCTL_NDISUIO_OPEN_DEVICE
:
465 return OpenDeviceReadWrite(Irp
, IrpSp
);
467 case IOCTL_NDISUIO_OPEN_WRITE_DEVICE
:
468 return OpenDeviceWrite(Irp
, IrpSp
);
470 case IOCTL_NDISUIO_BIND_WAIT
:
471 return WaitForBind(Irp
, IrpSp
);
473 case IOCTL_NDISUIO_QUERY_BINDING
:
474 return QueryBinding(Irp
, IrpSp
);
477 /* Fail if this file object has no adapter associated */
478 if (IrpSp
->FileObject
->FsContext
== NULL
)
480 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
481 Irp
->IoStatus
.Information
= 0;
482 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
484 return STATUS_INVALID_PARAMETER
;
487 /* Now handle write IOCTLs */
488 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
490 case IOCTL_NDISUIO_SET_OID_VALUE
:
491 return SetAdapterOid(Irp
, IrpSp
);
494 /* Check that we have read permissions */
495 OpenEntry
= IrpSp
->FileObject
->FsContext2
;
496 if (OpenEntry
->WriteOnly
)
498 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
499 Irp
->IoStatus
.Information
= 0;
500 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
502 return STATUS_INVALID_PARAMETER
;
505 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
508 case IOCTL_CANCEL_READ
:
509 return CancelPacketRead(Irp
, IrpSp
);
512 case IOCTL_NDISUIO_QUERY_OID_VALUE
:
513 return QueryAdapterOid(Irp
, IrpSp
);
516 DPRINT1("Unimplemented\n");
517 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
518 Irp
->IoStatus
.Information
= 0;
519 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
520 return STATUS_NOT_IMPLEMENTED
;