2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/lpc/reply.c
5 * PURPOSE: Local Procedure Call: Receive (Replies)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* PRIVATE FUNCTIONS *********************************************************/
19 LpcpFreeDataInfoMessage(IN PLPCP_PORT_OBJECT Port
,
22 IN CLIENT_ID ClientId
)
24 PLPCP_MESSAGE Message
;
25 PLIST_ENTRY ListHead
, NextEntry
;
27 /* Check if the port we want is the connection port */
28 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) > LPCP_UNCONNECTED_PORT
)
31 Port
= Port
->ConnectionPort
;
36 ListHead
= &Port
->LpcDataInfoChainHead
;
37 NextEntry
= ListHead
->Flink
;
38 while (ListHead
!= NextEntry
)
41 Message
= CONTAINING_RECORD(NextEntry
, LPCP_MESSAGE
, Entry
);
43 /* Make sure it matches */
44 if ((Message
->Request
.MessageId
== MessageId
) &&
45 (Message
->Request
.ClientId
.UniqueThread
== ClientId
.UniqueThread
) &&
46 (Message
->Request
.ClientId
.UniqueProcess
== ClientId
.UniqueProcess
))
48 /* Unlink and free it */
49 RemoveEntryList(&Message
->Entry
);
50 InitializeListHead(&Message
->Entry
);
51 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
);
55 /* Go to the next entry */
56 NextEntry
= NextEntry
->Flink
;
62 LpcpSaveDataInfoMessage(IN PLPCP_PORT_OBJECT Port
,
63 IN PLPCP_MESSAGE Message
,
66 BOOLEAN LockHeld
= (LockFlags
& LPCP_LOCK_HELD
);
70 /* Acquire the lock */
71 if (!LockHeld
) KeAcquireGuardedMutex(&LpcpLock
);
73 /* Check if the port we want is the connection port */
74 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) > LPCP_UNCONNECTED_PORT
)
77 Port
= Port
->ConnectionPort
;
80 /* Release the lock and return */
81 if (!LockHeld
) KeReleaseGuardedMutex(&LpcpLock
);
86 /* Link the message */
87 InsertTailList(&Port
->LpcDataInfoChainHead
, &Message
->Entry
);
89 /* Release the lock */
90 if (!LockHeld
) KeReleaseGuardedMutex(&LpcpLock
);
95 LpcpFindDataInfoMessage(
96 IN PLPCP_PORT_OBJECT Port
,
98 IN LPC_CLIENT_ID ClientId
)
100 PLPCP_MESSAGE Message
;
101 PLIST_ENTRY ListEntry
;
104 /* Check if the port we want is the connection port */
105 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) > LPCP_UNCONNECTED_PORT
)
108 Port
= Port
->ConnectionPort
;
116 /* Loop all entries in the list */
117 for (ListEntry
= Port
->LpcDataInfoChainHead
.Flink
;
118 ListEntry
!= &Port
->LpcDataInfoChainHead
;
119 ListEntry
= ListEntry
->Flink
)
121 Message
= CONTAINING_RECORD(ListEntry
, LPCP_MESSAGE
, Entry
);
123 /* Check if this is the desired message */
124 if ((Message
->Request
.MessageId
== MessageId
) &&
125 (Message
->Request
.ClientId
.UniqueProcess
== ClientId
.UniqueProcess
) &&
126 (Message
->Request
.ClientId
.UniqueThread
== ClientId
.UniqueThread
))
128 /* It is, return it */
138 LpcpMoveMessage(IN PPORT_MESSAGE Destination
,
139 IN PPORT_MESSAGE Origin
,
141 IN ULONG MessageType
,
142 IN PCLIENT_ID ClientId
)
144 /* Set the Message size */
145 LPCTRACE((LPC_REPLY_DEBUG
| LPC_SEND_DEBUG
),
146 "Destination/Origin: %p/%p. Data: %p. Length: %lx\n",
151 Destination
->u1
.Length
= Origin
->u1
.Length
;
153 /* Set the Message Type */
154 Destination
->u2
.s2
.Type
= !MessageType
?
155 Origin
->u2
.s2
.Type
: MessageType
& 0xFFFF;
157 /* Check if we have a Client ID */
160 /* Set the Client ID */
161 Destination
->ClientId
.UniqueProcess
= ClientId
->UniqueProcess
;
162 Destination
->ClientId
.UniqueThread
= ClientId
->UniqueThread
;
166 /* Otherwise, copy it */
167 Destination
->ClientId
.UniqueProcess
= Origin
->ClientId
.UniqueProcess
;
168 Destination
->ClientId
.UniqueThread
= Origin
->ClientId
.UniqueThread
;
171 /* Copy the MessageId and ClientViewSize */
172 Destination
->MessageId
= Origin
->MessageId
;
173 Destination
->ClientViewSize
= Origin
->ClientViewSize
;
175 /* Copy the Message Data */
176 RtlCopyMemory(Destination
+ 1,
178 ALIGN_UP_BY(Destination
->u1
.s1
.DataLength
, sizeof(ULONG
)));
181 /* PUBLIC FUNCTIONS **********************************************************/
188 NtReplyPort(IN HANDLE PortHandle
,
189 IN PPORT_MESSAGE ReplyMessage
)
191 PLPCP_PORT_OBJECT Port
;
192 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
194 PLPCP_MESSAGE Message
;
195 PETHREAD Thread
= PsGetCurrentThread(), WakeupThread
;
196 //PORT_MESSAGE CapturedReplyMessage;
199 LPCTRACE(LPC_REPLY_DEBUG
,
200 "Handle: %p. Message: %p.\n",
204 if (KeGetPreviousMode() == UserMode
)
208 ProbeForRead(ReplyMessage
, sizeof(PORT_MESSAGE
), sizeof(ULONG
));
209 /*RtlCopyMemory(&CapturedReplyMessage, ReplyMessage, sizeof(PORT_MESSAGE));
210 ReplyMessage = &CapturedReplyMessage;*/
212 _SEH2_EXCEPT(ExSystemExceptionFilter())
214 DPRINT1("SEH crash [1]\n");
216 _SEH2_YIELD(return _SEH2_GetExceptionCode());
221 /* Validate its length */
222 if (((ULONG
)ReplyMessage
->u1
.s1
.DataLength
+ sizeof(PORT_MESSAGE
)) >
223 (ULONG
)ReplyMessage
->u1
.s1
.TotalLength
)
226 return STATUS_INVALID_PARAMETER
;
229 /* Make sure it has a valid ID */
230 if (!ReplyMessage
->MessageId
) return STATUS_INVALID_PARAMETER
;
232 /* Get the Port object */
233 Status
= ObReferenceObjectByHandle(PortHandle
,
239 if (!NT_SUCCESS(Status
)) return Status
;
241 /* Validate its length in respect to the port object */
242 if (((ULONG
)ReplyMessage
->u1
.s1
.TotalLength
> Port
->MaxMessageLength
) ||
243 ((ULONG
)ReplyMessage
->u1
.s1
.TotalLength
<=
244 (ULONG
)ReplyMessage
->u1
.s1
.DataLength
))
246 /* Too large, fail */
247 ObDereferenceObject(Port
);
248 return STATUS_PORT_MESSAGE_TOO_LONG
;
251 /* Get the ETHREAD corresponding to it */
252 Status
= PsLookupProcessThreadByCid(&ReplyMessage
->ClientId
,
255 if (!NT_SUCCESS(Status
))
257 /* No thread found, fail */
258 ObDereferenceObject(Port
);
262 /* Allocate a message from the port zone */
263 Message
= LpcpAllocateFromPortZone();
266 /* Fail if we couldn't allocate a message */
267 ObDereferenceObject(WakeupThread
);
268 ObDereferenceObject(Port
);
269 return STATUS_NO_MEMORY
;
272 /* Keep the lock acquired */
273 KeAcquireGuardedMutex(&LpcpLock
);
275 /* Make sure this is the reply the thread is waiting for */
276 if ((WakeupThread
->LpcReplyMessageId
!= ReplyMessage
->MessageId
) ||
277 ((LpcpGetMessageFromThread(WakeupThread
)) &&
278 (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread
)->
279 Request
) != LPC_REQUEST
)))
282 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
283 ObDereferenceObject(WakeupThread
);
284 ObDereferenceObject(Port
);
285 return STATUS_REPLY_MESSAGE_MISMATCH
;
288 /* Copy the message */
291 LpcpMoveMessage(&Message
->Request
,
297 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
300 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
301 ObDereferenceObject(WakeupThread
);
302 ObDereferenceObject(Port
);
303 _SEH2_YIELD(return _SEH2_GetExceptionCode());
307 /* Reference the thread while we use it */
308 ObReferenceObject(WakeupThread
);
309 Message
->RepliedToThread
= WakeupThread
;
311 /* Set this as the reply message */
312 WakeupThread
->LpcReplyMessageId
= 0;
313 WakeupThread
->LpcReplyMessage
= (PVOID
)Message
;
315 /* Check if we have messages on the reply chain */
316 if (!(WakeupThread
->LpcExitThreadCalled
) &&
317 !(IsListEmpty(&WakeupThread
->LpcReplyChain
)))
319 /* Remove us from it and reinitialize it */
320 RemoveEntryList(&WakeupThread
->LpcReplyChain
);
321 InitializeListHead(&WakeupThread
->LpcReplyChain
);
324 /* Check if this is the message the thread had received */
325 if ((Thread
->LpcReceivedMsgIdValid
) &&
326 (Thread
->LpcReceivedMessageId
== ReplyMessage
->MessageId
))
328 /* Clear this data */
329 Thread
->LpcReceivedMessageId
= 0;
330 Thread
->LpcReceivedMsgIdValid
= FALSE
;
333 /* Free any data information */
334 LpcpFreeDataInfoMessage(Port
,
335 ReplyMessage
->MessageId
,
336 ReplyMessage
->CallbackId
,
337 ReplyMessage
->ClientId
);
339 /* Release the lock and release the LPC semaphore to wake up waiters */
340 KeReleaseGuardedMutex(&LpcpLock
);
341 LpcpCompleteWait(&WakeupThread
->LpcReplySemaphore
);
343 /* Now we can let go of the thread */
344 ObDereferenceObject(WakeupThread
);
346 /* Dereference port object */
347 ObDereferenceObject(Port
);
356 NtReplyWaitReceivePortEx(IN HANDLE PortHandle
,
357 OUT PVOID
*PortContext OPTIONAL
,
358 IN PPORT_MESSAGE ReplyMessage OPTIONAL
,
359 OUT PPORT_MESSAGE ReceiveMessage
,
360 IN PLARGE_INTEGER Timeout OPTIONAL
)
362 PLPCP_PORT_OBJECT Port
, ReceivePort
, ConnectionPort
= NULL
;
363 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode(), WaitMode
= PreviousMode
;
365 PLPCP_MESSAGE Message
;
366 PETHREAD Thread
= PsGetCurrentThread(), WakeupThread
;
367 PLPCP_CONNECTION_MESSAGE ConnectMessage
;
368 ULONG ConnectionInfoLength
;
369 //PORT_MESSAGE CapturedReplyMessage;
370 LARGE_INTEGER CapturedTimeout
;
373 LPCTRACE(LPC_REPLY_DEBUG
,
374 "Handle: %p. Messages: %p/%p. Context: %p\n",
380 if (KeGetPreviousMode() == UserMode
)
384 if (ReplyMessage
!= NULL
)
386 ProbeForRead(ReplyMessage
, sizeof(PORT_MESSAGE
), sizeof(ULONG
));
387 /*RtlCopyMemory(&CapturedReplyMessage, ReplyMessage, sizeof(PORT_MESSAGE));
388 ReplyMessage = &CapturedReplyMessage;*/
393 ProbeForReadLargeInteger(Timeout
);
394 RtlCopyMemory(&CapturedTimeout
, Timeout
, sizeof(LARGE_INTEGER
));
395 Timeout
= &CapturedTimeout
;
398 if (PortContext
!= NULL
)
399 ProbeForWritePointer(PortContext
);
401 _SEH2_EXCEPT(ExSystemExceptionFilter())
403 DPRINT1("SEH crash [1]\n");
405 _SEH2_YIELD(return _SEH2_GetExceptionCode());
411 /* If this is a system thread, then let it page out its stack */
412 if (Thread
->SystemThread
) WaitMode
= UserMode
;
415 /* Check if caller has a reply message */
418 /* Validate its length */
419 if (((ULONG
)ReplyMessage
->u1
.s1
.DataLength
+ sizeof(PORT_MESSAGE
)) >
420 (ULONG
)ReplyMessage
->u1
.s1
.TotalLength
)
423 return STATUS_INVALID_PARAMETER
;
426 /* Make sure it has a valid ID */
427 if (!ReplyMessage
->MessageId
) return STATUS_INVALID_PARAMETER
;
430 /* Get the Port object */
431 Status
= ObReferenceObjectByHandle(PortHandle
,
437 if (!NT_SUCCESS(Status
)) return Status
;
439 /* Check if the caller has a reply message */
442 /* Validate its length in respect to the port object */
443 if (((ULONG
)ReplyMessage
->u1
.s1
.TotalLength
> Port
->MaxMessageLength
) ||
444 ((ULONG
)ReplyMessage
->u1
.s1
.TotalLength
<=
445 (ULONG
)ReplyMessage
->u1
.s1
.DataLength
))
447 /* Too large, fail */
448 ObDereferenceObject(Port
);
449 return STATUS_PORT_MESSAGE_TOO_LONG
;
453 /* Check if this is anything but a client port */
454 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) != LPCP_CLIENT_PORT
)
456 /* Check if this is the connection port */
457 if (Port
->ConnectionPort
== Port
)
460 ConnectionPort
= ReceivePort
= Port
;
461 ObReferenceObject(ConnectionPort
);
465 /* Acquire the lock */
466 KeAcquireGuardedMutex(&LpcpLock
);
469 ConnectionPort
= ReceivePort
= Port
->ConnectionPort
;
473 KeReleaseGuardedMutex(&LpcpLock
);
474 ObDereferenceObject(Port
);
475 return STATUS_PORT_DISCONNECTED
;
478 /* Release lock and reference */
479 ObReferenceObject(ConnectionPort
);
480 KeReleaseGuardedMutex(&LpcpLock
);
485 /* Otherwise, use the port itself */
489 /* Check if the caller gave a reply message */
492 /* Get the ETHREAD corresponding to it */
493 Status
= PsLookupProcessThreadByCid(&ReplyMessage
->ClientId
,
496 if (!NT_SUCCESS(Status
))
498 /* No thread found, fail */
499 ObDereferenceObject(Port
);
500 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
504 /* Allocate a message from the port zone */
505 Message
= LpcpAllocateFromPortZone();
508 /* Fail if we couldn't allocate a message */
509 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
510 ObDereferenceObject(WakeupThread
);
511 ObDereferenceObject(Port
);
512 return STATUS_NO_MEMORY
;
515 /* Keep the lock acquired */
516 KeAcquireGuardedMutex(&LpcpLock
);
518 /* Make sure this is the reply the thread is waiting for */
519 if ((WakeupThread
->LpcReplyMessageId
!= ReplyMessage
->MessageId
) ||
520 ((LpcpGetMessageFromThread(WakeupThread
)) &&
521 (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread
)->
522 Request
) != LPC_REQUEST
)))
525 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
526 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
527 ObDereferenceObject(WakeupThread
);
528 ObDereferenceObject(Port
);
529 return STATUS_REPLY_MESSAGE_MISMATCH
;
532 /* Copy the message */
533 LpcpMoveMessage(&Message
->Request
,
539 /* Reference the thread while we use it */
540 ObReferenceObject(WakeupThread
);
541 Message
->RepliedToThread
= WakeupThread
;
543 /* Set this as the reply message */
544 WakeupThread
->LpcReplyMessageId
= 0;
545 WakeupThread
->LpcReplyMessage
= (PVOID
)Message
;
547 /* Check if we have messages on the reply chain */
548 if (!(WakeupThread
->LpcExitThreadCalled
) &&
549 !(IsListEmpty(&WakeupThread
->LpcReplyChain
)))
551 /* Remove us from it and reinitialize it */
552 RemoveEntryList(&WakeupThread
->LpcReplyChain
);
553 InitializeListHead(&WakeupThread
->LpcReplyChain
);
556 /* Check if this is the message the thread had received */
557 if ((Thread
->LpcReceivedMsgIdValid
) &&
558 (Thread
->LpcReceivedMessageId
== ReplyMessage
->MessageId
))
560 /* Clear this data */
561 Thread
->LpcReceivedMessageId
= 0;
562 Thread
->LpcReceivedMsgIdValid
= FALSE
;
565 /* Free any data information */
566 LpcpFreeDataInfoMessage(Port
,
567 ReplyMessage
->MessageId
,
568 ReplyMessage
->CallbackId
,
569 ReplyMessage
->ClientId
);
571 /* Release the lock and release the LPC semaphore to wake up waiters */
572 KeReleaseGuardedMutex(&LpcpLock
);
573 LpcpCompleteWait(&WakeupThread
->LpcReplySemaphore
);
575 /* Now we can let go of the thread */
576 ObDereferenceObject(WakeupThread
);
579 /* Now wait for someone to reply to us */
580 LpcpReceiveWait(ReceivePort
->MsgQueue
.Semaphore
, WaitMode
);
581 if (Status
!= STATUS_SUCCESS
) goto Cleanup
;
583 /* Wait done, get the LPC lock */
584 KeAcquireGuardedMutex(&LpcpLock
);
586 /* Check if we've received nothing */
587 if (IsListEmpty(&ReceivePort
->MsgQueue
.ReceiveHead
))
589 /* Check if this was a waitable port and wake it */
590 if (ReceivePort
->Flags
& LPCP_WAITABLE_PORT
)
592 /* Reset its event */
593 KeResetEvent(&ReceivePort
->WaitEvent
);
596 /* Release the lock and fail */
597 KeReleaseGuardedMutex(&LpcpLock
);
598 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
599 ObDereferenceObject(Port
);
600 return STATUS_UNSUCCESSFUL
;
603 /* Get the message on the queue */
604 Message
= CONTAINING_RECORD(RemoveHeadList(&ReceivePort
->
605 MsgQueue
.ReceiveHead
),
609 /* Check if the queue is empty now */
610 if (IsListEmpty(&ReceivePort
->MsgQueue
.ReceiveHead
))
612 /* Check if this was a waitable port */
613 if (ReceivePort
->Flags
& LPCP_WAITABLE_PORT
)
615 /* Reset its event */
616 KeResetEvent(&ReceivePort
->WaitEvent
);
620 /* Re-initialize the message's list entry */
621 InitializeListHead(&Message
->Entry
);
623 /* Set this as the received message */
624 Thread
->LpcReceivedMessageId
= Message
->Request
.MessageId
;
625 Thread
->LpcReceivedMsgIdValid
= TRUE
;
629 /* Check if this was a connection request */
630 if (LpcpGetMessageType(&Message
->Request
) == LPC_CONNECTION_REQUEST
)
632 /* Get the connection message */
633 ConnectMessage
= (PLPCP_CONNECTION_MESSAGE
)(Message
+ 1);
634 LPCTRACE(LPC_REPLY_DEBUG
,
635 "Request Messages: %p/%p\n",
640 ConnectionInfoLength
= Message
->Request
.u1
.s1
.DataLength
-
641 sizeof(LPCP_CONNECTION_MESSAGE
);
643 /* Return it as the receive message */
644 *ReceiveMessage
= Message
->Request
;
646 /* Clear our stack variable so the message doesn't get freed */
649 /* Setup the receive message */
650 ReceiveMessage
->u1
.s1
.TotalLength
= (CSHORT
)(sizeof(LPCP_MESSAGE
) +
651 ConnectionInfoLength
);
652 ReceiveMessage
->u1
.s1
.DataLength
= (CSHORT
)ConnectionInfoLength
;
653 RtlCopyMemory(ReceiveMessage
+ 1,
655 ConnectionInfoLength
);
657 /* Clear the port context if the caller requested one */
658 if (PortContext
) *PortContext
= NULL
;
660 else if (LpcpGetMessageType(&Message
->Request
) != LPC_REPLY
)
662 /* Otherwise, this is a new message or event */
663 LPCTRACE(LPC_REPLY_DEBUG
,
664 "Non-Reply Messages: %p/%p\n",
666 (&Message
->Request
) + 1);
669 LpcpMoveMessage(ReceiveMessage
,
671 (&Message
->Request
) + 1,
675 /* Return its context */
676 if (PortContext
) *PortContext
= Message
->PortContext
;
678 /* And check if it has data information */
679 if (Message
->Request
.u2
.s2
.DataInfoOffset
)
681 /* It does, save it, and don't free the message below */
682 LpcpSaveDataInfoMessage(Port
, Message
, LPCP_LOCK_HELD
);
688 /* This is a reply message, should never happen! */
692 _SEH2_EXCEPT(ExSystemExceptionFilter())
694 DPRINT1("SEH crash [2]\n");
696 Status
= _SEH2_GetExceptionCode();
700 /* Check if we have a message pointer here */
703 /* Free it and release the lock */
704 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
708 /* Just release the lock */
709 KeReleaseGuardedMutex(&LpcpLock
);
713 /* All done, dereference the port and return the status */
714 LPCTRACE(LPC_REPLY_DEBUG
,
715 "Port: %p. Status: %d\n",
718 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
719 ObDereferenceObject(Port
);
728 NtReplyWaitReceivePort(IN HANDLE PortHandle
,
729 OUT PVOID
*PortContext OPTIONAL
,
730 IN PPORT_MESSAGE ReplyMessage OPTIONAL
,
731 OUT PPORT_MESSAGE ReceiveMessage
)
733 /* Call the newer API */
734 return NtReplyWaitReceivePortEx(PortHandle
,
746 NtReplyWaitReplyPort(IN HANDLE PortHandle
,
747 IN PPORT_MESSAGE ReplyMessage
)
750 return STATUS_NOT_IMPLEMENTED
;
757 IN HANDLE PortHandle
,
758 IN PPORT_MESSAGE Message
,
761 IN ULONG BufferLength
,
762 OUT PULONG Returnlength
)
764 KPROCESSOR_MODE PreviousMode
;
765 PORT_MESSAGE CapturedMessage
;
766 PLPCP_PORT_OBJECT Port
= NULL
;
767 PETHREAD ClientThread
= NULL
;
768 ULONG LocalReturnlength
;
769 PLPCP_MESSAGE InfoMessage
;
770 PLPCP_DATA_INFO DataInfo
;
771 PVOID DataInfoBaseAddress
;
775 /* Check the previous mode */
776 PreviousMode
= ExGetPreviousMode();
777 if (PreviousMode
== KernelMode
)
779 CapturedMessage
= *Message
;
785 ProbeForRead(Message
, sizeof(*Message
), sizeof(PVOID
));
786 CapturedMessage
= *Message
;
788 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
790 DPRINT1("Got exception!\n");
791 return _SEH2_GetExceptionCode();
796 /* Make sure there is any data to copy */
797 if (CapturedMessage
.u2
.s2
.DataInfoOffset
== 0)
799 return STATUS_INVALID_PARAMETER
;
802 /* Reference the port handle */
803 Status
= ObReferenceObjectByHandle(PortHandle
,
809 if (!NT_SUCCESS(Status
))
811 DPRINT1("Failed to reference port handle: 0x%ls\n", Status
);
815 /* Look up the client thread */
816 Status
= PsLookupProcessThreadByCid(&CapturedMessage
.ClientId
,
819 if (!NT_SUCCESS(Status
))
821 DPRINT1("Failed to lookup client thread for [0x%lx:0x%lx]: 0x%ls\n",
822 CapturedMessage
.ClientId
.UniqueProcess
,
823 CapturedMessage
.ClientId
.UniqueThread
, Status
);
827 /* Acquire the global LPC lock */
828 KeAcquireGuardedMutex(&LpcpLock
);
830 /* Check for message id mismatch */
831 if ((ClientThread
->LpcReplyMessageId
!= CapturedMessage
.MessageId
) ||
832 (CapturedMessage
.MessageId
== 0))
834 DPRINT1("LpcReplyMessageId mismatch: 0x%lx/0x%lx.\n",
835 ClientThread
->LpcReplyMessageId
, CapturedMessage
.MessageId
);
836 Status
= STATUS_REPLY_MESSAGE_MISMATCH
;
837 goto CleanupWithLock
;
840 /* Validate the port */
841 if (!LpcpValidateClientPort(ClientThread
, Port
))
843 DPRINT1("LpcpValidateClientPort failed\n");
844 Status
= STATUS_REPLY_MESSAGE_MISMATCH
;
845 goto CleanupWithLock
;
848 /* Find the message with the data */
849 InfoMessage
= LpcpFindDataInfoMessage(Port
,
850 CapturedMessage
.MessageId
,
851 CapturedMessage
.ClientId
);
852 if (InfoMessage
== NULL
)
854 DPRINT1("LpcpFindDataInfoMessage failed\n");
855 Status
= STATUS_INVALID_PARAMETER
;
856 goto CleanupWithLock
;
859 /* Get the data info */
860 DataInfo
= LpcpGetDataInfoFromMessage(&InfoMessage
->Request
);
862 /* Check if the index is within bounds */
863 if (Index
>= DataInfo
->NumberOfEntries
)
865 DPRINT1("Message data index %lu out of bounds (%lu in msg)\n",
866 Index
, DataInfo
->NumberOfEntries
);
867 Status
= STATUS_INVALID_PARAMETER
;
868 goto CleanupWithLock
;
871 /* Check if the caller wants to read/write more data than expected */
872 if (BufferLength
> DataInfo
->Entries
[Index
].DataLength
)
874 DPRINT1("Trying to read more data (%lu) than available (%lu)\n",
875 BufferLength
, DataInfo
->Entries
[Index
].DataLength
);
876 Status
= STATUS_INVALID_PARAMETER
;
877 goto CleanupWithLock
;
880 /* Get the data pointer */
881 DataInfoBaseAddress
= DataInfo
->Entries
[Index
].BaseAddress
;
883 /* Release the lock */
884 KeReleaseGuardedMutex(&LpcpLock
);
888 /* Copy data from the caller to the message sender */
889 Status
= MmCopyVirtualMemory(PsGetCurrentProcess(),
891 ClientThread
->ThreadsProcess
,
899 /* Copy data from the message sender to the caller */
900 Status
= MmCopyVirtualMemory(ClientThread
->ThreadsProcess
,
902 PsGetCurrentProcess(),
909 if (!NT_SUCCESS(Status
))
911 DPRINT1("MmCopyVirtualMemory failed: 0x%ls\n", Status
);
915 /* Check if the caller asked to return the copied length */
916 if (Returnlength
!= NULL
)
920 *Returnlength
= LocalReturnlength
;
922 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
925 DPRINT1("Exception writing Returnlength, ignoring\n");
932 if (ClientThread
!= NULL
)
933 ObDereferenceObject(ClientThread
);
935 ObDereferenceObject(Port
);
941 /* Release the lock */
942 KeReleaseGuardedMutex(&LpcpLock
);
951 NtReadRequestData(IN HANDLE PortHandle
,
952 IN PPORT_MESSAGE Message
,
955 IN ULONG BufferLength
,
956 OUT PULONG ReturnLength
)
958 /* Call the internal function */
959 return LpcpCopyRequestData(FALSE
,
973 NtWriteRequestData(IN HANDLE PortHandle
,
974 IN PPORT_MESSAGE Message
,
977 IN ULONG BufferLength
,
978 OUT PULONG ReturnLength
)
980 /* Call the internal function */
981 return LpcpCopyRequestData(TRUE
,