Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS NDIS User I/O driver * FILE: ioctl.c * PURPOSE: IOCTL handling * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org) */
#include "ndisuio.h"
//#define NDEBUG#include <debug.h>
staticNTSTATUSWaitForBind(PIRP Irp, PIO_STACK_LOCATION IrpSp){ /* I've seen several code samples that use this IOCTL but there's * no official documentation on it. I'm just implementing it as a no-op * right now because I don't see any reason we need it. We handle an open * and bind just fine with IRP_MJ_CREATE and IOCTL_NDISUIO_OPEN_DEVICE */ DPRINT("Wait for bind complete\n");
Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;}
staticNTSTATUSQueryBinding(PIRP Irp, PIO_STACK_LOCATION IrpSp){ PNDISUIO_ADAPTER_CONTEXT AdapterContext = NULL; PNDISUIO_QUERY_BINDING QueryBinding = Irp->AssociatedIrp.SystemBuffer; ULONG BindingLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; NTSTATUS Status; PLIST_ENTRY CurrentEntry; KIRQL OldIrql; ULONG i; ULONG BytesCopied = 0;
if (QueryBinding && BindingLength >= sizeof(NDISUIO_QUERY_BINDING)) { KeAcquireSpinLock(&GlobalAdapterListLock, &OldIrql); i = 0; CurrentEntry = GlobalAdapterList.Flink; while (CurrentEntry != &GlobalAdapterList) { if (i == QueryBinding->BindingIndex) { AdapterContext = CONTAINING_RECORD(CurrentEntry, NDISUIO_ADAPTER_CONTEXT, ListEntry); break; } i++; CurrentEntry = CurrentEntry->Flink; } KeReleaseSpinLock(&GlobalAdapterListLock, OldIrql); if (AdapterContext) { DPRINT("Query binding for index %d is adapter %wZ\n", i, &AdapterContext->DeviceName); BytesCopied = sizeof(NDISUIO_QUERY_BINDING); if (AdapterContext->DeviceName.Length <= BindingLength - BytesCopied) { QueryBinding->DeviceNameOffset = BytesCopied; QueryBinding->DeviceNameLength = AdapterContext->DeviceName.Length; RtlCopyMemory((PUCHAR)QueryBinding + QueryBinding->DeviceNameOffset, AdapterContext->DeviceName.Buffer, QueryBinding->DeviceNameLength); BytesCopied += AdapterContext->DeviceName.Length;
/* FIXME: Copy description too */ QueryBinding->DeviceDescrOffset = BytesCopied; QueryBinding->DeviceDescrLength = 0;
/* Successful */ Status = STATUS_SUCCESS; } else { /* Not enough buffer space */ Status = STATUS_BUFFER_TOO_SMALL; } } else { /* Invalid index */ Status = STATUS_NO_MORE_ENTRIES; } } else { /* Invalid parameters */ Status = STATUS_INVALID_PARAMETER; }
Irp->IoStatus.Status = Status; Irp->IoStatus.Information = BytesCopied;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;}
#if 0staticNTSTATUSCancelPacketRead(PIRP Irp, PIO_STACK_LOCATION IrpSp){ PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext; PNDISUIO_PACKET_ENTRY PacketEntry; NTSTATUS Status;
/* Indicate a 0-byte packet on the queue so one read returns 0 */ PacketEntry = ExAllocatePool(PagedPool, sizeof(NDISUIO_PACKET_ENTRY)); if (PacketEntry) { PacketEntry->PacketLength = 0;
ExInterlockedInsertHeadList(&AdapterContext->PacketList, &PacketEntry->ListEntry, &AdapterContext->Spinlock);
KeSetEvent(&AdapterContext->PacketReadEvent, IO_NO_INCREMENT, FALSE);
Status = STATUS_SUCCESS; } else { Status = STATUS_NO_MEMORY; }
Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;}#endif
staticNTSTATUSSetAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp){ PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext; PNDISUIO_SET_OID SetOidRequest; NDIS_REQUEST Request; ULONG RequestLength; NDIS_STATUS Status;
Irp->IoStatus.Information = 0;
SetOidRequest = Irp->AssociatedIrp.SystemBuffer; RequestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; if (SetOidRequest && RequestLength >= sizeof(NDIS_OID)) { /* Setup the NDIS request */ Request.RequestType = NdisRequestSetInformation; Request.DATA.SET_INFORMATION.Oid = SetOidRequest->Oid; Request.DATA.SET_INFORMATION.InformationBufferLength = RequestLength - sizeof(NDIS_OID); if (Request.DATA.SET_INFORMATION.InformationBufferLength != 0) { Request.DATA.SET_INFORMATION.InformationBuffer = SetOidRequest->Data; } else { Request.DATA.SET_INFORMATION.InformationBuffer = NULL; } Request.DATA.SET_INFORMATION.BytesRead = 0;
DPRINT("Setting OID 0x%x on adapter %wZ\n", SetOidRequest->Oid, &AdapterContext->DeviceName);
/* Dispatch the request */ NdisRequest(&Status, AdapterContext->BindingHandle, &Request);
/* Wait for the request */ if (Status == NDIS_STATUS_PENDING) { KeWaitForSingleObject(&AdapterContext->AsyncEvent, Executive, KernelMode, FALSE, NULL); Status = AdapterContext->AsyncStatus; }
/* Return the bytes read */ if (Status == NDIS_STATUS_INVALID_LENGTH || Status == NDIS_STATUS_BUFFER_TOO_SHORT) { Status = STATUS_BUFFER_TOO_SMALL; } else if (Status == NDIS_STATUS_SUCCESS) { Irp->IoStatus.Information = sizeof(NDIS_OID) + Request.DATA.SET_INFORMATION.BytesRead; }
DPRINT("Final request status: 0x%x (%d)\n", Status, Irp->IoStatus.Information); } else { /* Bad parameters */ Status = STATUS_INVALID_PARAMETER; }
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;}
staticNTSTATUSQueryAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp){ PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext; PNDISUIO_QUERY_OID QueryOidRequest; NDIS_REQUEST Request; ULONG RequestLength; NDIS_STATUS Status;
Irp->IoStatus.Information = 0;
QueryOidRequest = Irp->AssociatedIrp.SystemBuffer; RequestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; if (QueryOidRequest && RequestLength >= sizeof(NDIS_OID)) { /* Setup the NDIS request */ Request.RequestType = NdisRequestQueryInformation; Request.DATA.QUERY_INFORMATION.Oid = QueryOidRequest->Oid; Request.DATA.QUERY_INFORMATION.InformationBufferLength = RequestLength - sizeof(NDIS_OID); if (Request.DATA.QUERY_INFORMATION.InformationBufferLength != 0) { Request.DATA.QUERY_INFORMATION.InformationBuffer = QueryOidRequest->Data; } else { Request.DATA.QUERY_INFORMATION.InformationBuffer = NULL; } Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
DPRINT("Querying OID 0x%x on adapter %wZ\n", QueryOidRequest->Oid, &AdapterContext->DeviceName);
/* Dispatch the request */ NdisRequest(&Status, AdapterContext->BindingHandle, &Request);
/* Wait for the request */ if (Status == NDIS_STATUS_PENDING) { KeWaitForSingleObject(&AdapterContext->AsyncEvent, Executive, KernelMode, FALSE, NULL); Status = AdapterContext->AsyncStatus; }
/* Return the bytes written */ if (Status == NDIS_STATUS_INVALID_LENGTH || Status == NDIS_STATUS_BUFFER_TOO_SHORT) { Status = STATUS_BUFFER_TOO_SMALL; } else if (Status == NDIS_STATUS_SUCCESS) { Irp->IoStatus.Information = sizeof(NDIS_OID) + Request.DATA.QUERY_INFORMATION.BytesWritten; }
DPRINT("Final request status: 0x%x (%d)\n", Status, Irp->IoStatus.Information); } else { /* Bad parameters */ Status = STATUS_INVALID_PARAMETER; }
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;}
staticNTSTATUSOpenDeviceReadWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp){ PFILE_OBJECT FileObject = IrpSp->FileObject; UNICODE_STRING DeviceName; ULONG NameLength; NTSTATUS Status; PNDISUIO_ADAPTER_CONTEXT AdapterContext; PNDISUIO_OPEN_ENTRY OpenEntry; KIRQL OldIrql;
NameLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; if (NameLength != 0) { DeviceName.MaximumLength = DeviceName.Length = NameLength; DeviceName.Buffer = Irp->AssociatedIrp.SystemBuffer;
/* Check if this already has a context */ AdapterContext = FindAdapterContextByName(&DeviceName); if (AdapterContext != NULL) { DPRINT("Binding file object 0x%x to device %wZ\n", FileObject, &AdapterContext->DeviceName);
/* Reference the adapter context */ KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql); if (AdapterContext->OpenCount != 0) { /* An open for read-write is exclusive, * so we can't have any other open handles */ KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); Status = STATUS_INVALID_PARAMETER; } else { /* Add a reference */ ReferenceAdapterContext(AdapterContext); Status = STATUS_SUCCESS; } } else { /* Invalid device name */ Status = STATUS_INVALID_PARAMETER; }
/* Check that the bind succeeded */ if (NT_SUCCESS(Status)) { OpenEntry = ExAllocatePool(NonPagedPool, sizeof(*OpenEntry)); if (OpenEntry) { /* Set the file object pointer */ OpenEntry->FileObject = FileObject;
/* Set the permissions */ OpenEntry->WriteOnly = FALSE;
/* Associate this FO with the adapter */ FileObject->FsContext = AdapterContext; FileObject->FsContext2 = OpenEntry;
/* Add it to the adapter's list */ InsertTailList(&AdapterContext->OpenEntryList, &OpenEntry->ListEntry);
/* Success */ KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); Status = STATUS_SUCCESS; } else { /* Remove the reference we added */ KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); DereferenceAdapterContextWithOpenEntry(AdapterContext, NULL); Status = STATUS_NO_MEMORY; } } } else { /* Invalid device name */ Status = STATUS_INVALID_PARAMETER; }
Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;}
#if 0staticNTSTATUSOpenDeviceWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp){ PFILE_OBJECT FileObject = IrpSp->FileObject; UNICODE_STRING DeviceName; ULONG NameLength; NTSTATUS Status; PNDISUIO_ADAPTER_CONTEXT AdapterContext; PNDISUIO_OPEN_ENTRY OpenEntry; KIRQL OldIrql;
NameLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; if (NameLength != 0) { DeviceName.MaximumLength = DeviceName.Length = NameLength; DeviceName.Buffer = Irp->AssociatedIrp.SystemBuffer;
/* Check if this already has a context */ AdapterContext = FindAdapterContextByName(&DeviceName); if (AdapterContext != NULL) { /* Reference the adapter context */ KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql); ReferenceAdapterContext(AdapterContext); Status = STATUS_SUCCESS; } else { /* Invalid device name */ Status = STATUS_INVALID_PARAMETER; }
/* Check that the bind succeeded */ if (NT_SUCCESS(Status)) { OpenEntry = ExAllocatePool(NonPagedPool, sizeof(*OpenEntry)); if (OpenEntry) { /* Set the file object pointer */ OpenEntry->FileObject = FileObject;
/* Associate this FO with the adapter */ FileObject->FsContext = AdapterContext; FileObject->FsContext2 = OpenEntry;
/* Set permissions */ OpenEntry->WriteOnly = TRUE;
/* Add it to the adapter's list */ InsertTailList(&AdapterContext->OpenEntryList, &OpenEntry->ListEntry);
/* Success */ KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); Status = STATUS_SUCCESS; } else { /* Remove the reference we added */ KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql); DereferenceAdapterContext(AdapterContext, NULL); Status = STATUS_NO_MEMORY; } } } else { /* Invalid device name */ Status = STATUS_INVALID_PARAMETER; }
Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;}#endif
NTSTATUSNTAPINduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp){ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PNDISUIO_OPEN_ENTRY OpenEntry;
ASSERT(DeviceObject == GlobalDeviceObject);
/* Handle open IOCTLs first */ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_NDISUIO_OPEN_DEVICE: return OpenDeviceReadWrite(Irp, IrpSp);#if 0 case IOCTL_NDISUIO_OPEN_WRITE_DEVICE: return OpenDeviceWrite(Irp, IrpSp);#endif case IOCTL_NDISUIO_BIND_WAIT: return WaitForBind(Irp, IrpSp);
case IOCTL_NDISUIO_QUERY_BINDING: return QueryBinding(Irp, IrpSp);
default: /* Fail if this file object has no adapter associated */ if (IrpSp->FileObject->FsContext == NULL) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INVALID_PARAMETER; }
/* Now handle write IOCTLs */ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_NDISUIO_SET_OID_VALUE: return SetAdapterOid(Irp, IrpSp);
default: /* Check that we have read permissions */ OpenEntry = IrpSp->FileObject->FsContext2; if (OpenEntry->WriteOnly) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INVALID_PARAMETER; }
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {#if 0 case IOCTL_CANCEL_READ: return CancelPacketRead(Irp, IrpSp);#endif
case IOCTL_NDISUIO_QUERY_OID_VALUE: return QueryAdapterOid(Irp, IrpSp);
default: DPRINT1("Unimplemented\n"); Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NOT_IMPLEMENTED; } } break; }}