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 */
23 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
24 Irp
->IoStatus
.Information
= 0;
26 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
28 return STATUS_SUCCESS
;
33 QueryBinding(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
35 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
36 PNDISUIO_QUERY_BINDING QueryBinding
= IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
37 ULONG BindingLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
39 PLIST_ENTRY CurrentEntry
;
42 ULONG BytesCopied
= 0;
44 if (QueryBinding
&& BindingLength
>= sizeof(NDISUIO_QUERY_BINDING
))
46 KeAcquireSpinLock(&GlobalAdapterListLock
, &OldIrql
);
48 CurrentEntry
= GlobalAdapterList
.Flink
;
49 while (CurrentEntry
!= &GlobalAdapterList
)
51 if (i
== QueryBinding
->BindingIndex
)
54 CurrentEntry
= CurrentEntry
->Flink
;
56 KeReleaseSpinLock(&GlobalAdapterListLock
, OldIrql
);
57 if (i
== QueryBinding
->BindingIndex
)
59 AdapterContext
= CONTAINING_RECORD(CurrentEntry
, NDISUIO_ADAPTER_CONTEXT
, ListEntry
);
60 if (AdapterContext
->DeviceName
.Length
<= QueryBinding
->DeviceNameLength
)
62 BytesCopied
+= AdapterContext
->DeviceName
.Length
;
63 RtlCopyMemory((PUCHAR
)QueryBinding
+ QueryBinding
->DeviceNameOffset
,
64 AdapterContext
->DeviceName
.Buffer
,
66 QueryBinding
->DeviceNameLength
= AdapterContext
->DeviceName
.Length
;
68 /* FIXME: Copy description too */
69 QueryBinding
->DeviceDescrLength
= 0;
72 Status
= STATUS_SUCCESS
;
76 /* Not enough buffer space */
77 Status
= STATUS_BUFFER_TOO_SMALL
;
83 Status
= STATUS_NO_MORE_ENTRIES
;
88 /* Invalid parameters */
89 Status
= STATUS_INVALID_PARAMETER
;
92 Irp
->IoStatus
.Status
= Status
;
93 Irp
->IoStatus
.Information
= BytesCopied
;
95 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
103 CancelPacketRead(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
105 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
106 PNDISUIO_PACKET_ENTRY PacketEntry
;
109 /* Indicate a 0-byte packet on the queue so one read returns 0 */
110 PacketEntry
= ExAllocatePool(PagedPool
, sizeof(NDISUIO_PACKET_ENTRY
));
113 PacketEntry
->PacketLength
= 0;
115 ExInterlockedInsertHeadList(&AdapterContext
->PacketList
,
116 &PacketEntry
->ListEntry
,
117 &AdapterContext
->Spinlock
);
119 KeSetEvent(&AdapterContext
->PacketReadEvent
, IO_NO_INCREMENT
, FALSE
);
121 Status
= STATUS_SUCCESS
;
125 Status
= STATUS_NO_MEMORY
;
128 Irp
->IoStatus
.Status
= Status
;
129 Irp
->IoStatus
.Information
= 0;
131 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
139 SetAdapterOid(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
141 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
142 PNDISUIO_SET_OID SetOidRequest
;
143 NDIS_REQUEST Request
;
147 Irp
->IoStatus
.Information
= 0;
149 SetOidRequest
= IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
150 RequestLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
151 if (SetOidRequest
&& RequestLength
>= sizeof(NDIS_OID
))
153 /* Setup the NDIS request */
154 Request
.RequestType
= NdisRequestSetInformation
;
155 Request
.DATA
.SET_INFORMATION
.Oid
= SetOidRequest
->Oid
;
156 Request
.DATA
.SET_INFORMATION
.InformationBuffer
= SetOidRequest
->Data
;
157 Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= RequestLength
- sizeof(NDIS_OID
);
159 /* Dispatch the request */
161 AdapterContext
->BindingHandle
,
164 /* Wait for the request */
165 if (Status
== NDIS_STATUS_PENDING
)
167 KeWaitForSingleObject(&AdapterContext
->AsyncEvent
,
172 Status
= AdapterContext
->AsyncStatus
;
175 /* Return the bytes read */
176 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= Request
.DATA
.SET_INFORMATION
.BytesRead
;
181 Status
= STATUS_INVALID_PARAMETER
;
184 Irp
->IoStatus
.Status
= Status
;
186 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
193 QueryAdapterOid(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
195 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
196 PNDISUIO_QUERY_OID QueryOidRequest
;
197 NDIS_REQUEST Request
;
201 Irp
->IoStatus
.Information
= 0;
203 QueryOidRequest
= IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
204 RequestLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
205 if (QueryOidRequest
&& RequestLength
>= sizeof(NDIS_OID
))
207 /* Setup the NDIS request */
208 Request
.RequestType
= NdisRequestQueryInformation
;
209 Request
.DATA
.QUERY_INFORMATION
.Oid
= QueryOidRequest
->Oid
;
210 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= QueryOidRequest
->Data
;
211 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= RequestLength
- sizeof(NDIS_OID
);
213 /* Dispatch the request */
215 AdapterContext
->BindingHandle
,
218 /* Wait for the request */
219 if (Status
== NDIS_STATUS_PENDING
)
221 KeWaitForSingleObject(&AdapterContext
->AsyncEvent
,
226 Status
= AdapterContext
->AsyncStatus
;
229 /* Return the bytes written */
230 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= Request
.DATA
.QUERY_INFORMATION
.BytesWritten
;
235 Status
= STATUS_INVALID_PARAMETER
;
238 Irp
->IoStatus
.Status
= Status
;
240 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
247 OpenDeviceReadWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
249 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
250 UNICODE_STRING DeviceName
;
253 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
254 PNDISUIO_OPEN_ENTRY OpenEntry
;
257 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
260 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
261 DeviceName
.Buffer
= IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
263 /* Check if this already has a context */
264 AdapterContext
= FindAdapterContextByName(&DeviceName
);
265 if (AdapterContext
!= NULL
)
267 /* Reference the adapter context */
268 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
269 if (AdapterContext
->OpenCount
!= 0)
271 /* An open for read-write is exclusive,
272 * so we can't have any other open handles */
273 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
274 Status
= STATUS_INVALID_PARAMETER
;
278 /* Add a reference */
279 ReferenceAdapterContext(AdapterContext
);
280 Status
= STATUS_SUCCESS
;
285 /* Invalid device name */
286 Status
= STATUS_INVALID_PARAMETER
;
289 /* Check that the bind succeeded */
290 if (NT_SUCCESS(Status
))
292 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
295 /* Set the file object pointer */
296 OpenEntry
->FileObject
= FileObject
;
298 /* Set the permissions */
299 OpenEntry
->WriteOnly
= FALSE
;
301 /* Associate this FO with the adapter */
302 FileObject
->FsContext
= AdapterContext
;
303 FileObject
->FsContext2
= OpenEntry
;
305 /* Add it to the adapter's list */
306 InsertTailList(&AdapterContext
->OpenEntryList
,
307 &OpenEntry
->ListEntry
);
310 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
311 Status
= STATUS_SUCCESS
;
315 /* Remove the reference we added */
316 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
317 DereferenceAdapterContextWithOpenEntry(AdapterContext
, NULL
);
318 Status
= STATUS_NO_MEMORY
;
324 /* Invalid device name */
325 Status
= STATUS_INVALID_PARAMETER
;
328 Irp
->IoStatus
.Status
= Status
;
329 Irp
->IoStatus
.Information
= 0;
331 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
339 OpenDeviceWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
341 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
342 UNICODE_STRING DeviceName
;
345 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
346 PNDISUIO_OPEN_ENTRY OpenEntry
;
349 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
352 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
353 DeviceName
.Buffer
= IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
355 /* Check if this already has a context */
356 AdapterContext
= FindAdapterContextByName(&DeviceName
);
357 if (AdapterContext
!= NULL
)
359 /* Reference the adapter context */
360 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
361 ReferenceAdapterContext(AdapterContext
);
362 Status
= STATUS_SUCCESS
;
366 /* Invalid device name */
367 Status
= STATUS_INVALID_PARAMETER
;
370 /* Check that the bind succeeded */
371 if (NT_SUCCESS(Status
))
373 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
376 /* Set the file object pointer */
377 OpenEntry
->FileObject
= FileObject
;
379 /* Associate this FO with the adapter */
380 FileObject
->FsContext
= AdapterContext
;
381 FileObject
->FsContext2
= OpenEntry
;
383 /* Set permissions */
384 OpenEntry
->WriteOnly
= TRUE
;
386 /* Add it to the adapter's list */
387 InsertTailList(&AdapterContext
->OpenEntryList
,
388 &OpenEntry
->ListEntry
);
391 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
392 Status
= STATUS_SUCCESS
;
396 /* Remove the reference we added */
397 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
398 DereferenceAdapterContext(AdapterContext
, NULL
);
399 Status
= STATUS_NO_MEMORY
;
405 /* Invalid device name */
406 Status
= STATUS_INVALID_PARAMETER
;
409 Irp
->IoStatus
.Status
= Status
;
410 Irp
->IoStatus
.Information
= 0;
412 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
420 NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject
,
423 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
424 PNDISUIO_OPEN_ENTRY OpenEntry
;
426 ASSERT(DeviceObject
== GlobalDeviceObject
);
428 /* Handle open IOCTLs first */
429 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
431 case IOCTL_NDISUIO_OPEN_DEVICE
:
432 return OpenDeviceReadWrite(Irp
, IrpSp
);
434 case IOCTL_NDISUIO_OPEN_WRITE_DEVICE
:
435 return OpenDeviceWrite(Irp
, IrpSp
);
437 case IOCTL_NDISUIO_BIND_WAIT
:
438 return WaitForBind(Irp
, IrpSp
);
440 case IOCTL_NDISUIO_QUERY_BINDING
:
441 return QueryBinding(Irp
, IrpSp
);
444 /* Fail if this file object has no adapter associated */
445 if (IrpSp
->FileObject
->FsContext
== NULL
)
447 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
448 Irp
->IoStatus
.Information
= 0;
449 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
451 return STATUS_INVALID_PARAMETER
;
454 /* Now handle write IOCTLs */
455 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
457 case IOCTL_NDISUIO_SET_OID_VALUE
:
458 return SetAdapterOid(Irp
, IrpSp
);
461 /* Check that we have read permissions */
462 OpenEntry
= IrpSp
->FileObject
->FsContext2
;
463 if (OpenEntry
->WriteOnly
)
465 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
466 Irp
->IoStatus
.Information
= 0;
467 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
469 return STATUS_INVALID_PARAMETER
;
472 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
475 case IOCTL_CANCEL_READ
:
476 return CancelPacketRead(Irp
, IrpSp
);
479 case IOCTL_NDISUIO_QUERY_OID_VALUE
:
480 return QueryAdapterOid(Irp
, IrpSp
);
483 DPRINT1("Unimplemented\n");
484 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
485 Irp
->IoStatus
.Information
= 0;
486 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
487 return STATUS_NOT_IMPLEMENTED
;