--- /dev/null
+/*
+ * 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 */