/* Unlink and free it */
RemoveEntryList(&Message->Entry);
InitializeListHead(&Message->Entry);
- LpcpFreeToPortZone(Message, 1);
+ LpcpFreeToPortZone(Message, LPCP_LOCK_HELD);
break;
}
NTAPI
LpcpSaveDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
IN PLPCP_MESSAGE Message,
- IN ULONG LockHeld)
+ IN ULONG LockFlags)
{
+ BOOLEAN LockHeld = (LockFlags & LPCP_LOCK_HELD);
+
PAGED_CODE();
/* Acquire 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 ULONG MessageType,
IN PCLIENT_ID ClientId)
{
- /* Set the Message size */
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 */
/* Copy the Message Data */
RtlCopyMemory(Destination + 1,
Data,
- ((Destination->u1.Length & 0xFFFF) + 3) &~3);
+ ALIGN_UP_BY(Destination->u1.s1.DataLength, sizeof(ULONG)));
}
/* PUBLIC FUNCTIONS **********************************************************/
NtReplyPort(IN HANDLE PortHandle,
IN PPORT_MESSAGE ReplyMessage)
{
- PLPCP_PORT_OBJECT Port, ConnectionPort = NULL;
- KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
NTSTATUS Status;
+ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+ PORT_MESSAGE CapturedReplyMessage;
+ PLPCP_PORT_OBJECT Port;
PLPCP_MESSAGE Message;
PETHREAD Thread = PsGetCurrentThread(), WakeupThread;
- //PORT_MESSAGE CapturedReplyMessage;
PAGED_CODE();
LPCTRACE(LPC_REPLY_DEBUG,
- "Handle: %lx. Message: %p.\n",
+ "Handle: %p. Message: %p.\n",
PortHandle,
ReplyMessage);
- if (KeGetPreviousMode() == UserMode)
+ /* Check if the call comes from user mode */
+ if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
- ProbeForRead(ReplyMessage, sizeof(PORT_MESSAGE), sizeof(ULONG));
- /*RtlCopyMemory(&CapturedReplyMessage, ReplyMessage, sizeof(PORT_MESSAGE));
- ReplyMessage = &CapturedReplyMessage;*/
+ ProbeForRead(ReplyMessage, sizeof(*ReplyMessage), sizeof(ULONG));
+ CapturedReplyMessage = *(volatile PORT_MESSAGE*)ReplyMessage;
}
- _SEH2_EXCEPT(ExSystemExceptionFilter())
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- DPRINT1("SEH crash [1]\n");
- DbgBreakPoint();
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
+ else
+ {
+ CapturedReplyMessage = *ReplyMessage;
+ }
/* Validate its length */
- if (((ULONG)ReplyMessage->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
- (ULONG)ReplyMessage->u1.s1.TotalLength)
+ 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 (!ReplyMessage->MessageId) return STATUS_INVALID_PARAMETER;
+ if (!CapturedReplyMessage.MessageId) return STATUS_INVALID_PARAMETER;
/* Get the Port object */
Status = ObReferenceObjectByHandle(PortHandle,
if (!NT_SUCCESS(Status)) return Status;
/* Validate its length in respect to the port object */
- if (((ULONG)ReplyMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
- ((ULONG)ReplyMessage->u1.s1.TotalLength <=
- (ULONG)ReplyMessage->u1.s1.DataLength))
+ if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > Port->MaxMessageLength) ||
+ ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <=
+ (ULONG)CapturedReplyMessage.u1.s1.DataLength))
{
/* Too large, fail */
ObDereferenceObject(Port);
}
/* Get the ETHREAD corresponding to it */
- Status = PsLookupProcessThreadByCid(&ReplyMessage->ClientId,
+ Status = PsLookupProcessThreadByCid(&CapturedReplyMessage.ClientId,
NULL,
&WakeupThread);
if (!NT_SUCCESS(Status))
{
/* No thread found, fail */
ObDereferenceObject(Port);
- if (ConnectionPort) ObDereferenceObject(ConnectionPort);
return Status;
}
if (!Message)
{
/* Fail if we couldn't allocate a message */
- if (ConnectionPort) ObDereferenceObject(ConnectionPort);
ObDereferenceObject(WakeupThread);
ObDereferenceObject(Port);
return STATUS_NO_MEMORY;
KeAcquireGuardedMutex(&LpcpLock);
/* Make sure this is the reply the thread is waiting for */
- if ((WakeupThread->LpcReplyMessageId != ReplyMessage->MessageId) ||
+ if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) ||
((LpcpGetMessageFromThread(WakeupThread)) &&
- (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)->
- Request) != LPC_REQUEST)))
+ (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)-> Request)
+ != LPC_REQUEST)))
{
/* It isn't, fail */
- LpcpFreeToPortZone(Message, 3);
- if (ConnectionPort) ObDereferenceObject(ConnectionPort);
+ LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
ObDereferenceObject(WakeupThread);
ObDereferenceObject(Port);
return STATUS_REPLY_MESSAGE_MISMATCH;
_SEH2_TRY
{
LpcpMoveMessage(&Message->Request,
- ReplyMessage,
+ &CapturedReplyMessage,
ReplyMessage + 1,
LPC_REPLY,
NULL);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- /* Fail */
- LpcpFreeToPortZone(Message, 3);
+ /* Cleanup and return the exception code */
+ LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
ObDereferenceObject(WakeupThread);
ObDereferenceObject(Port);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
/* Check if this is the message the thread had received */
if ((Thread->LpcReceivedMsgIdValid) &&
- (Thread->LpcReceivedMessageId == ReplyMessage->MessageId))
+ (Thread->LpcReceivedMessageId == CapturedReplyMessage.MessageId))
{
/* Clear this data */
Thread->LpcReceivedMessageId = 0;
/* Free any data information */
LpcpFreeDataInfoMessage(Port,
- ReplyMessage->MessageId,
- ReplyMessage->CallbackId,
- ReplyMessage->ClientId);
+ CapturedReplyMessage.MessageId,
+ CapturedReplyMessage.CallbackId,
+ CapturedReplyMessage.ClientId);
/* Release the lock and release the LPC semaphore to wake up waiters */
KeReleaseGuardedMutex(&LpcpLock);
OUT PPORT_MESSAGE ReceiveMessage,
IN PLARGE_INTEGER Timeout OPTIONAL)
{
- PLPCP_PORT_OBJECT Port, ReceivePort, ConnectionPort = NULL;
- KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(), WaitMode = PreviousMode;
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;
- //PORT_MESSAGE CapturedReplyMessage;
- LARGE_INTEGER CapturedTimeout;
PAGED_CODE();
LPCTRACE(LPC_REPLY_DEBUG,
- "Handle: %lx. Messages: %p/%p. Context: %p\n",
+ "Handle: %p. Messages: %p/%p. Context: %p\n",
PortHandle,
ReplyMessage,
ReceiveMessage,
PortContext);
- if (KeGetPreviousMode() == UserMode)
+ /* Check if the call comes from user mode */
+ if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
+ if (PortContext != NULL)
+ ProbeForWritePointer(PortContext);
+
if (ReplyMessage != NULL)
{
- ProbeForRead(ReplyMessage, sizeof(PORT_MESSAGE), sizeof(ULONG));
- /*RtlCopyMemory(&CapturedReplyMessage, ReplyMessage, sizeof(PORT_MESSAGE));
- ReplyMessage = &CapturedReplyMessage;*/
+ ProbeForRead(ReplyMessage, sizeof(*ReplyMessage), sizeof(ULONG));
+ CapturedReplyMessage = *(volatile PORT_MESSAGE*)ReplyMessage;
}
if (Timeout != NULL)
{
ProbeForReadLargeInteger(Timeout);
- RtlCopyMemory(&CapturedTimeout, Timeout, sizeof(LARGE_INTEGER));
+ CapturedTimeout = *(volatile LARGE_INTEGER*)Timeout;
Timeout = &CapturedTimeout;
}
-
- if (PortContext != NULL)
- ProbeForWritePointer(PortContext);
}
- _SEH2_EXCEPT(ExSystemExceptionFilter())
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- DPRINT1("SEH crash [1]\n");
- DbgBreakPoint();
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
{
/* 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)ReplyMessage->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
- (ULONG)ReplyMessage->u1.s1.TotalLength)
+ 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 (!ReplyMessage->MessageId) return STATUS_INVALID_PARAMETER;
+ if (!CapturedReplyMessage.MessageId) return STATUS_INVALID_PARAMETER;
}
/* Get the Port object */
if (ReplyMessage)
{
/* Validate its length in respect to the port object */
- if (((ULONG)ReplyMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
- ((ULONG)ReplyMessage->u1.s1.TotalLength <=
- (ULONG)ReplyMessage->u1.s1.DataLength))
+ if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > Port->MaxMessageLength) ||
+ ((ULONG)CapturedReplyMessage.u1.s1.TotalLength <=
+ (ULONG)CapturedReplyMessage.u1.s1.DataLength))
{
/* Too large, fail */
ObDereferenceObject(Port);
if (ReplyMessage)
{
/* Get the ETHREAD corresponding to it */
- Status = PsLookupProcessThreadByCid(&ReplyMessage->ClientId,
+ Status = PsLookupProcessThreadByCid(&CapturedReplyMessage.ClientId,
NULL,
&WakeupThread);
if (!NT_SUCCESS(Status))
KeAcquireGuardedMutex(&LpcpLock);
/* Make sure this is the reply the thread is waiting for */
- if ((WakeupThread->LpcReplyMessageId != ReplyMessage->MessageId) ||
+ if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) ||
((LpcpGetMessageFromThread(WakeupThread)) &&
- (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)->
- Request) != LPC_REQUEST)))
+ (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)->Request)
+ != LPC_REQUEST)))
{
/* It isn't, fail */
- LpcpFreeToPortZone(Message, 3);
+ LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
if (ConnectionPort) ObDereferenceObject(ConnectionPort);
ObDereferenceObject(WakeupThread);
ObDereferenceObject(Port);
}
/* Copy the message */
- LpcpMoveMessage(&Message->Request,
- ReplyMessage,
- ReplyMessage + 1,
- LPC_REPLY,
- NULL);
+ _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);
/* Check if this is the message the thread had received */
if ((Thread->LpcReceivedMsgIdValid) &&
- (Thread->LpcReceivedMessageId == ReplyMessage->MessageId))
+ (Thread->LpcReceivedMessageId == CapturedReplyMessage.MessageId))
{
/* Clear this data */
Thread->LpcReceivedMessageId = 0;
/* Free any data information */
LpcpFreeDataInfoMessage(Port,
- ReplyMessage->MessageId,
- ReplyMessage->CallbackId,
- ReplyMessage->ClientId);
+ CapturedReplyMessage.MessageId,
+ CapturedReplyMessage.CallbackId,
+ CapturedReplyMessage.ClientId);
/* Release the lock and release the LPC semaphore to wake up waiters */
KeReleaseGuardedMutex(&LpcpLock);
}
/* Get the message on the queue */
- Message = CONTAINING_RECORD(RemoveHeadList(&ReceivePort->
- MsgQueue.ReceiveHead),
+ Message = CONTAINING_RECORD(RemoveHeadList(&ReceivePort->MsgQueue.ReceiveHead),
LPCP_MESSAGE,
Entry);
if (Message->Request.u2.s2.DataInfoOffset)
{
/* It does, save it, and don't free the message below */
- LpcpSaveDataInfoMessage(Port, Message, 1);
+ LpcpSaveDataInfoMessage(Port, Message, LPCP_LOCK_HELD);
Message = NULL;
}
}
ASSERT(FALSE);
}
}
- _SEH2_EXCEPT(ExSystemExceptionFilter())
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- DPRINT1("SEH crash [2]\n");
- DbgBreakPoint();
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
if (Message)
{
/* Free it and release the lock */
- LpcpFreeToPortZone(Message, 3);
+ LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
}
else
{
Cleanup:
/* All done, dereference the port and return the status */
LPCTRACE(LPC_REPLY_DEBUG,
- "Port: %p. Status: %p\n",
+ "Port: %p. Status: %d\n",
Port,
Status);
if (ConnectionPort) ObDereferenceObject(ConnectionPort);
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;
+}
+
/*
- * @unimplemented
+ * @implemented
*/
NTSTATUS
NTAPI
IN ULONG Index,
IN PVOID Buffer,
IN ULONG BufferLength,
- OUT PULONG Returnlength)
+ OUT PULONG ReturnLength)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ /* Call the internal function */
+ return LpcpCopyRequestData(FALSE,
+ PortHandle,
+ Message,
+ Index,
+ Buffer,
+ BufferLength,
+ ReturnLength);
}
/*
- * @unimplemented
+ * @implemented
*/
NTSTATUS
NTAPI
IN ULONG BufferLength,
OUT PULONG ReturnLength)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ /* Call the internal function */
+ return LpcpCopyRequestData(TRUE,
+ PortHandle,
+ Message,
+ Index,
+ Buffer,
+ BufferLength,
+ ReturnLength);
}
/* EOF */