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
.InformationBuffer
= SetOidRequest
->Data
;
164 Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= RequestLength
- sizeof(NDIS_OID
);
166 DPRINT("Setting OID 0x%x on adapter %wZ\n", SetOidRequest
->Oid
, &AdapterContext
->DeviceName
);
168 /* Dispatch the request */
170 AdapterContext
->BindingHandle
,
173 /* Wait for the request */
174 if (Status
== NDIS_STATUS_PENDING
)
176 KeWaitForSingleObject(&AdapterContext
->AsyncEvent
,
181 Status
= AdapterContext
->AsyncStatus
;
184 /* Return the bytes read */
185 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= Request
.DATA
.SET_INFORMATION
.BytesRead
;
190 Status
= STATUS_INVALID_PARAMETER
;
193 Irp
->IoStatus
.Status
= Status
;
195 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
202 QueryAdapterOid(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
204 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
205 PNDISUIO_QUERY_OID QueryOidRequest
;
206 NDIS_REQUEST Request
;
210 Irp
->IoStatus
.Information
= 0;
212 QueryOidRequest
= Irp
->AssociatedIrp
.SystemBuffer
;
213 RequestLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
214 if (QueryOidRequest
&& RequestLength
>= sizeof(NDIS_OID
))
216 /* Setup the NDIS request */
217 Request
.RequestType
= NdisRequestQueryInformation
;
218 Request
.DATA
.QUERY_INFORMATION
.Oid
= QueryOidRequest
->Oid
;
219 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= QueryOidRequest
->Data
;
220 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= RequestLength
- sizeof(NDIS_OID
);
222 DPRINT("Querying OID 0x%x on adapter %wZ\n", QueryOidRequest
->Oid
, &AdapterContext
->DeviceName
);
224 /* Dispatch the request */
226 AdapterContext
->BindingHandle
,
229 /* Wait for the request */
230 if (Status
== NDIS_STATUS_PENDING
)
232 KeWaitForSingleObject(&AdapterContext
->AsyncEvent
,
237 Status
= AdapterContext
->AsyncStatus
;
240 /* Return the bytes written */
241 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= Request
.DATA
.QUERY_INFORMATION
.BytesWritten
;
246 Status
= STATUS_INVALID_PARAMETER
;
249 Irp
->IoStatus
.Status
= Status
;
251 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
258 OpenDeviceReadWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
260 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
261 UNICODE_STRING DeviceName
;
264 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
265 PNDISUIO_OPEN_ENTRY OpenEntry
;
268 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
271 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
272 DeviceName
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
274 /* Check if this already has a context */
275 AdapterContext
= FindAdapterContextByName(&DeviceName
);
276 if (AdapterContext
!= NULL
)
278 DPRINT("Binding file object 0x%x to device %wZ\n", FileObject
, &AdapterContext
->DeviceName
);
280 /* Reference the adapter context */
281 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
282 if (AdapterContext
->OpenCount
!= 0)
284 /* An open for read-write is exclusive,
285 * so we can't have any other open handles */
286 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
287 Status
= STATUS_INVALID_PARAMETER
;
291 /* Add a reference */
292 ReferenceAdapterContext(AdapterContext
);
293 Status
= STATUS_SUCCESS
;
298 /* Invalid device name */
299 Status
= STATUS_INVALID_PARAMETER
;
302 /* Check that the bind succeeded */
303 if (NT_SUCCESS(Status
))
305 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
308 /* Set the file object pointer */
309 OpenEntry
->FileObject
= FileObject
;
311 /* Set the permissions */
312 OpenEntry
->WriteOnly
= FALSE
;
314 /* Associate this FO with the adapter */
315 FileObject
->FsContext
= AdapterContext
;
316 FileObject
->FsContext2
= OpenEntry
;
318 /* Add it to the adapter's list */
319 InsertTailList(&AdapterContext
->OpenEntryList
,
320 &OpenEntry
->ListEntry
);
323 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
324 Status
= STATUS_SUCCESS
;
328 /* Remove the reference we added */
329 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
330 DereferenceAdapterContextWithOpenEntry(AdapterContext
, NULL
);
331 Status
= STATUS_NO_MEMORY
;
337 /* Invalid device name */
338 Status
= STATUS_INVALID_PARAMETER
;
341 Irp
->IoStatus
.Status
= Status
;
342 Irp
->IoStatus
.Information
= 0;
344 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
352 OpenDeviceWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
354 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
355 UNICODE_STRING DeviceName
;
358 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
359 PNDISUIO_OPEN_ENTRY OpenEntry
;
362 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
365 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
366 DeviceName
.Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
368 /* Check if this already has a context */
369 AdapterContext
= FindAdapterContextByName(&DeviceName
);
370 if (AdapterContext
!= NULL
)
372 /* Reference the adapter context */
373 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
374 ReferenceAdapterContext(AdapterContext
);
375 Status
= STATUS_SUCCESS
;
379 /* Invalid device name */
380 Status
= STATUS_INVALID_PARAMETER
;
383 /* Check that the bind succeeded */
384 if (NT_SUCCESS(Status
))
386 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
389 /* Set the file object pointer */
390 OpenEntry
->FileObject
= FileObject
;
392 /* Associate this FO with the adapter */
393 FileObject
->FsContext
= AdapterContext
;
394 FileObject
->FsContext2
= OpenEntry
;
396 /* Set permissions */
397 OpenEntry
->WriteOnly
= TRUE
;
399 /* Add it to the adapter's list */
400 InsertTailList(&AdapterContext
->OpenEntryList
,
401 &OpenEntry
->ListEntry
);
404 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
405 Status
= STATUS_SUCCESS
;
409 /* Remove the reference we added */
410 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
411 DereferenceAdapterContext(AdapterContext
, NULL
);
412 Status
= STATUS_NO_MEMORY
;
418 /* Invalid device name */
419 Status
= STATUS_INVALID_PARAMETER
;
422 Irp
->IoStatus
.Status
= Status
;
423 Irp
->IoStatus
.Information
= 0;
425 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
433 NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject
,
436 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
437 PNDISUIO_OPEN_ENTRY OpenEntry
;
439 ASSERT(DeviceObject
== GlobalDeviceObject
);
441 /* Handle open IOCTLs first */
442 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
444 case IOCTL_NDISUIO_OPEN_DEVICE
:
445 return OpenDeviceReadWrite(Irp
, IrpSp
);
447 case IOCTL_NDISUIO_OPEN_WRITE_DEVICE
:
448 return OpenDeviceWrite(Irp
, IrpSp
);
450 case IOCTL_NDISUIO_BIND_WAIT
:
451 return WaitForBind(Irp
, IrpSp
);
453 case IOCTL_NDISUIO_QUERY_BINDING
:
454 return QueryBinding(Irp
, IrpSp
);
457 /* Fail if this file object has no adapter associated */
458 if (IrpSp
->FileObject
->FsContext
== NULL
)
460 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
461 Irp
->IoStatus
.Information
= 0;
462 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
464 return STATUS_INVALID_PARAMETER
;
467 /* Now handle write IOCTLs */
468 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
470 case IOCTL_NDISUIO_SET_OID_VALUE
:
471 return SetAdapterOid(Irp
, IrpSp
);
474 /* Check that we have read permissions */
475 OpenEntry
= IrpSp
->FileObject
->FsContext2
;
476 if (OpenEntry
->WriteOnly
)
478 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
479 Irp
->IoStatus
.Information
= 0;
480 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
482 return STATUS_INVALID_PARAMETER
;
485 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
488 case IOCTL_CANCEL_READ
:
489 return CancelPacketRead(Irp
, IrpSp
);
492 case IOCTL_NDISUIO_QUERY_OID_VALUE
:
493 return QueryAdapterOid(Irp
, IrpSp
);
496 DPRINT1("Unimplemented\n");
497 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
498 Irp
->IoStatus
.Information
= 0;
499 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
500 return STATUS_NOT_IMPLEMENTED
;