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 (Status
== NDIS_STATUS_INVALID_LENGTH
||
194 Status
== NDIS_STATUS_BUFFER_TOO_SHORT
)
196 Status
= STATUS_BUFFER_TOO_SMALL
;
198 else if (Status
== NDIS_STATUS_SUCCESS
)
200 Irp
->IoStatus
.Information
= sizeof(NDIS_OID
) + Request
.DATA
.SET_INFORMATION
.BytesRead
;
203 DPRINT("Final request status: 0x%x (%d)\n", Status
, Irp
->IoStatus
.Information
);
208 Status
= STATUS_INVALID_PARAMETER
;
211 Irp
->IoStatus
.Status
= Status
;
213 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
220 QueryAdapterOid(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
222 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
223 PNDISUIO_QUERY_OID QueryOidRequest
;
224 NDIS_REQUEST Request
;
228 Irp
->IoStatus
.Information
= 0;
230 QueryOidRequest
= Irp
->AssociatedIrp
.SystemBuffer
;
231 RequestLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
232 if (QueryOidRequest
&& RequestLength
>= sizeof(NDIS_OID
))
234 /* Setup the NDIS request */
235 Request
.RequestType
= NdisRequestQueryInformation
;
236 Request
.DATA
.QUERY_INFORMATION
.Oid
= QueryOidRequest
->Oid
;
237 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= RequestLength
- sizeof(NDIS_OID
);
238 if (Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
!= 0)
240 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= QueryOidRequest
->Data
;
244 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= NULL
;
246 Request
.DATA
.QUERY_INFORMATION
.BytesWritten
= 0;
248 DPRINT("Querying OID 0x%x on adapter %wZ\n", QueryOidRequest
->Oid
, &AdapterContext
->DeviceName
);
250 /* Dispatch the request */
252 AdapterContext
->BindingHandle
,
255 /* Wait for the request */
256 if (Status
== NDIS_STATUS_PENDING
)
258 KeWaitForSingleObject(&AdapterContext
->AsyncEvent
,
263 Status
= AdapterContext
->AsyncStatus
;
266 /* Return the bytes written */
267 if (Status
== NDIS_STATUS_INVALID_LENGTH
||
268 Status
== NDIS_STATUS_BUFFER_TOO_SHORT
)
270 Status
= STATUS_BUFFER_TOO_SMALL
;
272 else if (Status
== NDIS_STATUS_SUCCESS
)
274 Irp
->IoStatus
.Information
= sizeof(NDIS_OID
) + Request
.DATA
.QUERY_INFORMATION
.BytesWritten
;
277 DPRINT("Final request status: 0x%x (%d)\n", Status
, Irp
->IoStatus
.Information
);
282 Status
= STATUS_INVALID_PARAMETER
;
285 Irp
->IoStatus
.Status
= Status
;
287 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
294 OpenDeviceReadWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
296 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
297 UNICODE_STRING DeviceName
;
300 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
301 PNDISUIO_OPEN_ENTRY OpenEntry
;
304 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
307 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
308 DeviceName
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
310 /* Check if this already has a context */
311 AdapterContext
= FindAdapterContextByName(&DeviceName
);
312 if (AdapterContext
!= NULL
)
314 DPRINT("Binding file object 0x%x to device %wZ\n", FileObject
, &AdapterContext
->DeviceName
);
316 /* Reference the adapter context */
317 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
318 if (AdapterContext
->OpenCount
!= 0)
320 /* An open for read-write is exclusive,
321 * so we can't have any other open handles */
322 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
323 Status
= STATUS_INVALID_PARAMETER
;
327 /* Add a reference */
328 ReferenceAdapterContext(AdapterContext
);
329 Status
= STATUS_SUCCESS
;
334 /* Invalid device name */
335 Status
= STATUS_INVALID_PARAMETER
;
338 /* Check that the bind succeeded */
339 if (NT_SUCCESS(Status
))
341 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
344 /* Set the file object pointer */
345 OpenEntry
->FileObject
= FileObject
;
347 /* Set the permissions */
348 OpenEntry
->WriteOnly
= FALSE
;
350 /* Associate this FO with the adapter */
351 FileObject
->FsContext
= AdapterContext
;
352 FileObject
->FsContext2
= OpenEntry
;
354 /* Add it to the adapter's list */
355 InsertTailList(&AdapterContext
->OpenEntryList
,
356 &OpenEntry
->ListEntry
);
359 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
360 Status
= STATUS_SUCCESS
;
364 /* Remove the reference we added */
365 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
366 DereferenceAdapterContextWithOpenEntry(AdapterContext
, NULL
);
367 Status
= STATUS_NO_MEMORY
;
373 /* Invalid device name */
374 Status
= STATUS_INVALID_PARAMETER
;
377 Irp
->IoStatus
.Status
= Status
;
378 Irp
->IoStatus
.Information
= 0;
380 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
388 OpenDeviceWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
390 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
391 UNICODE_STRING DeviceName
;
394 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
395 PNDISUIO_OPEN_ENTRY OpenEntry
;
398 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
401 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
402 DeviceName
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
404 /* Check if this already has a context */
405 AdapterContext
= FindAdapterContextByName(&DeviceName
);
406 if (AdapterContext
!= NULL
)
408 /* Reference the adapter context */
409 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
410 ReferenceAdapterContext(AdapterContext
);
411 Status
= STATUS_SUCCESS
;
415 /* Invalid device name */
416 Status
= STATUS_INVALID_PARAMETER
;
419 /* Check that the bind succeeded */
420 if (NT_SUCCESS(Status
))
422 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
425 /* Set the file object pointer */
426 OpenEntry
->FileObject
= FileObject
;
428 /* Associate this FO with the adapter */
429 FileObject
->FsContext
= AdapterContext
;
430 FileObject
->FsContext2
= OpenEntry
;
432 /* Set permissions */
433 OpenEntry
->WriteOnly
= TRUE
;
435 /* Add it to the adapter's list */
436 InsertTailList(&AdapterContext
->OpenEntryList
,
437 &OpenEntry
->ListEntry
);
440 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
441 Status
= STATUS_SUCCESS
;
445 /* Remove the reference we added */
446 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
447 DereferenceAdapterContext(AdapterContext
, NULL
);
448 Status
= STATUS_NO_MEMORY
;
454 /* Invalid device name */
455 Status
= STATUS_INVALID_PARAMETER
;
458 Irp
->IoStatus
.Status
= Status
;
459 Irp
->IoStatus
.Information
= 0;
461 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
469 NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject
,
472 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
473 PNDISUIO_OPEN_ENTRY OpenEntry
;
475 ASSERT(DeviceObject
== GlobalDeviceObject
);
477 /* Handle open IOCTLs first */
478 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
480 case IOCTL_NDISUIO_OPEN_DEVICE
:
481 return OpenDeviceReadWrite(Irp
, IrpSp
);
483 case IOCTL_NDISUIO_OPEN_WRITE_DEVICE
:
484 return OpenDeviceWrite(Irp
, IrpSp
);
486 case IOCTL_NDISUIO_BIND_WAIT
:
487 return WaitForBind(Irp
, IrpSp
);
489 case IOCTL_NDISUIO_QUERY_BINDING
:
490 return QueryBinding(Irp
, IrpSp
);
493 /* Fail if this file object has no adapter associated */
494 if (IrpSp
->FileObject
->FsContext
== NULL
)
496 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
497 Irp
->IoStatus
.Information
= 0;
498 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
500 return STATUS_INVALID_PARAMETER
;
503 /* Now handle write IOCTLs */
504 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
506 case IOCTL_NDISUIO_SET_OID_VALUE
:
507 return SetAdapterOid(Irp
, IrpSp
);
510 /* Check that we have read permissions */
511 OpenEntry
= IrpSp
->FileObject
->FsContext2
;
512 if (OpenEntry
->WriteOnly
)
514 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
515 Irp
->IoStatus
.Information
= 0;
516 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
518 return STATUS_INVALID_PARAMETER
;
521 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
524 case IOCTL_CANCEL_READ
:
525 return CancelPacketRead(Irp
, IrpSp
);
528 case IOCTL_NDISUIO_QUERY_OID_VALUE
:
529 return QueryAdapterOid(Irp
, IrpSp
);
532 DPRINT1("Unimplemented\n");
533 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
534 Irp
->IoStatus
.Information
= 0;
535 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
536 return STATUS_NOT_IMPLEMENTED
;