2011-06-17 11:04:45 +00:00
|
|
|
/*
|
2013-08-06 01:12:08 +00:00
|
|
|
* PROJECT: ReactOS Drivers
|
|
|
|
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
|
|
|
* FILE: drivers/sac/driver/chanmgr.c
|
|
|
|
* PURPOSE: Driver for the Server Administration Console (SAC) for EMS
|
|
|
|
* PROGRAMMERS: ReactOS Portable Systems Group
|
2011-06-17 11:04:45 +00:00
|
|
|
*/
|
|
|
|
|
2013-10-13 19:40:34 +00:00
|
|
|
/* INCLUDES *******************************************************************/
|
2011-06-17 11:04:45 +00:00
|
|
|
|
|
|
|
#include "sacdrv.h"
|
|
|
|
|
2013-10-13 19:40:34 +00:00
|
|
|
/* GLOBALS ********************************************************************/
|
2011-06-17 11:04:45 +00:00
|
|
|
|
2013-08-06 01:12:08 +00:00
|
|
|
SAC_CHANNEL_LOCK ChannelCreateLock;
|
|
|
|
BOOLEAN ChannelCreateEnabled;
|
|
|
|
PSAC_CHANNEL ChannelArray[SAC_MAX_CHANNELS];
|
|
|
|
LONG ChannelRefCount[SAC_MAX_CHANNELS];
|
|
|
|
LONG ChannelReaped[SAC_MAX_CHANNELS];
|
|
|
|
SAC_CHANNEL_LOCK ChannelSlotLock[SAC_MAX_CHANNELS];
|
2011-06-17 11:04:45 +00:00
|
|
|
|
2013-10-13 19:40:34 +00:00
|
|
|
/* FUNCTIONS ******************************************************************/
|
2013-08-06 01:12:08 +00:00
|
|
|
|
|
|
|
#define MAX_REF_COUNT 100
|
|
|
|
|
|
|
|
#define CHANNEL_SLOT_IS_IN_USE(x) (ChannelRefCount[(x)] > 0)
|
|
|
|
|
|
|
|
FORCEINLINE
|
|
|
|
PSAC_CHANNEL
|
|
|
|
ChannelFromIndex(IN ULONG Index)
|
|
|
|
{
|
|
|
|
return ChannelArray[Index];
|
|
|
|
}
|
|
|
|
|
|
|
|
FORCEINLINE
|
|
|
|
LONG
|
|
|
|
ChannelGetReferenceCount(IN LONG Index)
|
|
|
|
{
|
|
|
|
return ChannelRefCount[Index];
|
|
|
|
}
|
|
|
|
|
|
|
|
FORCEINLINE
|
|
|
|
LONG
|
|
|
|
ChannelReferenceByIndex(IN LONG Index)
|
|
|
|
{
|
|
|
|
if (ChannelGetReferenceCount(Index) > 0)
|
|
|
|
{
|
|
|
|
ASSERT(ChannelRefCount[Index] <= MAX_REF_COUNT);
|
|
|
|
ASSERT(ChannelRefCount[Index] >= 1);
|
|
|
|
_InterlockedIncrement(&ChannelRefCount[Index]);
|
|
|
|
ASSERT(ChannelRefCount[Index] <= MAX_REF_COUNT);
|
|
|
|
ASSERT(ChannelRefCount[Index] >= 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ChannelGetReferenceCount(Index);
|
|
|
|
}
|
|
|
|
|
|
|
|
FORCEINLINE
|
|
|
|
LONG
|
|
|
|
ChannelReferenceByIndexWithLock(IN LONG Index)
|
|
|
|
{
|
|
|
|
LONG RefCount;
|
|
|
|
|
|
|
|
ChannelSlotLock(Index);
|
|
|
|
RefCount = ChannelReferenceByIndex(Index);
|
|
|
|
ChannelSlotUnlock(Index);
|
|
|
|
return RefCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
FORCEINLINE
|
|
|
|
LONG
|
|
|
|
ChannelDereferenceByIndex(IN LONG Index)
|
|
|
|
{
|
|
|
|
ASSERT(ChannelGetReferenceCount(Index) <= MAX_REF_COUNT);
|
|
|
|
ASSERT(ChannelGetReferenceCount(Index) > 1);
|
|
|
|
_InterlockedDecrement(&ChannelRefCount[Index]);
|
|
|
|
ASSERT(ChannelGetReferenceCount(Index) >= 1);
|
|
|
|
return ChannelGetReferenceCount(Index);
|
|
|
|
}
|
|
|
|
|
|
|
|
FORCEINLINE
|
|
|
|
VOID
|
|
|
|
ChannelDereferenceByIndexWithLock(IN LONG Index)
|
|
|
|
{
|
|
|
|
ChannelSlotLock(Index);
|
|
|
|
ChannelDereferenceByIndex(Index);
|
|
|
|
ChannelSlotUnlock(Index);
|
|
|
|
}
|
|
|
|
|
|
|
|
FORCEINLINE
|
|
|
|
VOID
|
|
|
|
ChannelDereferenceToZeroByIndex(IN LONG Index)
|
|
|
|
{
|
|
|
|
ASSERT(ChannelGetReferenceCount(Index) == 1);
|
|
|
|
ASSERT(ChannelIsActive(ChannelFromIndex(Index)) == FALSE);
|
|
|
|
_InterlockedExchange(&ChannelRefCount[Index], 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
FORCEINLINE
|
|
|
|
VOID
|
|
|
|
ChannelReferenceToOneByIndex(IN LONG Index)
|
|
|
|
{
|
|
|
|
ASSERT(ChannelGetReferenceCount(Index) == 0);
|
|
|
|
_InterlockedExchange(&ChannelRefCount[Index], 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
FORCEINLINE
|
|
|
|
VOID
|
|
|
|
ChannelReferenceToOneByIndexWithLock(IN LONG Index)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
ChannelSlotLock(Index);
|
2013-08-14 04:20:17 +00:00
|
|
|
ChannelReferenceToOneByIndex(Index);
|
2013-08-06 01:12:08 +00:00
|
|
|
ChannelSlotUnlock(Index);
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrInitialize(VOID)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
/* Initialize the channel lock */
|
|
|
|
SacInitializeLock(&ChannelCreateLock);
|
|
|
|
ChannelCreateEnabled = TRUE;
|
|
|
|
|
|
|
|
/* Loop through the channel arrays */
|
|
|
|
for (i = 0; i < SAC_MAX_CHANNELS; i++)
|
|
|
|
{
|
|
|
|
/* Clear and initialize their locks */
|
|
|
|
ChannelArray[i] = NULL;
|
|
|
|
SacInitializeLock(&ChannelSlotLock[i]);
|
|
|
|
|
|
|
|
/* Clear their statuses and reference counts */
|
|
|
|
_InterlockedExchange(&ChannelRefCount[i], 0);
|
|
|
|
_InterlockedExchange(&ChannelReaped[i], 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All good */
|
|
|
|
return STATUS_SUCCESS;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrShutdown(VOID)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
/* FIXME: TODO */
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrGetChannelByName(IN PWCHAR Name,
|
|
|
|
OUT PSAC_CHANNEL* Channel)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
NTSTATUS Status, Status1;
|
|
|
|
ULONG i;
|
|
|
|
PSAC_CHANNEL CurrentChannel;
|
|
|
|
PWCHAR ChannelName;
|
|
|
|
BOOLEAN Found;
|
|
|
|
CHECK_PARAMETER1(Name);
|
|
|
|
CHECK_PARAMETER2(Channel);
|
|
|
|
|
|
|
|
/* Assume failure */
|
|
|
|
*Channel = NULL;
|
|
|
|
Status = STATUS_NOT_FOUND;
|
|
|
|
|
|
|
|
/* Loop through all channels */
|
|
|
|
for (i = 0; i < SAC_MAX_CHANNELS; i++)
|
|
|
|
{
|
|
|
|
/* Reference this one and check if it's valid */
|
|
|
|
if (ChannelReferenceByIndexWithLock(i) > 0)
|
|
|
|
{
|
|
|
|
/* All good, grab it */
|
|
|
|
CurrentChannel = ChannelFromIndex(i);
|
|
|
|
ASSERT(CurrentChannel != NULL);
|
|
|
|
|
|
|
|
/* Get its name */
|
|
|
|
Status1 = ChannelGetName(CurrentChannel, &ChannelName);
|
|
|
|
ASSERT(NT_SUCCESS(Status1));
|
|
|
|
|
|
|
|
/* Check if this is the name that was passed in */
|
|
|
|
Found = wcsicmp(Name, ChannelName);
|
|
|
|
SacFreePool(ChannelName);
|
|
|
|
if (Found)
|
|
|
|
{
|
|
|
|
/* We found it, return it (with a reference held) */
|
|
|
|
*Channel = CurrentChannel;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Not the one we want, dereference this one and keep going */
|
|
|
|
ChannelDereferenceByIndexWithLock(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No channels with this name were found */
|
|
|
|
return Status;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrGetByHandle(IN SAC_CHANNEL_ID ChannelId,
|
|
|
|
OUT PSAC_CHANNEL* TargetChannel)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
ULONG i;
|
|
|
|
PSAC_CHANNEL Channel;
|
|
|
|
CHECK_PARAMETER2(TargetChannel);
|
|
|
|
|
|
|
|
/* Assume failure */
|
|
|
|
*TargetChannel = NULL;
|
|
|
|
Status = STATUS_NOT_FOUND;
|
|
|
|
|
|
|
|
/* Loop through all channels */
|
|
|
|
for (i = 0; i < SAC_MAX_CHANNELS; i++)
|
|
|
|
{
|
|
|
|
/* Reference this one and check if it's valid */
|
|
|
|
if (ChannelReferenceByIndexWithLock(i) > 0)
|
|
|
|
{
|
|
|
|
/* All good, grab it */
|
|
|
|
Channel = ChannelFromIndex(i);
|
|
|
|
ASSERT(Channel != NULL);
|
|
|
|
|
|
|
|
/* Check if the channel ID matches */
|
|
|
|
if (ChannelIsEqual(Channel, &ChannelId))
|
|
|
|
{
|
|
|
|
/* We found it, return it (with a reference held) */
|
|
|
|
*TargetChannel = Channel;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Not the one we want, dereference this one and keep going */
|
|
|
|
ChannelDereferenceByIndexWithLock(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No channels with this ID were found */
|
|
|
|
return Status;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrReleaseChannel(IN PSAC_CHANNEL Channel)
|
|
|
|
{
|
|
|
|
LONG Index;
|
|
|
|
ULONG RefCount;
|
|
|
|
PSAC_CHANNEL ThisChannel;
|
|
|
|
CHECK_PARAMETER(Channel);
|
|
|
|
|
|
|
|
/* Get the index of the channel */
|
|
|
|
Index = ChannelGetIndex(Channel);
|
|
|
|
|
|
|
|
/* Drop a reference -- there should still be at least the keepalive left */
|
|
|
|
ChannelSlotLock(Index);
|
|
|
|
RefCount = ChannelDereferenceByIndex(Index);
|
|
|
|
ASSERT(RefCount > 0);
|
|
|
|
|
|
|
|
/* Do we only have the keep-alive left, and the channel is dead? */
|
|
|
|
if ((RefCount == 1) && !(ChannelIsActive(Channel)))
|
|
|
|
{
|
|
|
|
/* Check if the ??? flag is set, or if there's no output data */
|
|
|
|
ThisChannel = ChannelFromIndex(Index);
|
|
|
|
if (!(ThisChannel->Flags & 1))
|
|
|
|
{
|
|
|
|
/* Nope, we can wipe the references and get rid of it */
|
|
|
|
ChannelDereferenceToZeroByIndex(Index);
|
|
|
|
}
|
|
|
|
else if (!ThisChannel->ChannelHasNewOBufferData)
|
|
|
|
{
|
|
|
|
/* No data, we can wipe the references and get rid of it */
|
|
|
|
ChannelDereferenceToZeroByIndex(Index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We're done, we can unlock the slot now */
|
|
|
|
ChannelSlotUnlock(Index);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
|
|
|
ChanMgrIsUniqueName(IN PWCHAR ChannelName)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
BOOLEAN IsUnique = FALSE;
|
|
|
|
PSAC_CHANNEL Channel;
|
|
|
|
|
|
|
|
/* Check if a channel with this name already exists */
|
|
|
|
Status = ChanMgrGetChannelByName(ChannelName, &Channel);
|
|
|
|
if (Status == STATUS_NOT_FOUND) IsUnique = TRUE;
|
|
|
|
|
|
|
|
/* If one did, dereference it, all we wanted was to check uniqueness */
|
|
|
|
if (NT_SUCCESS(Status)) ChanMgrReleaseChannel(Channel);
|
|
|
|
|
|
|
|
/* Return if one was found or not */
|
|
|
|
return IsUnique;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrReapChannel(IN ULONG ChannelIndex)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
/* FIXME: TODO */
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrReapChannels(VOID)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
ULONG i;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
/* Loop all the channels */
|
|
|
|
for (i = 0; i < SAC_MAX_CHANNELS; i++)
|
|
|
|
{
|
|
|
|
/* Lock this index and see if the channel was reaped */
|
|
|
|
ChannelSlotLock(i);
|
|
|
|
if (!ChannelReaped[i])
|
|
|
|
{
|
|
|
|
/* It was not reaped yet, so a channel should still be here */
|
|
|
|
ASSERT(ChannelFromIndex(i) != NULL);
|
|
|
|
if (ChannelGetReferenceCount(i) <= 0)
|
|
|
|
{
|
|
|
|
/* The channel has no more references, so clear the buffer flags */
|
|
|
|
_InterlockedExchange(&ChannelArray[i]->ChannelHasNewIBufferData, 0);
|
|
|
|
_InterlockedExchange(&ChannelArray[i]->ChannelHasNewOBufferData, 0);
|
|
|
|
|
|
|
|
/* And reap it */
|
|
|
|
Status = ChanMgrReapChannel(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Release the lock, and move on unless reaping failed */
|
|
|
|
ChannelSlotUnlock(i);
|
|
|
|
if (!NT_SUCCESS(Status)) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return reaping status */
|
|
|
|
return Status;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
2013-08-06 01:12:08 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
ChanMgrCreateChannel(OUT PSAC_CHANNEL *Channel,
|
|
|
|
IN PSAC_CHANNEL_ATTRIBUTES Attributes)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
PSAC_CHANNEL NewChannel;
|
|
|
|
SAC_CHANNEL_ID ChanId;
|
|
|
|
ULONG i;
|
|
|
|
CHECK_PARAMETER(Channel);
|
|
|
|
CHECK_PARAMETER2(Attributes);
|
|
|
|
|
|
|
|
/* No other channel create attempts can happen */
|
|
|
|
ChannelLockCreates();
|
|
|
|
|
|
|
|
/* Is the channel manager initialized? */
|
2013-08-14 04:20:17 +00:00
|
|
|
if (!ChannelCreateEnabled)
|
2013-08-06 01:12:08 +00:00
|
|
|
{
|
|
|
|
/* Nope, bail out */
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
|
|
goto ReturnStatus;
|
|
|
|
}
|
2011-06-17 11:04:45 +00:00
|
|
|
|
2013-08-06 01:12:08 +00:00
|
|
|
/* Reap any zombie channels */
|
|
|
|
Status = ChanMgrReapChannels();
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Bail out on error */
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
|
|
goto ReturnStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if we already have a channel with this name */
|
|
|
|
if (!ChanMgrIsUniqueName(Attributes->NameBuffer))
|
|
|
|
{
|
|
|
|
/* We do, fail */
|
|
|
|
Status = STATUS_DUPLICATE_NAME;
|
|
|
|
goto ReturnStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate this channel */
|
|
|
|
NewChannel = SacAllocatePool(sizeof(SAC_CHANNEL), CHANNEL_BLOCK_TAG);
|
|
|
|
CHECK_PARAMETER_WITH_STATUS(NewChannel, STATUS_NO_MEMORY); // bug
|
|
|
|
RtlZeroMemory(NewChannel, sizeof(SAC_CHANNEL));
|
|
|
|
|
|
|
|
/* Loop channel slots */
|
|
|
|
for (i = 0; i < SAC_MAX_CHANNELS; i++)
|
|
|
|
{
|
|
|
|
/* Find a free spot for it */
|
|
|
|
if (ChannelReaped[i])
|
|
|
|
{
|
|
|
|
/* Free slot found, attempt to use it */
|
|
|
|
ASSERT(!CHANNEL_SLOT_IS_IN_USE(i));
|
2018-04-23 09:27:49 +00:00
|
|
|
InterlockedCompareExchangePointer((PVOID*)&ChannelArray[i], NewChannel, NULL);
|
2013-08-06 01:12:08 +00:00
|
|
|
if (ChannelArray[i] == NewChannel) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Did we not find a single free slot? */
|
|
|
|
if (i == SAC_MAX_CHANNELS)
|
|
|
|
{
|
|
|
|
/* Bail out */
|
|
|
|
goto ReturnStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create an ID for this channel */
|
|
|
|
RtlZeroMemory(&ChanId, sizeof(ChanId));
|
|
|
|
Status = ExUuidCreate(&ChanId.ChannelGuid);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Bail out if we couldn't */
|
|
|
|
SAC_DBG(SAC_DBG_INIT, "SAC Create Channel :: Failed to get GUID\n");
|
|
|
|
goto ReturnStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now create the channel proper */
|
|
|
|
Status = ChannelCreate(NewChannel, Attributes, ChanId);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Set the channel index */
|
|
|
|
_InterlockedExchange(&NewChannel->Index, i);
|
|
|
|
|
|
|
|
/* Add the initial reference to the channel */
|
|
|
|
ChannelReferenceToOneByIndexWithLock(i);
|
|
|
|
|
|
|
|
/* Return it to the caller */
|
|
|
|
*Channel = NewChannel;
|
|
|
|
|
|
|
|
/* This slot is now occupied */
|
|
|
|
ASSERT(ChannelReaped[i] == 1);
|
|
|
|
_InterlockedExchange(&ChannelReaped[i], 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* We couldn't create it, free the buffer */
|
|
|
|
SacFreePool(NewChannel);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnStatus:
|
|
|
|
/* Return whatever the operation status was */
|
|
|
|
ChannelUnlockCreates();
|
|
|
|
return Status;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrGetByHandleAndFileObject(IN SAC_CHANNEL_ID ChannelId,
|
|
|
|
IN PFILE_OBJECT FileObject,
|
|
|
|
OUT PSAC_CHANNEL* TargetChannel)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
PSAC_CHANNEL FoundChannel;
|
|
|
|
|
|
|
|
/* Lookup the channel by ID first */
|
|
|
|
Status = ChanMgrGetByHandle(ChannelId, &FoundChannel);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* We found it, now check if the file object matches */
|
|
|
|
if (FoundChannel->FileObject == FileObject)
|
|
|
|
{
|
|
|
|
/* Yep, return success */
|
|
|
|
*TargetChannel = FoundChannel;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Nope, drop the reference on the channel */
|
|
|
|
ChanMgrReleaseChannel(FoundChannel);
|
|
|
|
|
|
|
|
/* And return failure */
|
|
|
|
*TargetChannel = NULL;
|
|
|
|
Status = STATUS_NOT_FOUND;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return if we found it or not */
|
|
|
|
return Status;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrGetChannelIndex(IN PSAC_CHANNEL Channel,
|
|
|
|
IN PLONG ChannelIndex)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
CHECK_PARAMETER1(Channel);
|
|
|
|
CHECK_PARAMETER2(ChannelIndex);
|
|
|
|
|
|
|
|
/* Just return the index of the channel */
|
|
|
|
*ChannelIndex = ChannelGetIndex(Channel);
|
|
|
|
return STATUS_SUCCESS;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrGetByIndex(IN LONG TargetIndex,
|
|
|
|
IN PSAC_CHANNEL* TargetChannel)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
CHECK_PARAMETER1(TargetIndex < SAC_MAX_CHANNELS);
|
|
|
|
CHECK_PARAMETER2(TargetChannel);
|
|
|
|
|
|
|
|
/* Assume failure */
|
|
|
|
*TargetChannel = NULL;
|
|
|
|
Status = STATUS_NOT_FOUND;
|
|
|
|
|
|
|
|
/* Reference this one and check if it's valid */
|
|
|
|
if (ChannelReferenceByIndexWithLock(TargetIndex) > 0)
|
|
|
|
{
|
|
|
|
/* We found it, return it (with a reference held) */
|
|
|
|
*TargetChannel = ChannelFromIndex(TargetIndex);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No channels with this ID were found */
|
|
|
|
return Status;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrGetNextActiveChannel(IN PSAC_CHANNEL CurrentChannel,
|
|
|
|
IN PULONG TargetIndex,
|
|
|
|
OUT PSAC_CHANNEL *TargetChannel)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
ULONG i;
|
|
|
|
LONG ChannelIndex, StartIndex;
|
|
|
|
PSAC_CHANNEL FoundChannel;
|
|
|
|
BOOLEAN ChannelFound;
|
|
|
|
CHECK_PARAMETER1(CurrentChannel);
|
|
|
|
CHECK_PARAMETER2(TargetIndex);
|
|
|
|
CHECK_PARAMETER3(TargetChannel);
|
|
|
|
|
|
|
|
/* Get the current channel index */
|
|
|
|
Status = ChanMgrGetChannelIndex(CurrentChannel, &ChannelIndex);
|
|
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
|
|
|
|
/* Assume failure */
|
|
|
|
ChannelFound = FALSE;
|
|
|
|
|
|
|
|
/* Loop through all the possible active channels */
|
|
|
|
StartIndex = (ChannelIndex + 1) % SAC_MAX_CHANNELS;
|
|
|
|
for (i = StartIndex; i != StartIndex; i = (i + 1) % SAC_MAX_CHANNELS)
|
|
|
|
{
|
|
|
|
/* Get the channel and see if it exists*/
|
|
|
|
Status = ChanMgrGetByIndex(i, &FoundChannel);
|
|
|
|
if (Status != STATUS_NOT_FOUND)
|
|
|
|
{
|
|
|
|
/* Bail out if we failed for some reason */
|
|
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
|
|
|
|
/* It exists -- is it active? Or, does it have output data? */
|
|
|
|
if ((ChannelIsActive(FoundChannel)) ||
|
|
|
|
(!(ChannelIsActive(FoundChannel)) &&
|
|
|
|
(FoundChannel->ChannelHasNewOBufferData)))
|
|
|
|
{
|
|
|
|
/* It's active or has output data, return with it */
|
|
|
|
ChannelFound = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Drop the reference on this channel and try the next one */
|
|
|
|
Status = ChanMgrReleaseChannel(FoundChannel);
|
|
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if we successfully found a channel */
|
|
|
|
if ((NT_SUCCESS(Status)) && (ChannelFound))
|
|
|
|
{
|
|
|
|
/* Return it and its indexed. Remember we still hold the reference */
|
|
|
|
*TargetIndex = i;
|
|
|
|
*TargetChannel = FoundChannel;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All done */
|
|
|
|
return Status;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrChannelDestroy(IN PSAC_CHANNEL Channel)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
CHECK_PARAMETER1(Channel);
|
|
|
|
CHECK_PARAMETER(ChannelGetReferenceCount(Channel->Index) > 0);
|
|
|
|
|
|
|
|
/* Destroy the channel */
|
|
|
|
return Channel->ChannelDestroy(Channel);
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrCloseChannel(IN PSAC_CHANNEL Channel)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
CHECK_PARAMETER(Channel);
|
|
|
|
|
|
|
|
/* Check if the channel is active */
|
|
|
|
if (ChannelIsActive(Channel))
|
|
|
|
{
|
|
|
|
/* Yep, close it */
|
|
|
|
Status = ChannelClose(Channel);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Nothing to do */
|
|
|
|
Status = STATUS_ALREADY_DISCONNECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle the channel close */
|
|
|
|
ConMgrHandleEvent(TRUE, Channel, &Status);
|
|
|
|
return Status;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
2013-08-06 01:12:08 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
ChanMgrGetChannelCount(OUT PULONG ChannelCount)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
ULONG i;
|
|
|
|
PSAC_CHANNEL Channel;
|
|
|
|
NTSTATUS Status;
|
|
|
|
CHECK_PARAMETER(ChannelCount);
|
|
|
|
|
|
|
|
/* Assume no channels */
|
|
|
|
*ChannelCount = 0;
|
|
|
|
|
|
|
|
/* Loop every channel */
|
|
|
|
for (i = 0; i < SAC_MAX_CHANNELS; i++)
|
|
|
|
{
|
|
|
|
/* See if this one exists */
|
|
|
|
Status = ChanMgrGetByIndex(i, &Channel);
|
|
|
|
if (Status != STATUS_NOT_FOUND)
|
|
|
|
{
|
|
|
|
/* Sanity checks*/
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
ASSERT(Channel != NULL);
|
|
|
|
|
|
|
|
/* It exists -- is it active? Or, does it have output data? */
|
|
|
|
if ((ChannelIsActive(Channel)) ||
|
|
|
|
(!(ChannelIsActive(Channel)) &&
|
|
|
|
(Channel->ChannelHasNewOBufferData)))
|
|
|
|
{
|
|
|
|
/* It's active or has output data, increase the count */
|
|
|
|
++*ChannelCount;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Drop the reference on this channel and try the next one */
|
|
|
|
Status = ChanMgrReleaseChannel(Channel);
|
|
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Channel doesn't exist, nothing wrong with that, keep going */
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We should always succeed if we get here */
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
return Status;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrIsFull(OUT PBOOLEAN IsFull)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
ULONG Count;
|
|
|
|
|
|
|
|
/* Count the channels */
|
|
|
|
Status = ChanMgrGetChannelCount(&Count);
|
|
|
|
CHECK_PARAMETER(Status == STATUS_SUCCESS);
|
|
|
|
|
|
|
|
/* Return if we hit the limit */
|
|
|
|
*IsFull = (Count == SAC_MAX_CHANNELS);
|
|
|
|
return Status;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrCloseChannelsWithFileObject(IN PFILE_OBJECT FileObject)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
PSAC_CHANNEL Channel;
|
|
|
|
ULONG i;
|
|
|
|
NTSTATUS Status;
|
|
|
|
CHECK_PARAMETER1(FileObject);
|
|
|
|
|
|
|
|
/* Loop all channels */
|
|
|
|
for (i = 0; i < SAC_MAX_CHANNELS; i++)
|
|
|
|
{
|
|
|
|
/* Try to get this one */
|
|
|
|
Status = ChanMgrGetByIndex(i, &Channel);
|
|
|
|
if (!NT_SUCCESS(Status)) break;
|
|
|
|
|
|
|
|
/* Check if the FO matches, if so, close the channel */
|
|
|
|
if (Channel->FileObject == FileObject) ChanMgrCloseChannel(Channel);
|
|
|
|
|
|
|
|
/* Drop the reference and try the next channel(s) */
|
|
|
|
Status = ChanMgrReleaseChannel(Channel);
|
|
|
|
if (!NT_SUCCESS(Status)) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All done */
|
|
|
|
return Status;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-08-06 01:12:08 +00:00
|
|
|
NTAPI
|
|
|
|
ChanMgrGenerateUniqueCmdName(IN PWCHAR ChannelName)
|
2011-06-17 11:04:45 +00:00
|
|
|
{
|
2013-08-06 01:12:08 +00:00
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
2011-06-17 11:04:45 +00:00
|
|
|
}
|