* 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)
*/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
NTSTATUS
NTAPI
LpcpInitializePortQueue(IN PLPCP_PORT_OBJECT Port)
{
PLPCP_NONPAGED_PORT_QUEUE MessageQueue;
PAGED_CODE();
MessageQueue = ExAllocatePoolWithTag(NonPagedPool,
sizeof(*MessageQueue),
'troP');
if (!MessageQueue) return STATUS_INSUFFICIENT_RESOURCES;
KeInitializeSemaphore(&MessageQueue->Semaphore, 0, MAXLONG);
MessageQueue->BackPointer = Port;
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;
#if DBG
UNICODE_STRING CapturedPortName;
#endif
PLPCP_PORT_OBJECT Port;
HANDLE Handle;
PAGED_CODE();
RtlInitEmptyUnicodeString(&CapturedObjectName, NULL, 0);
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
ProbeForWriteHandle(PortHandle);
ProbeForRead(ObjectAttributes, sizeof(*ObjectAttributes), sizeof(ULONG));
ObjectName = ((volatile OBJECT_ATTRIBUTES*)ObjectAttributes)->ObjectName;
if (ObjectName)
CapturedObjectName = ProbeForReadUnicodeString(ObjectName);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
else
{
ObjectName = ObjectAttributes->ObjectName;
if (ObjectName)
CapturedObjectName = *ObjectName;
}
* a name, for initializing an unconnected port. */
if (CapturedObjectName.Length == 0)
CapturedObjectName.Buffer = NULL;
#if DBG
* own capture. As it is used only for debugging, ignore any failure;
* the string is zeroed out in such case. */
ProbeAndCaptureUnicodeString(&CapturedPortName, PreviousMode, ObjectName);
LPCTRACE(LPC_CREATE_DEBUG, "Name: %wZ\n", &CapturedPortName);
ReleaseCapturedUnicodeString(&CapturedPortName, PreviousMode);
#endif
Status = ObCreateObject(PreviousMode,
LpcPortObjectType,
ObjectAttributes,
PreviousMode,
NULL,
sizeof(LPCP_PORT_OBJECT),
0,
0,
(PVOID*)&Port);
if (!NT_SUCCESS(Status)) return Status;
RtlZeroMemory(Port, sizeof(LPCP_PORT_OBJECT));
Port->ConnectionPort = Port;
Port->Creator = PsGetCurrentThread()->Cid;
InitializeListHead(&Port->LpcDataInfoChainHead);
InitializeListHead(&Port->LpcReplyChainHead);
if (CapturedObjectName.Buffer == NULL)
{
Port->Flags = LPCP_UNCONNECTED_PORT;
Port->ConnectedPort = Port;
Port->ServerProcess = NULL;
}
else
{
Port->Flags = LPCP_CONNECTION_PORT;
Port->ServerProcess = PsGetCurrentProcess();
ObReferenceObject(Port->ServerProcess);
}
if (Waitable) Port->Flags |= LPCP_WAITABLE_PORT;
Status = LpcpInitializePortQueue(Port);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Port);
return Status;
}
if (Port->Flags & LPCP_WAITABLE_PORT)
{
KeInitializeEvent(&Port->WaitEvent, NotificationEvent, FALSE);
}
Port->MaxMessageLength = LpcpMaxMessageSize -
FIELD_OFFSET(LPCP_MESSAGE, Request);
Port->MaxConnectionInfoLength = Port->MaxMessageLength -
sizeof(PORT_MESSAGE) -
sizeof(LPCP_CONNECTION_MESSAGE);
if (Port->MaxConnectionInfoLength < MaxConnectionInfoLength)
{
ObDereferenceObject(Port);
return STATUS_INVALID_PARAMETER_3;
}
else if (Port->MaxMessageLength < MaxMessageLength)
{
ObDereferenceObject(Port);
return STATUS_INVALID_PARAMETER_4;
}
Port->MaxMessageLength = MaxMessageLength;
Status = ObInsertObject(Port,
NULL,
PORT_ALL_ACCESS,
0,
NULL,
&Handle);
if (NT_SUCCESS(Status))
{
_SEH2_TRY
{
*PortHandle = Handle;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ObCloseHandle(Handle, PreviousMode);
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
LPCTRACE(LPC_CREATE_DEBUG, "Port: %p. Handle: %p\n", Port, Handle);
return Status;
}
* @implemented
*/
NTSTATUS
NTAPI
NtCreatePort(OUT PHANDLE PortHandle,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN ULONG MaxConnectInfoLength,
IN ULONG MaxDataLength,
IN ULONG MaxPoolUsage)
{
PAGED_CODE();
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();
return LpcpCreatePort(PortHandle,
ObjectAttributes,
MaxConnectInfoLength,
MaxDataLength,
MaxPoolUsage,
TRUE);
}