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
;
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
)
55 CurrentEntry
= CurrentEntry
->Flink
;
57 KeReleaseSpinLock(&GlobalAdapterListLock
, OldIrql
);
58 if (i
== QueryBinding
->BindingIndex
)
60 AdapterContext
= CONTAINING_RECORD(CurrentEntry
, NDISUIO_ADAPTER_CONTEXT
, ListEntry
);
61 DPRINT("Query binding for index %d is adapter %wZ\n", i
, &AdapterContext
->DeviceName
);
62 BytesCopied
= sizeof(NDISUIO_QUERY_BINDING
);
63 if (AdapterContext
->DeviceName
.Length
<= BindingLength
- BytesCopied
)
65 BytesCopied
+= AdapterContext
->DeviceName
.Length
;
67 QueryBinding
->DeviceNameOffset
= BytesCopied
;
68 QueryBinding
->DeviceNameLength
= AdapterContext
->DeviceName
.Length
;
69 RtlCopyMemory((PUCHAR
)QueryBinding
+ QueryBinding
->DeviceNameOffset
,
70 AdapterContext
->DeviceName
.Buffer
,
71 QueryBinding
->DeviceNameLength
);
73 /* FIXME: Copy description too */
74 QueryBinding
->DeviceDescrOffset
= BytesCopied
;
75 QueryBinding
->DeviceDescrLength
= 0;
78 Status
= STATUS_SUCCESS
;
82 /* Not enough buffer space */
83 Status
= STATUS_BUFFER_TOO_SMALL
;
89 Status
= STATUS_NO_MORE_ENTRIES
;
94 /* Invalid parameters */
95 Status
= STATUS_INVALID_PARAMETER
;
98 Irp
->IoStatus
.Status
= Status
;
99 Irp
->IoStatus
.Information
= BytesCopied
;
101 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
109 CancelPacketRead(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
111 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
112 PNDISUIO_PACKET_ENTRY PacketEntry
;
115 /* Indicate a 0-byte packet on the queue so one read returns 0 */
116 PacketEntry
= ExAllocatePool(PagedPool
, sizeof(NDISUIO_PACKET_ENTRY
));
119 PacketEntry
->PacketLength
= 0;
121 ExInterlockedInsertHeadList(&AdapterContext
->PacketList
,
122 &PacketEntry
->ListEntry
,
123 &AdapterContext
->Spinlock
);
125 KeSetEvent(&AdapterContext
->PacketReadEvent
, IO_NO_INCREMENT
, FALSE
);
127 Status
= STATUS_SUCCESS
;
131 Status
= STATUS_NO_MEMORY
;
134 Irp
->IoStatus
.Status
= Status
;
135 Irp
->IoStatus
.Information
= 0;
137 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
145 SetAdapterOid(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
147 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
148 PNDISUIO_SET_OID SetOidRequest
;
149 NDIS_REQUEST Request
;
153 Irp
->IoStatus
.Information
= 0;
155 SetOidRequest
= Irp
->AssociatedIrp
.SystemBuffer
;
156 RequestLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
157 if (SetOidRequest
&& RequestLength
>= sizeof(NDIS_OID
))
159 /* Setup the NDIS request */
160 Request
.RequestType
= NdisRequestSetInformation
;
161 Request
.DATA
.SET_INFORMATION
.Oid
= SetOidRequest
->Oid
;
162 Request
.DATA
.SET_INFORMATION
.InformationBuffer
= SetOidRequest
->Data
;
163 Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= RequestLength
- sizeof(NDIS_OID
);
165 DPRINT("Setting OID 0x%x on adapter %wZ\n", SetOidRequest
->Oid
, &AdapterContext
->DeviceName
);
167 /* Dispatch the request */
169 AdapterContext
->BindingHandle
,
172 /* Wait for the request */
173 if (Status
== NDIS_STATUS_PENDING
)
175 KeWaitForSingleObject(&AdapterContext
->AsyncEvent
,
180 Status
= AdapterContext
->AsyncStatus
;
183 /* Return the bytes read */
184 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= Request
.DATA
.SET_INFORMATION
.BytesRead
;
189 Status
= STATUS_INVALID_PARAMETER
;
192 Irp
->IoStatus
.Status
= Status
;
194 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
201 QueryAdapterOid(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
203 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
204 PNDISUIO_QUERY_OID QueryOidRequest
;
205 NDIS_REQUEST Request
;
209 Irp
->IoStatus
.Information
= 0;
211 QueryOidRequest
= Irp
->AssociatedIrp
.SystemBuffer
;
212 RequestLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
213 if (QueryOidRequest
&& RequestLength
>= sizeof(NDIS_OID
))
215 /* Setup the NDIS request */
216 Request
.RequestType
= NdisRequestQueryInformation
;
217 Request
.DATA
.QUERY_INFORMATION
.Oid
= QueryOidRequest
->Oid
;
218 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= QueryOidRequest
->Data
;
219 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= RequestLength
- sizeof(NDIS_OID
);
221 DPRINT("Querying OID 0x%x on adapter %wZ\n", QueryOidRequest
->Oid
, &AdapterContext
->DeviceName
);
223 /* Dispatch the request */
225 AdapterContext
->BindingHandle
,
228 /* Wait for the request */
229 if (Status
== NDIS_STATUS_PENDING
)
231 KeWaitForSingleObject(&AdapterContext
->AsyncEvent
,
236 Status
= AdapterContext
->AsyncStatus
;
239 /* Return the bytes written */
240 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= Request
.DATA
.QUERY_INFORMATION
.BytesWritten
;
245 Status
= STATUS_INVALID_PARAMETER
;
248 Irp
->IoStatus
.Status
= Status
;
250 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
257 OpenDeviceReadWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
259 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
260 UNICODE_STRING DeviceName
;
263 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
264 PNDISUIO_OPEN_ENTRY OpenEntry
;
267 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
270 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
271 DeviceName
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
273 /* Check if this already has a context */
274 AdapterContext
= FindAdapterContextByName(&DeviceName
);
275 if (AdapterContext
!= NULL
)
277 DPRINT("Binding file object 0x%x to device %wZ\n", FileObject
, &AdapterContext
->DeviceName
);
279 /* Reference the adapter context */
280 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
281 if (AdapterContext
->OpenCount
!= 0)
283 /* An open for read-write is exclusive,
284 * so we can't have any other open handles */
285 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
286 Status
= STATUS_INVALID_PARAMETER
;
290 /* Add a reference */
291 ReferenceAdapterContext(AdapterContext
);
292 Status
= STATUS_SUCCESS
;
297 /* Invalid device name */
298 Status
= STATUS_INVALID_PARAMETER
;
301 /* Check that the bind succeeded */
302 if (NT_SUCCESS(Status
))
304 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
307 /* Set the file object pointer */
308 OpenEntry
->FileObject
= FileObject
;
310 /* Set the permissions */
311 OpenEntry
->WriteOnly
= FALSE
;
313 /* Associate this FO with the adapter */
314 FileObject
->FsContext
= AdapterContext
;
315 FileObject
->FsContext2
= OpenEntry
;
317 /* Add it to the adapter's list */
318 InsertTailList(&AdapterContext
->OpenEntryList
,
319 &OpenEntry
->ListEntry
);
322 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
323 Status
= STATUS_SUCCESS
;
327 /* Remove the reference we added */
328 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
329 DereferenceAdapterContextWithOpenEntry(AdapterContext
, NULL
);
330 Status
= STATUS_NO_MEMORY
;
336 /* Invalid device name */
337 Status
= STATUS_INVALID_PARAMETER
;
340 Irp
->IoStatus
.Status
= Status
;
341 Irp
->IoStatus
.Information
= 0;
343 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
351 OpenDeviceWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
353 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
354 UNICODE_STRING DeviceName
;
357 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
358 PNDISUIO_OPEN_ENTRY OpenEntry
;
361 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
364 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
365 DeviceName
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
367 /* Check if this already has a context */
368 AdapterContext
= FindAdapterContextByName(&DeviceName
);
369 if (AdapterContext
!= NULL
)
371 /* Reference the adapter context */
372 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
373 ReferenceAdapterContext(AdapterContext
);
374 Status
= STATUS_SUCCESS
;
378 /* Invalid device name */
379 Status
= STATUS_INVALID_PARAMETER
;
382 /* Check that the bind succeeded */
383 if (NT_SUCCESS(Status
))
385 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
388 /* Set the file object pointer */
389 OpenEntry
->FileObject
= FileObject
;
391 /* Associate this FO with the adapter */
392 FileObject
->FsContext
= AdapterContext
;
393 FileObject
->FsContext2
= OpenEntry
;
395 /* Set permissions */
396 OpenEntry
->WriteOnly
= TRUE
;
398 /* Add it to the adapter's list */
399 InsertTailList(&AdapterContext
->OpenEntryList
,
400 &OpenEntry
->ListEntry
);
403 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
404 Status
= STATUS_SUCCESS
;
408 /* Remove the reference we added */
409 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
410 DereferenceAdapterContext(AdapterContext
, NULL
);
411 Status
= STATUS_NO_MEMORY
;
417 /* Invalid device name */
418 Status
= STATUS_INVALID_PARAMETER
;
421 Irp
->IoStatus
.Status
= Status
;
422 Irp
->IoStatus
.Information
= 0;
424 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
432 NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject
,
435 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
436 PNDISUIO_OPEN_ENTRY OpenEntry
;
438 ASSERT(DeviceObject
== GlobalDeviceObject
);
440 /* Handle open IOCTLs first */
441 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
443 case IOCTL_NDISUIO_OPEN_DEVICE
:
444 return OpenDeviceReadWrite(Irp
, IrpSp
);
446 case IOCTL_NDISUIO_OPEN_WRITE_DEVICE
:
447 return OpenDeviceWrite(Irp
, IrpSp
);
449 case IOCTL_NDISUIO_BIND_WAIT
:
450 return WaitForBind(Irp
, IrpSp
);
452 case IOCTL_NDISUIO_QUERY_BINDING
:
453 return QueryBinding(Irp
, IrpSp
);
456 /* Fail if this file object has no adapter associated */
457 if (IrpSp
->FileObject
->FsContext
== NULL
)
459 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
460 Irp
->IoStatus
.Information
= 0;
461 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
463 return STATUS_INVALID_PARAMETER
;
466 /* Now handle write IOCTLs */
467 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
469 case IOCTL_NDISUIO_SET_OID_VALUE
:
470 return SetAdapterOid(Irp
, IrpSp
);
473 /* Check that we have read permissions */
474 OpenEntry
= IrpSp
->FileObject
->FsContext2
;
475 if (OpenEntry
->WriteOnly
)
477 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
478 Irp
->IoStatus
.Information
= 0;
479 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
481 return STATUS_INVALID_PARAMETER
;
484 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
487 case IOCTL_CANCEL_READ
:
488 return CancelPacketRead(Irp
, IrpSp
);
491 case IOCTL_NDISUIO_QUERY_OID_VALUE
:
492 return QueryAdapterOid(Irp
, IrpSp
);
495 DPRINT1("Unimplemented\n");
496 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
497 Irp
->IoStatus
.Information
= 0;
498 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
499 return STATUS_NOT_IMPLEMENTED
;