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 QueryBinding
->DeviceNameOffset
= BytesCopied
;
66 QueryBinding
->DeviceNameLength
= AdapterContext
->DeviceName
.Length
;
67 RtlCopyMemory((PUCHAR
)QueryBinding
+ QueryBinding
->DeviceNameOffset
,
68 AdapterContext
->DeviceName
.Buffer
,
69 QueryBinding
->DeviceNameLength
);
70 BytesCopied
+= AdapterContext
->DeviceName
.Length
;
72 /* FIXME: Copy description too */
73 QueryBinding
->DeviceDescrOffset
= BytesCopied
;
74 QueryBinding
->DeviceDescrLength
= 0;
77 Status
= STATUS_SUCCESS
;
81 /* Not enough buffer space */
82 Status
= STATUS_BUFFER_TOO_SMALL
;
88 Status
= STATUS_NO_MORE_ENTRIES
;
93 /* Invalid parameters */
94 Status
= STATUS_INVALID_PARAMETER
;
97 Irp
->IoStatus
.Status
= Status
;
98 Irp
->IoStatus
.Information
= BytesCopied
;
100 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
108 CancelPacketRead(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
110 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
111 PNDISUIO_PACKET_ENTRY PacketEntry
;
114 /* Indicate a 0-byte packet on the queue so one read returns 0 */
115 PacketEntry
= ExAllocatePool(PagedPool
, sizeof(NDISUIO_PACKET_ENTRY
));
118 PacketEntry
->PacketLength
= 0;
120 ExInterlockedInsertHeadList(&AdapterContext
->PacketList
,
121 &PacketEntry
->ListEntry
,
122 &AdapterContext
->Spinlock
);
124 KeSetEvent(&AdapterContext
->PacketReadEvent
, IO_NO_INCREMENT
, FALSE
);
126 Status
= STATUS_SUCCESS
;
130 Status
= STATUS_NO_MEMORY
;
133 Irp
->IoStatus
.Status
= Status
;
134 Irp
->IoStatus
.Information
= 0;
136 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
144 SetAdapterOid(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
146 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
147 PNDISUIO_SET_OID SetOidRequest
;
148 NDIS_REQUEST Request
;
152 Irp
->IoStatus
.Information
= 0;
154 SetOidRequest
= Irp
->AssociatedIrp
.SystemBuffer
;
155 RequestLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
156 if (SetOidRequest
&& RequestLength
>= sizeof(NDIS_OID
))
158 /* Setup the NDIS request */
159 Request
.RequestType
= NdisRequestSetInformation
;
160 Request
.DATA
.SET_INFORMATION
.Oid
= SetOidRequest
->Oid
;
161 Request
.DATA
.SET_INFORMATION
.InformationBuffer
= SetOidRequest
->Data
;
162 Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= RequestLength
- sizeof(NDIS_OID
);
164 DPRINT("Setting OID 0x%x on adapter %wZ\n", SetOidRequest
->Oid
, &AdapterContext
->DeviceName
);
166 /* Dispatch the request */
168 AdapterContext
->BindingHandle
,
171 /* Wait for the request */
172 if (Status
== NDIS_STATUS_PENDING
)
174 KeWaitForSingleObject(&AdapterContext
->AsyncEvent
,
179 Status
= AdapterContext
->AsyncStatus
;
182 /* Return the bytes read */
183 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= Request
.DATA
.SET_INFORMATION
.BytesRead
;
188 Status
= STATUS_INVALID_PARAMETER
;
191 Irp
->IoStatus
.Status
= Status
;
193 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
200 QueryAdapterOid(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
202 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
203 PNDISUIO_QUERY_OID QueryOidRequest
;
204 NDIS_REQUEST Request
;
208 Irp
->IoStatus
.Information
= 0;
210 QueryOidRequest
= Irp
->AssociatedIrp
.SystemBuffer
;
211 RequestLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
212 if (QueryOidRequest
&& RequestLength
>= sizeof(NDIS_OID
))
214 /* Setup the NDIS request */
215 Request
.RequestType
= NdisRequestQueryInformation
;
216 Request
.DATA
.QUERY_INFORMATION
.Oid
= QueryOidRequest
->Oid
;
217 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= QueryOidRequest
->Data
;
218 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= RequestLength
- sizeof(NDIS_OID
);
220 DPRINT("Querying OID 0x%x on adapter %wZ\n", QueryOidRequest
->Oid
, &AdapterContext
->DeviceName
);
222 /* Dispatch the request */
224 AdapterContext
->BindingHandle
,
227 /* Wait for the request */
228 if (Status
== NDIS_STATUS_PENDING
)
230 KeWaitForSingleObject(&AdapterContext
->AsyncEvent
,
235 Status
= AdapterContext
->AsyncStatus
;
238 /* Return the bytes written */
239 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= Request
.DATA
.QUERY_INFORMATION
.BytesWritten
;
244 Status
= STATUS_INVALID_PARAMETER
;
247 Irp
->IoStatus
.Status
= Status
;
249 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
256 OpenDeviceReadWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
258 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
259 UNICODE_STRING DeviceName
;
262 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
263 PNDISUIO_OPEN_ENTRY OpenEntry
;
266 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
269 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
270 DeviceName
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
272 /* Check if this already has a context */
273 AdapterContext
= FindAdapterContextByName(&DeviceName
);
274 if (AdapterContext
!= NULL
)
276 DPRINT("Binding file object 0x%x to device %wZ\n", FileObject
, &AdapterContext
->DeviceName
);
278 /* Reference the adapter context */
279 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
280 if (AdapterContext
->OpenCount
!= 0)
282 /* An open for read-write is exclusive,
283 * so we can't have any other open handles */
284 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
285 Status
= STATUS_INVALID_PARAMETER
;
289 /* Add a reference */
290 ReferenceAdapterContext(AdapterContext
);
291 Status
= STATUS_SUCCESS
;
296 /* Invalid device name */
297 Status
= STATUS_INVALID_PARAMETER
;
300 /* Check that the bind succeeded */
301 if (NT_SUCCESS(Status
))
303 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
306 /* Set the file object pointer */
307 OpenEntry
->FileObject
= FileObject
;
309 /* Set the permissions */
310 OpenEntry
->WriteOnly
= FALSE
;
312 /* Associate this FO with the adapter */
313 FileObject
->FsContext
= AdapterContext
;
314 FileObject
->FsContext2
= OpenEntry
;
316 /* Add it to the adapter's list */
317 InsertTailList(&AdapterContext
->OpenEntryList
,
318 &OpenEntry
->ListEntry
);
321 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
322 Status
= STATUS_SUCCESS
;
326 /* Remove the reference we added */
327 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
328 DereferenceAdapterContextWithOpenEntry(AdapterContext
, NULL
);
329 Status
= STATUS_NO_MEMORY
;
335 /* Invalid device name */
336 Status
= STATUS_INVALID_PARAMETER
;
339 Irp
->IoStatus
.Status
= Status
;
340 Irp
->IoStatus
.Information
= 0;
342 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
350 OpenDeviceWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
352 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
353 UNICODE_STRING DeviceName
;
356 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
357 PNDISUIO_OPEN_ENTRY OpenEntry
;
360 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
363 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
364 DeviceName
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
366 /* Check if this already has a context */
367 AdapterContext
= FindAdapterContextByName(&DeviceName
);
368 if (AdapterContext
!= NULL
)
370 /* Reference the adapter context */
371 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
372 ReferenceAdapterContext(AdapterContext
);
373 Status
= STATUS_SUCCESS
;
377 /* Invalid device name */
378 Status
= STATUS_INVALID_PARAMETER
;
381 /* Check that the bind succeeded */
382 if (NT_SUCCESS(Status
))
384 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
387 /* Set the file object pointer */
388 OpenEntry
->FileObject
= FileObject
;
390 /* Associate this FO with the adapter */
391 FileObject
->FsContext
= AdapterContext
;
392 FileObject
->FsContext2
= OpenEntry
;
394 /* Set permissions */
395 OpenEntry
->WriteOnly
= TRUE
;
397 /* Add it to the adapter's list */
398 InsertTailList(&AdapterContext
->OpenEntryList
,
399 &OpenEntry
->ListEntry
);
402 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
403 Status
= STATUS_SUCCESS
;
407 /* Remove the reference we added */
408 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
409 DereferenceAdapterContext(AdapterContext
, NULL
);
410 Status
= STATUS_NO_MEMORY
;
416 /* Invalid device name */
417 Status
= STATUS_INVALID_PARAMETER
;
420 Irp
->IoStatus
.Status
= Status
;
421 Irp
->IoStatus
.Information
= 0;
423 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
431 NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject
,
434 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
435 PNDISUIO_OPEN_ENTRY OpenEntry
;
437 ASSERT(DeviceObject
== GlobalDeviceObject
);
439 /* Handle open IOCTLs first */
440 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
442 case IOCTL_NDISUIO_OPEN_DEVICE
:
443 return OpenDeviceReadWrite(Irp
, IrpSp
);
445 case IOCTL_NDISUIO_OPEN_WRITE_DEVICE
:
446 return OpenDeviceWrite(Irp
, IrpSp
);
448 case IOCTL_NDISUIO_BIND_WAIT
:
449 return WaitForBind(Irp
, IrpSp
);
451 case IOCTL_NDISUIO_QUERY_BINDING
:
452 return QueryBinding(Irp
, IrpSp
);
455 /* Fail if this file object has no adapter associated */
456 if (IrpSp
->FileObject
->FsContext
== NULL
)
458 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
459 Irp
->IoStatus
.Information
= 0;
460 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
462 return STATUS_INVALID_PARAMETER
;
465 /* Now handle write IOCTLs */
466 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
468 case IOCTL_NDISUIO_SET_OID_VALUE
:
469 return SetAdapterOid(Irp
, IrpSp
);
472 /* Check that we have read permissions */
473 OpenEntry
= IrpSp
->FileObject
->FsContext2
;
474 if (OpenEntry
->WriteOnly
)
476 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
477 Irp
->IoStatus
.Information
= 0;
478 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
480 return STATUS_INVALID_PARAMETER
;
483 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
486 case IOCTL_CANCEL_READ
:
487 return CancelPacketRead(Irp
, IrpSp
);
490 case IOCTL_NDISUIO_QUERY_OID_VALUE
:
491 return QueryAdapterOid(Irp
, IrpSp
);
494 DPRINT1("Unimplemented\n");
495 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
496 Irp
->IoStatus
.Information
= 0;
497 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
498 return STATUS_NOT_IMPLEMENTED
;