/* * 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 #define NDEBUG #include /* PRIVATE FUNCTIONS *********************************************************/ NTSTATUS NTAPI LpcpInitializePortQueue(IN PLPCP_PORT_OBJECT Port) { PLPCP_NONPAGED_PORT_QUEUE MessageQueue; PAGED_CODE(); /* Allocate the queue */ MessageQueue = ExAllocatePoolWithTag(NonPagedPool, sizeof(LPCP_NONPAGED_PORT_QUEUE), '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) { KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); NTSTATUS Status; PLPCP_PORT_OBJECT Port; HANDLE Handle; PUNICODE_STRING ObjectName; BOOLEAN NoName; PAGED_CODE(); LPCTRACE(LPC_CREATE_DEBUG, "Name: %wZ\n", ObjectAttributes->ObjectName); /* Check if the call comes from user mode */ if (PreviousMode != KernelMode) { _SEH2_TRY { /* Probe the PortHandle */ ProbeForWriteHandle(PortHandle); /* Probe the ObjectAttributes */ ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG)); /* Get the object name and probe the unicode string */ ObjectName = ObjectAttributes->ObjectName; ProbeForRead(ObjectName, sizeof(UNICODE_STRING), 1); /* Check if we have no name */ NoName = (ObjectName->Buffer == NULL) || (ObjectName->Length == 0); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; } else { /* Check if we have no name */ NoName = (ObjectAttributes->ObjectName->Buffer == NULL) || (ObjectAttributes->ObjectName->Length == 0); } /* 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 (NoName) { /* 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((PVOID)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) { ObCloseHandle(Handle, UserMode); 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 */