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 KeReleaseSpinLock(&GlobalAdapterListLock
, OldIrql
);
56 if (i
== QueryBinding
->BindingIndex
)
58 AdapterContext
= CONTAINING_RECORD(CurrentEntry
, NDISUIO_ADAPTER_CONTEXT
, ListEntry
);
59 if (AdapterContext
->DeviceName
.Length
<= QueryBinding
->DeviceNameLength
)
61 BytesCopied
+= AdapterContext
->DeviceName
.Length
;
62 RtlCopyMemory((PUCHAR
)QueryBinding
+ QueryBinding
->DeviceNameOffset
,
63 AdapterContext
->DeviceName
.Buffer
,
65 QueryBinding
->DeviceNameLength
= AdapterContext
->DeviceName
.Length
;
67 /* FIXME: Copy description too */
68 QueryBinding
->DeviceDescrLength
= 0;
71 Status
= STATUS_SUCCESS
;
75 /* Not enough buffer space */
76 Status
= STATUS_BUFFER_TOO_SMALL
;
82 Status
= STATUS_NO_MORE_ENTRIES
;
87 /* Invalid parameters */
88 Status
= STATUS_INVALID_PARAMETER
;
91 Irp
->IoStatus
.Status
= Status
;
92 Irp
->IoStatus
.Information
= BytesCopied
;
94 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
100 CancelPacketRead(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
102 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
103 PNDISUIO_PACKET_ENTRY PacketEntry
;
106 /* Indicate a 0-byte packet on the queue so one read returns 0 */
107 PacketEntry
= ExAllocatePool(PagedPool
, sizeof(NDISUIO_PACKET_ENTRY
));
110 PacketEntry
->PacketLength
= 0;
112 ExInterlockedInsertHeadList(&AdapterContext
->PacketList
,
113 &PacketEntry
->ListEntry
,
114 &AdapterContext
->Spinlock
);
116 KeSetEvent(&AdapterContext
->PacketReadEvent
, IO_NO_INCREMENT
, FALSE
);
118 Status
= STATUS_SUCCESS
;
122 Status
= STATUS_NO_MEMORY
;
125 Irp
->IoStatus
.Status
= Status
;
126 Irp
->IoStatus
.Information
= 0;
128 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
134 SetAdapterOid(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
136 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
137 PNDISUIO_SET_OID SetOidRequest
;
138 NDIS_REQUEST NdisRequest
;
142 Irp
->IoStatus
.Information
= 0;
144 SetOidRequest
= IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
145 RequestLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
146 if (QueryOidRequest
&& RequestLength
>= sizeof(NDIS_OID
))
148 /* Setup the NDIS request */
149 NdisRequest
.RequestType
= NdisRequestSetInformation
;
150 NdisRequest
.Oid
= SetOidRequest
->Oid
;
151 NdisRequest
.InformationBuffer
= SetOidRequest
->Data
;
152 NdisRequest
.InformationBufferLength
= RequestLength
- sizeof(NDIS_OID
);
154 /* Dispatch the request */
156 AdapterContext
->BindingHandle
,
159 /* Wait for the request */
160 if (Status
== NDIS_STATUS_PENDING
)
162 KeWaitForSingleObject(&AdapterContext
->AsyncEvent
,
167 Status
= AdapterContext
->AsyncStatus
;
170 /* Return the bytes read */
171 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= NdisRequest
.BytesRead
;
176 Status
= STATUS_INVALID_PARAMETER
;
179 Irp
->IoStatus
.Status
= Status
;
181 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
187 QueryAdapterOid(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
189 PNDISUIO_ADAPTER_CONTEXT AdapterContext
= IrpSp
->FileObject
->FsContext
;
190 PNDISUIO_QUERY_OID QueryOidRequest
;
191 NDIS_REQUEST NdisRequest
;
195 Irp
->IoStatus
.Information
= 0;
197 QueryOidRequest
= IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
198 RequestLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
199 if (QueryOidRequest
&& RequestLength
>= sizeof(NDIS_OID
))
201 /* Setup the NDIS request */
202 NdisRequest
.RequestType
= NdisRequestQueryInformation
;
203 NdisRequest
.Oid
= QueryOidRequest
->Oid
;
204 NdisRequest
.InformationBuffer
= QueryOidRequest
->Data
;
205 NdisRequest
.InformationBufferLength
= RequestLength
- sizeof(NDIS_OID
);
207 /* Dispatch the request */
209 AdapterContext
->BindingHandle
,
212 /* Wait for the request */
213 if (Status
== NDIS_STATUS_PENDING
)
215 KeWaitForSingleObject(&AdapterContext
->AsyncEvent
,
220 Status
= AdapterContext
->AsyncStatus
;
223 /* Return the bytes written */
224 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= NdisRequest
.BytesWritten
;
229 Status
= STATUS_INVALID_PARAMETER
;
232 Irp
->IoStatus
.Status
= Status
;
234 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
240 OpenDeviceReadWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
242 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
243 UNICODE_STRING DeviceName
;
246 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
247 PNDISUIO_OPEN_ENTRY OpenEntry
;
250 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
253 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
254 DeviceName
.Buffer
= IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
256 /* Check if this already has a context */
257 AdapterContext
= FindAdapterContextByName(&DeviceName
);
258 if (AdapterContext
!= NULL
)
260 /* Reference the adapter context */
261 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
262 if (AdapterContext
->OpenCount
!= 0)
264 /* An open for read-write is exclusive,
265 * so we can't have any other open handles */
266 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
267 Status
= STATUS_INVALID_PARAMETER
;
271 /* Add a reference */
272 ReferenceAdapterContext(AdapterContext
);
273 Status
= STATUS_SUCCESS
;
278 /* Invalid device name */
279 Status
= STATUS_INVALID_PARAMETER
;
282 /* Check that the bind succeeded */
283 if (NT_SUCCESS(Status
))
285 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
288 /* Set the file object pointer */
289 OpenEntry
->FileObject
= FileObject
;
291 /* Set the permissions */
292 OpenEntry
->WriteOnly
= FALSE
;
294 /* Associate this FO with the adapter */
295 FileObject
->FsContext
= AdapterContext
;
296 FileObject
->FsContext2
= OpenEntry
;
298 /* Add it to the adapter's list */
299 InsertTailList(&AdapterContext
->OpenEntryList
,
300 &OpenEntry
->ListEntry
);
303 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
304 Status
= STATUS_SUCCESS
;
308 /* Remove the reference we added */
309 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
310 DereferenceAdapterContext(AdapterContext
, NULL
);
311 Status
= STATUS_NO_MEMORY
;
317 /* Invalid device name */
318 Status
= STATUS_INVALID_PARAMETER
;
321 Irp
->IoStatus
.Status
= Status
;
322 Irp
->IoStatus
.Information
= 0;
324 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
330 OpenDeviceWrite(PIRP Irp
, PIO_STACK_LOCATION IrpSp
)
332 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
333 UNICODE_STRING DeviceName
;
336 PNDISUIO_ADAPTER_CONTEXT AdapterContext
;
337 PNDISUIO_OPEN_ENTRY OpenEntry
;
340 NameLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
343 DeviceName
.MaximumLength
= DeviceName
.Length
= NameLength
;
344 DeviceName
.Buffer
= IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
346 /* Check if this already has a context */
347 AdapterContext
= FindAdapterContextByName(&DeviceName
);
348 if (AdapterContext
!= NULL
)
350 /* Reference the adapter context */
351 KeAcquireSpinLock(&AdapterContext
->Spinlock
, &OldIrql
);
352 ReferenceAdapterContext(AdapterContext
);
353 Status
= STATUS_SUCCESS
;
357 /* Invalid device name */
358 Status
= STATUS_INVALID_PARAMETER
;
361 /* Check that the bind succeeded */
362 if (NT_SUCCESS(Status
))
364 OpenEntry
= ExAllocatePool(NonPagedPool
, sizeof(*OpenEntry
));
367 /* Set the file object pointer */
368 OpenEntry
->FileObject
= FileObject
;
370 /* Associate this FO with the adapter */
371 FileObject
->FsContext
= AdapterContext
;
372 FileObject
->FsContext2
= OpenEntry
;
374 /* Set permissions */
375 OpenEntry
->WriteOnly
= TRUE
;
377 /* Add it to the adapter's list */
378 InsertTailList(&AdapterContext
->OpenEntryList
,
379 &OpenEntry
->ListEntry
);
382 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
383 Status
= STATUS_SUCCESS
;
387 /* Remove the reference we added */
388 KeReleaseSpinLock(&AdapterContext
->Spinlock
, OldIrql
);
389 DereferenceAdapterContext(AdapterContext
, NULL
);
390 Status
= STATUS_NO_MEMORY
;
396 /* Invalid device name */
397 Status
= STATUS_INVALID_PARAMETER
;
400 Irp
->IoStatus
.Status
= Status
;
401 Irp
->IoStatus
.Information
= 0;
403 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
410 NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject
,
413 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
414 PNDISUIO_OPEN_ENTRY OpenEntry
;
416 ASSERT(DeviceObject
== GlobalDeviceObject
);
418 /* Handle open IOCTLs first */
419 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
421 case IOCTL_NDISUIO_OPEN_DEVICE
:
422 return OpenDeviceReadWrite(Irp
, IrpSp
);
424 case IOCTL_NDISUIO_OPEN_WRITE_DEVICE
:
425 return OpenDeviceWrite(Irp
, IrpSp
);
427 case IOCTL_NDISUIO_BIND_WAIT
:
428 return WaitForBind(Irp
, IrpSp
);
430 case IOCTL_NDISUIO_QUERY_BINDING
:
431 return QueryBinding(Irp
, IrpSp
);
434 /* Fail if this file object has no adapter associated */
435 if (IrpSp
->FileObject
->FsContext
== NULL
)
437 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
438 Irp
->IoStatus
.Information
= 0;
439 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
441 return STATUS_INVALID_PARAMETER
;
444 /* Now handle write IOCTLs */
445 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
447 case IOCTL_NDISUIO_SET_OID_VALUE
:
448 return SetAdapterOid(Irp
, IrpSp
);
451 /* Check that we have read permissions */
452 OpenEntry
= IrpSp
->FileObject
->FsContext2
;
453 if (OpenEntry
->WriteOnly
)
455 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
456 Irp
->IoStatus
.Information
= 0;
457 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
459 return STATUS_INVALID_PARAMETER
;
462 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
464 case IOCTL_CANCEL_READ
:
465 return CancelPacketRead(Irp
, IrpSp
);
467 case IOCTL_NDISUIO_QUERY_OID_VALUE
:
468 return QueryAdapterOid(Irp
, IrpSp
);
471 DPRINT1("Unimplemented\n");
472 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
473 Irp
->IoStatus
.Information
= 0;
474 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);