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
;
32 QueryBinding(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
34 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
35 PNDISUIO_QUERY_BINDING QueryBinding
= IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
36 ULONG BindingLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
38 PLIST_ENTRY CurrentEntry
;
41 ULONG BytesCopied
= 0;
43 if (QueryBinding
&& BindingLength
>= sizeof(NDISUIO_QUERY_BINDING
))
45 KeAcquireSpinLock(&GlobalAdapterListLock
, &OldIrql
);
47 CurrentEntry
= GlobalAdapterList
.Flink
;
48 while (CurrentEntry
!= &GlobalAdapterList
)
50 if (i
== QueryBinding
->BindingIndex
)
53 CurrentEntry
= CurrentEntry
->Flink
;
55 if (i
== QueryBinding
->BindingIndex
)
57 AdapterContext
= CONTAINING_RECORD(CurrentEntry
, NDISUIO_ADAPTER_CONTEXT
, ListEntry
);
58 if (AdapterContext
->DeviceName
.Length
<= QueryBinding
->DeviceNameLength
)
60 BytesCopied
+= AdapterContext
->DeviceName
.Length
;
61 RtlCopyMemory((PUCHAR
)QueryBinding
+ QueryBinding
->DeviceNameOffset
,
62 AdapterContext
->DeviceName
.Buffer
,
64 QueryBinding
->DeviceNameLength
= AdapterContext
->DeviceName
.Length
;
66 /* FIXME: Copy description too */
67 QueryBinding
->DeviceDescrLength
= 0;
70 Status
= STATUS_SUCCESS
;
74 /* Not enough buffer space */
75 Status
= STATUS_BUFFER_TOO_SMALL
;
81 Status
= STATUS_INVALID_PARAMETER
;
86 /* Invalid parameters */
87 Status
= STATUS_INVALID_PARAMETER
;
90 Irp
->IoStatus
.Status
= Status
;
91 Irp
->IoStatus
.Information
= BytesCopied
;
93 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
99 CancelPacketRead(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
101 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
102 PNDISUIO_PACKET_ENTRY PacketEntry
;
105 /* Indicate a 0-byte packet on the queue so one read returns 0 */
106 PacketEntry
= ExAllocatePool(PagedPool
, sizeof(NDISUIO_PACKET_ENTRY
));
109 PacketEntry
->PacketLength
= 0;
111 ExInterlockedInsertTailList(&AdapterContext
->PacketList
,
112 &PacketEntry
->ListEntry
,
113 &AdapterContext
->Spinlock
);
115 KeSetEvent(&AdapterContext
->PacketReadEvent
, IO_NO_INCREMENT
, FALSE
);
117 Status
= STATUS_SUCCESS
;
121 Status
= STATUS_NO_MEMORY
;
124 Irp
->IoStatus
.Status
= Status
;
125 Irp
->IoStatus
.Information
= 0;
127 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
133 SetAdapterOid(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
135 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
136 PNDISUIO_SET_OID SetOidRequest
;
137 NDIS_REQUEST NdisRequest
;
141 Irp
->IoStatus
.Information
= 0;
143 SetOidRequest
= IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
144 RequestLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
145 if (QueryOidRequest
&& RequestLength
>= sizeof(NDIS_OID
))
147 /* Setup the NDIS request */
148 NdisRequest
.RequestType
= NdisRequestSetInformation
;
149 NdisRequest
.Oid
= SetOidRequest
->Oid
;
150 NdisRequest
.InformationBuffer
= SetOidRequest
->Data
;
151 NdisRequest
.InformationBufferLength
= RequestLength
- sizeof(NDIS_OID
);
153 /* Dispatch the request */
155 AdapterContext
->BindingHandle
,
158 /* Wait for the request */
159 if (Status
== NDIS_STATUS_PENDING
)
161 KeWaitForSingleObject(&AdapterContext
->AsyncEvent
,
166 Status
= AdapterContext
->AsyncStatus
;
169 /* Return the bytes read */
170 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= NdisRequest
.BytesRead
;
175 Status
= STATUS_INVALID_PARAMETER
;
178 Irp
->IoStatus
.Status
= Status
;
180 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
186 QueryAdapterOid(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
188 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
189 PNDISUIO_QUERY_OID QueryOidRequest
;
190 NDIS_REQUEST NdisRequest
;
194 Irp
->IoStatus
.Information
= 0;
196 QueryOidRequest
= IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
197 RequestLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
198 if (QueryOidRequest
&& RequestLength
>= sizeof(NDIS_OID
))
200 /* Setup the NDIS request */
201 NdisRequest
.RequestType
= NdisRequestQueryInformation
;
202 NdisRequest
.Oid
= QueryOidRequest
->Oid
;
203 NdisRequest
.InformationBuffer
= QueryOidRequest
->Data
;
204 NdisRequest
.InformationBufferLength
= RequestLength
- sizeof(NDIS_OID
);
206 /* Dispatch the request */
208 AdapterContext
->BindingHandle
,
211 /* Wait for the request */
212 if (Status
== NDIS_STATUS_PENDING
)
214 KeWaitForSingleObject(&AdapterContext
->AsyncEvent
,
219 Status
= AdapterContext
->AsyncStatus
;
222 /* Return the bytes written */
223 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= NdisRequest
.BytesWritten
;
228 Status
= STATUS_INVALID_PARAMETER
;
231 Irp
->IoStatus
.Status
= Status
;
233 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
239 OpenDeviceReadWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
241 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
242 UNICODE_STRING DeviceName
;
245 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
246 PNDISUIO_OPEN_ENTRY OpenEntry
;
249 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
252 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
253 DeviceName
.Buffer
= IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
255 /* Check if this already has a context */
256 AdapterContext
= FindAdapterContextByName(&DeviceName
);
257 if (AdapterContext
!= NULL
)
259 /* Reference the adapter context */
260 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
261 if (AdapterContext
->OpenCount
!= 0)
263 /* An open for read-write is exclusive,
264 * so we can't have any other open handles */
265 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
266 Status
= STATUS_INVALID_PARAMETER
;
270 /* Add a reference */
271 ReferenceAdapterContext(AdapterContext
);
272 Status
= STATUS_SUCCESS
;
277 /* Invalid device name */
278 Status
= STATUS_INVALID_PARAMETER
;
281 /* Check that the bind succeeded */
282 if (NT_SUCCESS(Status
))
284 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
287 /* Set the file object pointer */
288 OpenEntry
->FileObject
= FileObject
;
290 /* Set the permissions */
291 OpenEntry
->WriteOnly
= FALSE
;
293 /* Associate this FO with the adapter */
294 FileObject
->FsContext
= AdapterContext
;
295 FileObject
->FsContext2
= OpenEntry
;
297 /* Add it to the adapter's list */
298 InsertTailList(&AdapterContext
->OpenEntryList
,
299 &OpenEntry
->ListEntry
);
302 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
303 Status
= STATUS_SUCCESS
;
307 /* Remove the reference we added */
308 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
309 DereferenceAdapterContext(AdapterContext
, NULL
);
310 Status
= STATUS_NO_MEMORY
;
316 /* Invalid device name */
317 Status
= STATUS_INVALID_PARAMETER
;
320 Irp
->IoStatus
.Status
= Status
;
321 Irp
->IoStatus
.Information
= 0;
323 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
329 OpenDeviceWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
331 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
332 UNICODE_STRING DeviceName
;
335 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
336 PNDISUIO_OPEN_ENTRY OpenEntry
;
339 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
342 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
343 DeviceName
.Buffer
= IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
345 /* Check if this already has a context */
346 AdapterContext
= FindAdapterContextByName(&DeviceName
);
347 if (AdapterContext
!= NULL
)
349 /* Reference the adapter context */
350 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
351 ReferenceAdapterContext(AdapterContext
);
352 Status
= STATUS_SUCCESS
;
356 /* Invalid device name */
357 Status
= STATUS_INVALID_PARAMETER
;
360 /* Check that the bind succeeded */
361 if (NT_SUCCESS(Status
))
363 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
366 /* Set the file object pointer */
367 OpenEntry
->FileObject
= FileObject
;
369 /* Associate this FO with the adapter */
370 FileObject
->FsContext
= AdapterContext
;
371 FileObject
->FsContext2
= OpenEntry
;
373 /* Set permissions */
374 OpenEntry
->WriteOnly
= TRUE
;
376 /* Add it to the adapter's list */
377 InsertTailList(&AdapterContext
->OpenEntryList
,
378 &OpenEntry
->ListEntry
);
381 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
382 Status
= STATUS_SUCCESS
;
386 /* Remove the reference we added */
387 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
388 DereferenceAdapterContext(AdapterContext
, NULL
);
389 Status
= STATUS_NO_MEMORY
;
395 /* Invalid device name */
396 Status
= STATUS_INVALID_PARAMETER
;
399 Irp
->IoStatus
.Status
= Status
;
400 Irp
->IoStatus
.Information
= 0;
402 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
409 NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject
,
412 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
413 PNDISUIO_OPEN_ENTRY OpenEntry
;
415 ASSERT(DeviceObject
== GlobalDeviceObject
);
417 /* Handle open IOCTLs first */
418 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
420 case IOCTL_NDISUIO_OPEN_DEVICE
:
421 return OpenDeviceReadWrite(Irp
, IrpSp
);
423 case IOCTL_NDISUIO_OPEN_WRITE_DEVICE
:
424 return OpenDeviceWrite(Irp
, IrpSp
);
426 case IOCTL_NDISUIO_BIND_WAIT
:
427 return WaitForBind(Irp
, IrpSp
);
429 case IOCTL_NDISUIO_QUERY_BINDING
:
430 return QueryBinding(Irp
, IrpSp
);
433 /* Fail if this file object has no adapter associated */
434 if (IrpSp
->FileObject
->FsContext
== NULL
)
436 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
437 Irp
->IoStatus
.Information
= 0;
438 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
440 return STATUS_INVALID_PARAMETER
;
443 /* Now handle write IOCTLs */
444 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
446 case IOCTL_NDISUIO_SET_OID_VALUE
:
447 return SetAdapterOid(Irp
, IrpSp
);
450 /* Check that we have read permissions */
451 OpenEntry
= IrpSp
->FileObject
->FsContext2
;
452 if (OpenEntry
->WriteOnly
)
454 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
455 Irp
->IoStatus
.Information
= 0;
456 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
458 return STATUS_INVALID_PARAMETER
;
461 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
463 case IOCTL_CANCEL_READ
:
464 return CancelPacketRead(Irp
, IrpSp
);
466 case IOCTL_NDISUIO_QUERY_OID_VALUE
:
467 return QueryAdapterOid(Irp
, IrpSp
);
470 DPRINT1("Unimplemented\n");
471 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
472 Irp
->IoStatus
.Information
= 0;
473 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);