reactos/ntoskrnl/lpc/create.c

252 lines
7.5 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/lpc/create.c
* PURPOSE: Local Procedure Call: Port/Queue/Message Creation
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* PRIVATE FUNCTIONS *********************************************************/
NTSTATUS
NTAPI
LpcpInitializePortQueue(IN PLPCP_PORT_OBJECT Port)
{
PLPCP_NONPAGED_PORT_QUEUE MessageQueue;
PAGED_CODE();
/* Allocate the queue */
MessageQueue = ExAllocatePoolWithTag(NonPagedPool,
sizeof(*MessageQueue),
'troP');
if (!MessageQueue) return STATUS_INSUFFICIENT_RESOURCES;
/* Set it up */
KeInitializeSemaphore(&MessageQueue->Semaphore, 0, MAXLONG);
MessageQueue->BackPointer = Port;
/* And link it with the Paged Pool part */
Port->MsgQueue.Semaphore = &MessageQueue->Semaphore;
InitializeListHead(&Port->MsgQueue.ReceiveHead);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
LpcpCreatePort(OUT PHANDLE PortHandle,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN ULONG MaxConnectionInfoLength,
IN ULONG MaxMessageLength,
IN ULONG MaxPoolUsage,
IN BOOLEAN Waitable)
{
NTSTATUS Status;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
UNICODE_STRING CapturedObjectName, *ObjectName;
PLPCP_PORT_OBJECT Port;
HANDLE Handle;
PAGED_CODE();
LPCTRACE(LPC_CREATE_DEBUG, "Name: %wZ\n", ObjectAttributes->ObjectName);
RtlInitEmptyUnicodeString(&CapturedObjectName, NULL, 0);
/* Check if the call comes from user mode */
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
/* Probe the PortHandle */
ProbeForWriteHandle(PortHandle);
/* Probe the ObjectAttributes and its object name (not the buffer) */
ProbeForRead(ObjectAttributes, sizeof(*ObjectAttributes), sizeof(ULONG));
ObjectName = ((volatile OBJECT_ATTRIBUTES*)ObjectAttributes)->ObjectName;
if (ObjectName)
{
ProbeForRead(ObjectName, sizeof(*ObjectName), 1);
CapturedObjectName = *(volatile UNICODE_STRING*)ObjectName;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
else
{
if (ObjectAttributes->ObjectName)
CapturedObjectName = *(ObjectAttributes->ObjectName);
}
/* Normalize the buffer pointer in case we don't have a name */
if (CapturedObjectName.Length == 0)
CapturedObjectName.Buffer = NULL;
/* Create the Object */
Status = ObCreateObject(PreviousMode,
LpcPortObjectType,
ObjectAttributes,
PreviousMode,
NULL,
sizeof(LPCP_PORT_OBJECT),
0,
0,
(PVOID*)&Port);
if (!NT_SUCCESS(Status)) return Status;
/* Set up the Object */
RtlZeroMemory(Port, sizeof(LPCP_PORT_OBJECT));
Port->ConnectionPort = Port;
Port->Creator = PsGetCurrentThread()->Cid;
InitializeListHead(&Port->LpcDataInfoChainHead);
InitializeListHead(&Port->LpcReplyChainHead);
/* Check if we don't have a name */
if (CapturedObjectName.Buffer == NULL)
{
/* Set up for an unconnected port */
Port->Flags = LPCP_UNCONNECTED_PORT;
Port->ConnectedPort = Port;
Port->ServerProcess = NULL;
}
else
{
/* Set up for a named connection port */
Port->Flags = LPCP_CONNECTION_PORT;
Port->ServerProcess = PsGetCurrentProcess();
/* Don't let the process die on us */
ObReferenceObject(Port->ServerProcess);
}
/* Check if this is a waitable port */
if (Waitable) Port->Flags |= LPCP_WAITABLE_PORT;
/* Setup the port queue */
Status = LpcpInitializePortQueue(Port);
if (!NT_SUCCESS(Status))
{
/* Fail */
ObDereferenceObject(Port);
return Status;
}
/* Check if this is a waitable port */
if (Port->Flags & LPCP_WAITABLE_PORT)
{
/* Setup the wait event */
KeInitializeEvent(&Port->WaitEvent, NotificationEvent, FALSE);
}
/* Set the maximum message size allowed */
Port->MaxMessageLength = LpcpMaxMessageSize -
FIELD_OFFSET(LPCP_MESSAGE, Request);
/* Now subtract the actual message structures and get the data size */
Port->MaxConnectionInfoLength = Port->MaxMessageLength -
sizeof(PORT_MESSAGE) -
sizeof(LPCP_CONNECTION_MESSAGE);
/* Validate the sizes */
if (Port->MaxConnectionInfoLength < MaxConnectionInfoLength)
{
/* Not enough space for your request */
ObDereferenceObject(Port);
return STATUS_INVALID_PARAMETER_3;
}
else if (Port->MaxMessageLength < MaxMessageLength)
{
/* Not enough space for your request */
ObDereferenceObject(Port);
return STATUS_INVALID_PARAMETER_4;
}
/* Now set the custom setting */
Port->MaxMessageLength = MaxMessageLength;
/* Insert it now */
Status = ObInsertObject(Port,
NULL,
PORT_ALL_ACCESS,
0,
NULL,
&Handle);
if (NT_SUCCESS(Status))
{
_SEH2_TRY
{
/* Write back the handle, pointer was already probed */
*PortHandle = Handle;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* An exception happened, close the opened handle */
ObCloseHandle(Handle, PreviousMode);
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
/* Return success or the error */
LPCTRACE(LPC_CREATE_DEBUG, "Port: %p. Handle: %p\n", Port, Handle);
return Status;
}
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @implemented
*/
NTSTATUS
NTAPI
NtCreatePort(OUT PHANDLE PortHandle,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN ULONG MaxConnectInfoLength,
IN ULONG MaxDataLength,
IN ULONG MaxPoolUsage)
{
PAGED_CODE();
/* Call the internal API */
return LpcpCreatePort(PortHandle,
ObjectAttributes,
MaxConnectInfoLength,
MaxDataLength,
MaxPoolUsage,
FALSE);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtCreateWaitablePort(OUT PHANDLE PortHandle,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN ULONG MaxConnectInfoLength,
IN ULONG MaxDataLength,
IN ULONG MaxPoolUsage)
{
PAGED_CODE();
/* Call the internal API */
return LpcpCreatePort(PortHandle,
ObjectAttributes,
MaxConnectInfoLength,
MaxDataLength,
MaxPoolUsage,
TRUE);
}
/* EOF */