+++ /dev/null
-/*
- * PROJECT: ReactOS Kernel
- * LICENSE: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/lpc/reply.c
- * PURPOSE: Local Procedure Call: Receive (Replies)
- * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
- */
-
-/* INCLUDES ******************************************************************/
-
-#include <ntoskrnl.h>
-#define NDEBUG
-#include <debug.h>
-
-/* PRIVATE FUNCTIONS *********************************************************/
-
-VOID
-NTAPI
-LpcpFreeDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
- IN ULONG MessageId,
- IN ULONG CallbackId,
- IN CLIENT_ID ClientId)
-{
- PLPCP_MESSAGE Message;
- PLIST_ENTRY ListHead, NextEntry;
-
- /* Check if the port we want is the connection port */
- if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT)
- {
- /* Use it */
- Port = Port->ConnectionPort;
- if (!Port) return;
- }
-
- /* Loop the list */
- ListHead = &Port->LpcDataInfoChainHead;
- NextEntry = ListHead->Flink;
- while (ListHead != NextEntry)
- {
- /* Get the message */
- Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
-
- /* Make sure it matches */
- if ((Message->Request.MessageId == MessageId) &&
- (Message->Request.ClientId.UniqueThread == ClientId.UniqueThread) &&
- (Message->Request.ClientId.UniqueProcess == ClientId.UniqueProcess))
- {
- /* Unlink and free it */
- RemoveEntryList(&Message->Entry);
- InitializeListHead(&Message->Entry);
- LpcpFreeToPortZone(Message, LPCP_LOCK_HELD);
- break;
- }
-
- /* Go to the next entry */
- NextEntry = NextEntry->Flink;
- }
-}
-
-VOID
-NTAPI
-LpcpSaveDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
- IN PLPCP_MESSAGE Message,
- IN ULONG LockFlags)
-{
- BOOLEAN LockHeld = (LockFlags & LPCP_LOCK_HELD);
-
- PAGED_CODE();
-
- /* Acquire the lock */
- if (!LockHeld) KeAcquireGuardedMutex(&LpcpLock);
-
- /* Check if the port we want is the connection port */
- if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT)
- {
- /* Use it */
- Port = Port->ConnectionPort;
- if (!Port)
- {
- /* Release the lock and return */
- if (!LockHeld) KeReleaseGuardedMutex(&LpcpLock);
- return;
- }
- }
-
- /* Link the message */
- InsertTailList(&Port->LpcDataInfoChainHead, &Message->Entry);
-
- /* Release the lock */
- if (!LockHeld) KeReleaseGuardedMutex(&LpcpLock);
-}
-
-PLPCP_MESSAGE
-NTAPI
-LpcpFindDataInfoMessage(
- IN PLPCP_PORT_OBJECT Port,
- IN ULONG MessageId,
- IN LPC_CLIENT_ID ClientId)
-{
- PLPCP_MESSAGE Message;
- PLIST_ENTRY ListEntry;
-
- PAGED_CODE();
-
- /* Check if the port we want is the connection port */
- if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT)
- {
- /* Use it */
- Port = Port->ConnectionPort;
- if (!Port)
- {
- /* Return NULL */
- return NULL;
- }
- }
-
- /* Loop all entries in the list */
- for (ListEntry = Port->LpcDataInfoChainHead.Flink;
- ListEntry != &Port->LpcDataInfoChainHead;
- ListEntry = ListEntry->Flink)
- {
- Message = CONTAINING_RECORD(ListEntry, LPCP_MESSAGE, Entry);
-
- /* Check if this is the desired message */
- if ((Message->Request.MessageId == MessageId) &&
- (Message->Request.ClientId.UniqueProcess == ClientId.UniqueProcess) &&
- (Message->Request.ClientId.UniqueThread == ClientId.UniqueThread))
- {
- /* It is, return it */
- return Message;
- }
- }
-
- return NULL;
-}
-
-VOID
-NTAPI
-LpcpMoveMessage(IN PPORT_MESSAGE Destination,
- IN PPORT_MESSAGE Origin,
- IN PVOID Data,
- IN ULONG MessageType,
- IN PCLIENT_ID ClientId)
-{
- LPCTRACE((LPC_REPLY_DEBUG | LPC_SEND_DEBUG),
- "Destination/Origin: %p/%p. Data: %p. Length: %lx\n",
- Destination,
- Origin,
- Data,
- Origin->u1.Length);
-
- /* Set the Message size */
- Destination->u1.Length = Origin->u1.Length;
-
- /* Set the Message Type */
- Destination->u2.s2.Type = !MessageType ?
- Origin->u2.s2.Type : MessageType & 0xFFFF;
-
- /* Check if we have a Client ID */
- if (ClientId)
- {
- /* Set the Client ID */
- Destination->ClientId.UniqueProcess = ClientId->UniqueProcess;
- Destination->ClientId.UniqueThread = ClientId->UniqueThread;
- }
- else
- {
- /* Otherwise, copy it */
- Destination->ClientId.UniqueProcess = Origin->ClientId.UniqueProcess;
- Destination->ClientId.UniqueThread = Origin->ClientId.UniqueThread;
- }
-
- /* Copy the MessageId and ClientViewSize */
- Destination->MessageId = Origin->MessageId;
- Destination->ClientViewSize = Origin->ClientViewSize;
-
- /* Copy the Message Data */
- RtlCopyMemory(Destination + 1,
- Data,
- ALIGN_UP_BY(Destination->u1.s1.DataLength, sizeof(ULONG)));
-}
-
-/* PUBLIC FUNCTIONS **********************************************************/
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-NtReplyPort(IN HANDLE PortHandle,
- IN PPORT_MESSAGE ReplyMessage)
-{
- NTSTATUS Status;
- KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
- PORT_MESSAGE CapturedReplyMessage;
- PLPCP_PORT_OBJECT Port;
- PLPCP_MESSAGE Message;
- PETHREAD Thread = PsGetCurrentThread(), WakeupThread;
-
- PAGED_CODE();
- LPCTRACE(LPC_REPLY_DEBUG,
- "Handle: %p. Message: %p.\n",
- PortHandle,
- ReplyMessage);
-
- /* Check if the call comes from user mode */
- if (PreviousMode != KernelMode)
- {
- _SEH2_TRY
- {
- ProbeForRead(ReplyMessage, sizeof(*ReplyMessage), sizeof(ULONG));
- CapturedReplyMessage = *(volatile PORT_MESSAGE*)ReplyMessage;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
- }
- else
- {
- CapturedReplyMessage = *ReplyMessage;
- }
-
- /* Validate its length */
- if (((ULONG)CapturedReplyMessage.u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
- (ULONG)CapturedReplyMessage.u1.s1.TotalLength)
- {
- /* Fail */
- return STATUS_INVALID_PARAMETER;
- }
-
- /* Make sure it has a valid ID */
- if (!CapturedReplyMessage.MessageId) return STATUS_INVALID_PARAMETER;
-
- /* Get the Port object */
- Status = ObReferenceObjectByHandle(PortHandle,
- 0,
- LpcPortObjectType,
- PreviousMode,
- (PVOID*)&Port,
- NULL);
- if (!NT_SUCCESS(Status)) return Status;
-
- /* Validate its length in respect to the port object */
- if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > Port->MaxMessageLength) ||
- ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <=
- (ULONG)CapturedReplyMessage.u1.s1.DataLength))
- {
- /* Too large, fail */
- ObDereferenceObject(Port);
- return STATUS_PORT_MESSAGE_TOO_LONG;
- }
-
- /* Get the ETHREAD corresponding to it */
- Status = PsLookupProcessThreadByCid(&CapturedReplyMessage.ClientId,
- NULL,
- &WakeupThread);
- if (!NT_SUCCESS(Status))
- {
- /* No thread found, fail */
- ObDereferenceObject(Port);
- return Status;
- }
-
- /* Allocate a message from the port zone */
- Message = LpcpAllocateFromPortZone();
- if (!Message)
- {
- /* Fail if we couldn't allocate a message */
- ObDereferenceObject(WakeupThread);
- ObDereferenceObject(Port);
- return STATUS_NO_MEMORY;
- }
-
- /* Keep the lock acquired */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Make sure this is the reply the thread is waiting for */
- if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) ||
- ((LpcpGetMessageFromThread(WakeupThread)) &&
- (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)-> Request)
- != LPC_REQUEST)))
- {
- /* It isn't, fail */
- LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
- ObDereferenceObject(WakeupThread);
- ObDereferenceObject(Port);
- return STATUS_REPLY_MESSAGE_MISMATCH;
- }
-
- /* Copy the message */
- _SEH2_TRY
- {
- LpcpMoveMessage(&Message->Request,
- &CapturedReplyMessage,
- ReplyMessage + 1,
- LPC_REPLY,
- NULL);
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- /* Cleanup and return the exception code */
- LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
- ObDereferenceObject(WakeupThread);
- ObDereferenceObject(Port);
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
-
- /* Reference the thread while we use it */
- ObReferenceObject(WakeupThread);
- Message->RepliedToThread = WakeupThread;
-
- /* Set this as the reply message */
- WakeupThread->LpcReplyMessageId = 0;
- WakeupThread->LpcReplyMessage = (PVOID)Message;
-
- /* Check if we have messages on the reply chain */
- if (!(WakeupThread->LpcExitThreadCalled) &&
- !(IsListEmpty(&WakeupThread->LpcReplyChain)))
- {
- /* Remove us from it and reinitialize it */
- RemoveEntryList(&WakeupThread->LpcReplyChain);
- InitializeListHead(&WakeupThread->LpcReplyChain);
- }
-
- /* Check if this is the message the thread had received */
- if ((Thread->LpcReceivedMsgIdValid) &&
- (Thread->LpcReceivedMessageId == CapturedReplyMessage.MessageId))
- {
- /* Clear this data */
- Thread->LpcReceivedMessageId = 0;
- Thread->LpcReceivedMsgIdValid = FALSE;
- }
-
- /* Free any data information */
- LpcpFreeDataInfoMessage(Port,
- CapturedReplyMessage.MessageId,
- CapturedReplyMessage.CallbackId,
- CapturedReplyMessage.ClientId);
-
- /* Release the lock and release the LPC semaphore to wake up waiters */
- KeReleaseGuardedMutex(&LpcpLock);
- LpcpCompleteWait(&WakeupThread->LpcReplySemaphore);
-
- /* Now we can let go of the thread */
- ObDereferenceObject(WakeupThread);
-
- /* Dereference port object */
- ObDereferenceObject(Port);
- return Status;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
- OUT PVOID *PortContext OPTIONAL,
- IN PPORT_MESSAGE ReplyMessage OPTIONAL,
- OUT PPORT_MESSAGE ReceiveMessage,
- IN PLARGE_INTEGER Timeout OPTIONAL)
-{
- NTSTATUS Status;
- KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(), WaitMode = PreviousMode;
- PORT_MESSAGE CapturedReplyMessage;
- LARGE_INTEGER CapturedTimeout;
- PLPCP_PORT_OBJECT Port, ReceivePort, ConnectionPort = NULL;
- PLPCP_MESSAGE Message;
- PETHREAD Thread = PsGetCurrentThread(), WakeupThread;
- PLPCP_CONNECTION_MESSAGE ConnectMessage;
- ULONG ConnectionInfoLength;
-
- PAGED_CODE();
- LPCTRACE(LPC_REPLY_DEBUG,
- "Handle: %p. Messages: %p/%p. Context: %p\n",
- PortHandle,
- ReplyMessage,
- ReceiveMessage,
- PortContext);
-
- /* Check if the call comes from user mode */
- if (PreviousMode != KernelMode)
- {
- _SEH2_TRY
- {
- if (PortContext != NULL)
- ProbeForWritePointer(PortContext);
-
- if (ReplyMessage != NULL)
- {
- ProbeForRead(ReplyMessage, sizeof(*ReplyMessage), sizeof(ULONG));
- CapturedReplyMessage = *(volatile PORT_MESSAGE*)ReplyMessage;
- }
-
- if (Timeout != NULL)
- {
- ProbeForReadLargeInteger(Timeout);
- CapturedTimeout = *(volatile LARGE_INTEGER*)Timeout;
- Timeout = &CapturedTimeout;
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
- }
- else
- {
- /* If this is a system thread, then let it page out its stack */
- if (Thread->SystemThread) WaitMode = UserMode;
-
- if (ReplyMessage != NULL)
- CapturedReplyMessage = *ReplyMessage;
- }
-
- /* Check if caller has a reply message */
- if (ReplyMessage)
- {
- /* Validate its length */
- if (((ULONG)CapturedReplyMessage.u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
- (ULONG)CapturedReplyMessage.u1.s1.TotalLength)
- {
- /* Fail */
- return STATUS_INVALID_PARAMETER;
- }
-
- /* Make sure it has a valid ID */
- if (!CapturedReplyMessage.MessageId) return STATUS_INVALID_PARAMETER;
- }
-
- /* Get the Port object */
- Status = ObReferenceObjectByHandle(PortHandle,
- 0,
- LpcPortObjectType,
- PreviousMode,
- (PVOID*)&Port,
- NULL);
- if (!NT_SUCCESS(Status)) return Status;
-
- /* Check if the caller has a reply message */
- if (ReplyMessage)
- {
- /* Validate its length in respect to the port object */
- if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > Port->MaxMessageLength) ||
- ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <=
- (ULONG)CapturedReplyMessage.u1.s1.DataLength))
- {
- /* Too large, fail */
- ObDereferenceObject(Port);
- return STATUS_PORT_MESSAGE_TOO_LONG;
- }
- }
-
- /* Check if this is anything but a client port */
- if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CLIENT_PORT)
- {
- /* Check if this is the connection port */
- if (Port->ConnectionPort == Port)
- {
- /* Use this port */
- ConnectionPort = ReceivePort = Port;
- ObReferenceObject(ConnectionPort);
- }
- else
- {
- /* Acquire the lock */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Get the port */
- ConnectionPort = ReceivePort = Port->ConnectionPort;
- if (!ConnectionPort)
- {
- /* Fail */
- KeReleaseGuardedMutex(&LpcpLock);
- ObDereferenceObject(Port);
- return STATUS_PORT_DISCONNECTED;
- }
-
- /* Release lock and reference */
- ObReferenceObject(ConnectionPort);
- KeReleaseGuardedMutex(&LpcpLock);
- }
- }
- else
- {
- /* Otherwise, use the port itself */
- ReceivePort = Port;
- }
-
- /* Check if the caller gave a reply message */
- if (ReplyMessage)
- {
- /* Get the ETHREAD corresponding to it */
- Status = PsLookupProcessThreadByCid(&CapturedReplyMessage.ClientId,
- NULL,
- &WakeupThread);
- if (!NT_SUCCESS(Status))
- {
- /* No thread found, fail */
- ObDereferenceObject(Port);
- if (ConnectionPort) ObDereferenceObject(ConnectionPort);
- return Status;
- }
-
- /* Allocate a message from the port zone */
- Message = LpcpAllocateFromPortZone();
- if (!Message)
- {
- /* Fail if we couldn't allocate a message */
- if (ConnectionPort) ObDereferenceObject(ConnectionPort);
- ObDereferenceObject(WakeupThread);
- ObDereferenceObject(Port);
- return STATUS_NO_MEMORY;
- }
-
- /* Keep the lock acquired */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Make sure this is the reply the thread is waiting for */
- if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) ||
- ((LpcpGetMessageFromThread(WakeupThread)) &&
- (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)->Request)
- != LPC_REQUEST)))
- {
- /* It isn't, fail */
- LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
- if (ConnectionPort) ObDereferenceObject(ConnectionPort);
- ObDereferenceObject(WakeupThread);
- ObDereferenceObject(Port);
- return STATUS_REPLY_MESSAGE_MISMATCH;
- }
-
- /* Copy the message */
- _SEH2_TRY
- {
- LpcpMoveMessage(&Message->Request,
- &CapturedReplyMessage,
- ReplyMessage + 1,
- LPC_REPLY,
- NULL);
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- /* Cleanup and return the exception code */
- LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
- if (ConnectionPort) ObDereferenceObject(ConnectionPort);
- ObDereferenceObject(WakeupThread);
- ObDereferenceObject(Port);
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
-
- /* Reference the thread while we use it */
- ObReferenceObject(WakeupThread);
- Message->RepliedToThread = WakeupThread;
-
- /* Set this as the reply message */
- WakeupThread->LpcReplyMessageId = 0;
- WakeupThread->LpcReplyMessage = (PVOID)Message;
-
- /* Check if we have messages on the reply chain */
- if (!(WakeupThread->LpcExitThreadCalled) &&
- !(IsListEmpty(&WakeupThread->LpcReplyChain)))
- {
- /* Remove us from it and reinitialize it */
- RemoveEntryList(&WakeupThread->LpcReplyChain);
- InitializeListHead(&WakeupThread->LpcReplyChain);
- }
-
- /* Check if this is the message the thread had received */
- if ((Thread->LpcReceivedMsgIdValid) &&
- (Thread->LpcReceivedMessageId == CapturedReplyMessage.MessageId))
- {
- /* Clear this data */
- Thread->LpcReceivedMessageId = 0;
- Thread->LpcReceivedMsgIdValid = FALSE;
- }
-
- /* Free any data information */
- LpcpFreeDataInfoMessage(Port,
- CapturedReplyMessage.MessageId,
- CapturedReplyMessage.CallbackId,
- CapturedReplyMessage.ClientId);
-
- /* Release the lock and release the LPC semaphore to wake up waiters */
- KeReleaseGuardedMutex(&LpcpLock);
- LpcpCompleteWait(&WakeupThread->LpcReplySemaphore);
-
- /* Now we can let go of the thread */
- ObDereferenceObject(WakeupThread);
- }
-
- /* Now wait for someone to reply to us */
- LpcpReceiveWait(ReceivePort->MsgQueue.Semaphore, WaitMode);
- if (Status != STATUS_SUCCESS) goto Cleanup;
-
- /* Wait done, get the LPC lock */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Check if we've received nothing */
- if (IsListEmpty(&ReceivePort->MsgQueue.ReceiveHead))
- {
- /* Check if this was a waitable port and wake it */
- if (ReceivePort->Flags & LPCP_WAITABLE_PORT)
- {
- /* Reset its event */
- KeResetEvent(&ReceivePort->WaitEvent);
- }
-
- /* Release the lock and fail */
- KeReleaseGuardedMutex(&LpcpLock);
- if (ConnectionPort) ObDereferenceObject(ConnectionPort);
- ObDereferenceObject(Port);
- return STATUS_UNSUCCESSFUL;
- }
-
- /* Get the message on the queue */
- Message = CONTAINING_RECORD(RemoveHeadList(&ReceivePort->MsgQueue.ReceiveHead),
- LPCP_MESSAGE,
- Entry);
-
- /* Check if the queue is empty now */
- if (IsListEmpty(&ReceivePort->MsgQueue.ReceiveHead))
- {
- /* Check if this was a waitable port */
- if (ReceivePort->Flags & LPCP_WAITABLE_PORT)
- {
- /* Reset its event */
- KeResetEvent(&ReceivePort->WaitEvent);
- }
- }
-
- /* Re-initialize the message's list entry */
- InitializeListHead(&Message->Entry);
-
- /* Set this as the received message */
- Thread->LpcReceivedMessageId = Message->Request.MessageId;
- Thread->LpcReceivedMsgIdValid = TRUE;
-
- _SEH2_TRY
- {
- /* Check if this was a connection request */
- if (LpcpGetMessageType(&Message->Request) == LPC_CONNECTION_REQUEST)
- {
- /* Get the connection message */
- ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
- LPCTRACE(LPC_REPLY_DEBUG,
- "Request Messages: %p/%p\n",
- Message,
- ConnectMessage);
-
- /* Get its length */
- ConnectionInfoLength = Message->Request.u1.s1.DataLength -
- sizeof(LPCP_CONNECTION_MESSAGE);
-
- /* Return it as the receive message */
- *ReceiveMessage = Message->Request;
-
- /* Clear our stack variable so the message doesn't get freed */
- Message = NULL;
-
- /* Setup the receive message */
- ReceiveMessage->u1.s1.TotalLength = (CSHORT)(sizeof(LPCP_MESSAGE) +
- ConnectionInfoLength);
- ReceiveMessage->u1.s1.DataLength = (CSHORT)ConnectionInfoLength;
- RtlCopyMemory(ReceiveMessage + 1,
- ConnectMessage + 1,
- ConnectionInfoLength);
-
- /* Clear the port context if the caller requested one */
- if (PortContext) *PortContext = NULL;
- }
- else if (LpcpGetMessageType(&Message->Request) != LPC_REPLY)
- {
- /* Otherwise, this is a new message or event */
- LPCTRACE(LPC_REPLY_DEBUG,
- "Non-Reply Messages: %p/%p\n",
- &Message->Request,
- (&Message->Request) + 1);
-
- /* Copy it */
- LpcpMoveMessage(ReceiveMessage,
- &Message->Request,
- (&Message->Request) + 1,
- 0,
- NULL);
-
- /* Return its context */
- if (PortContext) *PortContext = Message->PortContext;
-
- /* And check if it has data information */
- if (Message->Request.u2.s2.DataInfoOffset)
- {
- /* It does, save it, and don't free the message below */
- LpcpSaveDataInfoMessage(Port, Message, LPCP_LOCK_HELD);
- Message = NULL;
- }
- }
- else
- {
- /* This is a reply message, should never happen! */
- ASSERT(FALSE);
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END;
-
- /* Check if we have a message pointer here */
- if (Message)
- {
- /* Free it and release the lock */
- LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
- }
- else
- {
- /* Just release the lock */
- KeReleaseGuardedMutex(&LpcpLock);
- }
-
-Cleanup:
- /* All done, dereference the port and return the status */
- LPCTRACE(LPC_REPLY_DEBUG,
- "Port: %p. Status: %d\n",
- Port,
- Status);
- if (ConnectionPort) ObDereferenceObject(ConnectionPort);
- ObDereferenceObject(Port);
- return Status;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-NtReplyWaitReceivePort(IN HANDLE PortHandle,
- OUT PVOID *PortContext OPTIONAL,
- IN PPORT_MESSAGE ReplyMessage OPTIONAL,
- OUT PPORT_MESSAGE ReceiveMessage)
-{
- /* Call the newer API */
- return NtReplyWaitReceivePortEx(PortHandle,
- PortContext,
- ReplyMessage,
- ReceiveMessage,
- NULL);
-}
-
-/*
- * @unimplemented
- */
-NTSTATUS
-NTAPI
-NtReplyWaitReplyPort(IN HANDLE PortHandle,
- IN PPORT_MESSAGE ReplyMessage)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-NTSTATUS
-NTAPI
-LpcpCopyRequestData(
- IN BOOLEAN Write,
- IN HANDLE PortHandle,
- IN PPORT_MESSAGE Message,
- IN ULONG Index,
- IN PVOID Buffer,
- IN ULONG BufferLength,
- OUT PULONG ReturnLength)
-{
- NTSTATUS Status;
- KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
- PORT_MESSAGE CapturedMessage;
- PLPCP_PORT_OBJECT Port = NULL;
- PETHREAD ClientThread = NULL;
- SIZE_T LocalReturnLength;
- PLPCP_MESSAGE InfoMessage;
- PLPCP_DATA_INFO DataInfo;
- PVOID DataInfoBaseAddress;
-
- PAGED_CODE();
-
- /* Check if the call comes from user mode */
- if (PreviousMode != KernelMode)
- {
- _SEH2_TRY
- {
- ProbeForRead(Message, sizeof(*Message), sizeof(PVOID));
- CapturedMessage = *(volatile PORT_MESSAGE*)Message;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
- }
- else
- {
- CapturedMessage = *Message;
- }
-
- /* Make sure there is any data to copy */
- if (CapturedMessage.u2.s2.DataInfoOffset == 0)
- {
- return STATUS_INVALID_PARAMETER;
- }
-
- /* Reference the port handle */
- Status = ObReferenceObjectByHandle(PortHandle,
- PORT_ALL_ACCESS,
- LpcPortObjectType,
- PreviousMode,
- (PVOID*)&Port,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Failed to reference port handle: 0x%ls\n", Status);
- return Status;
- }
-
- /* Look up the client thread */
- Status = PsLookupProcessThreadByCid(&CapturedMessage.ClientId,
- NULL,
- &ClientThread);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Failed to lookup client thread for [0x%lx:0x%lx]: 0x%ls\n",
- CapturedMessage.ClientId.UniqueProcess,
- CapturedMessage.ClientId.UniqueThread, Status);
- goto Cleanup;
- }
-
- /* Acquire the global LPC lock */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Check for message id mismatch */
- if ((ClientThread->LpcReplyMessageId != CapturedMessage.MessageId) ||
- (CapturedMessage.MessageId == 0))
- {
- DPRINT1("LpcReplyMessageId mismatch: 0x%lx/0x%lx.\n",
- ClientThread->LpcReplyMessageId, CapturedMessage.MessageId);
- Status = STATUS_REPLY_MESSAGE_MISMATCH;
- goto CleanupWithLock;
- }
-
- /* Validate the port */
- if (!LpcpValidateClientPort(ClientThread, Port))
- {
- DPRINT1("LpcpValidateClientPort failed\n");
- Status = STATUS_REPLY_MESSAGE_MISMATCH;
- goto CleanupWithLock;
- }
-
- /* Find the message with the data */
- InfoMessage = LpcpFindDataInfoMessage(Port,
- CapturedMessage.MessageId,
- CapturedMessage.ClientId);
- if (InfoMessage == NULL)
- {
- DPRINT1("LpcpFindDataInfoMessage failed\n");
- Status = STATUS_INVALID_PARAMETER;
- goto CleanupWithLock;
- }
-
- /* Get the data info */
- DataInfo = LpcpGetDataInfoFromMessage(&InfoMessage->Request);
-
- /* Check if the index is within bounds */
- if (Index >= DataInfo->NumberOfEntries)
- {
- DPRINT1("Message data index %lu out of bounds (%lu in msg)\n",
- Index, DataInfo->NumberOfEntries);
- Status = STATUS_INVALID_PARAMETER;
- goto CleanupWithLock;
- }
-
- /* Check if the caller wants to read/write more data than expected */
- if (BufferLength > DataInfo->Entries[Index].DataLength)
- {
- DPRINT1("Trying to read more data (%lu) than available (%lu)\n",
- BufferLength, DataInfo->Entries[Index].DataLength);
- Status = STATUS_INVALID_PARAMETER;
- goto CleanupWithLock;
- }
-
- /* Get the data pointer */
- DataInfoBaseAddress = DataInfo->Entries[Index].BaseAddress;
-
- /* Release the lock */
- KeReleaseGuardedMutex(&LpcpLock);
-
- if (Write)
- {
- /* Copy data from the caller to the message sender */
- Status = MmCopyVirtualMemory(PsGetCurrentProcess(),
- Buffer,
- ClientThread->ThreadsProcess,
- DataInfoBaseAddress,
- BufferLength,
- PreviousMode,
- &LocalReturnLength);
- }
- else
- {
- /* Copy data from the message sender to the caller */
- Status = MmCopyVirtualMemory(ClientThread->ThreadsProcess,
- DataInfoBaseAddress,
- PsGetCurrentProcess(),
- Buffer,
- BufferLength,
- PreviousMode,
- &LocalReturnLength);
- }
-
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("MmCopyVirtualMemory failed: 0x%ls\n", Status);
- goto Cleanup;
- }
-
- /* Check if the caller asked to return the copied length */
- if (ReturnLength != NULL)
- {
- _SEH2_TRY
- {
- *ReturnLength = LocalReturnLength;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- /* Ignore */
- DPRINT1("Exception writing ReturnLength, ignoring\n");
- }
- _SEH2_END;
- }
-
-Cleanup:
-
- if (ClientThread != NULL)
- ObDereferenceObject(ClientThread);
-
- ObDereferenceObject(Port);
-
- return Status;
-
-CleanupWithLock:
-
- /* Release the lock */
- KeReleaseGuardedMutex(&LpcpLock);
- goto Cleanup;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-NtReadRequestData(IN HANDLE PortHandle,
- IN PPORT_MESSAGE Message,
- IN ULONG Index,
- IN PVOID Buffer,
- IN ULONG BufferLength,
- OUT PULONG ReturnLength)
-{
- /* Call the internal function */
- return LpcpCopyRequestData(FALSE,
- PortHandle,
- Message,
- Index,
- Buffer,
- BufferLength,
- ReturnLength);
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-NtWriteRequestData(IN HANDLE PortHandle,
- IN PPORT_MESSAGE Message,
- IN ULONG Index,
- IN PVOID Buffer,
- IN ULONG BufferLength,
- OUT PULONG ReturnLength)
-{
- /* Call the internal function */
- return LpcpCopyRequestData(TRUE,
- PortHandle,
- Message,
- Index,
- Buffer,
- BufferLength,
- ReturnLength);
-}
-
-/* EOF */