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
;
105 /* Check if the port we want is the connection port */
106 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) > LPCP_UNCONNECTED_PORT
)
109 Port
= Port
->ConnectionPort
;
117 /* Loop all entries in the list */
118 for (ListEntry
= Port
->LpcDataInfoChainHead
.Flink
;
119 ListEntry
!= &Port
->LpcDataInfoChainHead
;
120 ListEntry
= ListEntry
->Flink
)
122 Message
= CONTAINING_RECORD(ListEntry
, LPCP_MESSAGE
, Entry
);
124 /* Check if this is the desired message */
125 if ((Message
->Request
.MessageId
== MessageId
) &&
126 (Message
->Request
.ClientId
.UniqueProcess
== ClientId
.UniqueProcess
) &&
127 (Message
->Request
.ClientId
.UniqueThread
== ClientId
.UniqueThread
))
129 /* It is, return it */
139 LpcpMoveMessage(IN PPORT_MESSAGE Destination
,
140 IN PPORT_MESSAGE Origin
,
142 IN ULONG MessageType
,
143 IN PCLIENT_ID ClientId
)
145 LPCTRACE((LPC_REPLY_DEBUG
| LPC_SEND_DEBUG
),
146 "Destination/Origin: %p/%p. Data: %p. Length: %lx\n",
152 /* Set the Message size */
153 Destination
->u1
.Length
= Origin
->u1
.Length
;
155 /* Set the Message Type */
156 Destination
->u2
.s2
.Type
= !MessageType
?
157 Origin
->u2
.s2
.Type
: MessageType
& 0xFFFF;
159 /* Check if we have a Client ID */
162 /* Set the Client ID */
163 Destination
->ClientId
.UniqueProcess
= ClientId
->UniqueProcess
;
164 Destination
->ClientId
.UniqueThread
= ClientId
->UniqueThread
;
168 /* Otherwise, copy it */
169 Destination
->ClientId
.UniqueProcess
= Origin
->ClientId
.UniqueProcess
;
170 Destination
->ClientId
.UniqueThread
= Origin
->ClientId
.UniqueThread
;
173 /* Copy the MessageId and ClientViewSize */
174 Destination
->MessageId
= Origin
->MessageId
;
175 Destination
->ClientViewSize
= Origin
->ClientViewSize
;
177 /* Copy the Message Data */
178 RtlCopyMemory(Destination
+ 1,
180 ALIGN_UP_BY(Destination
->u1
.s1
.DataLength
, sizeof(ULONG
)));
183 /* PUBLIC FUNCTIONS **********************************************************/
190 NtReplyPort(IN HANDLE PortHandle
,
191 IN PPORT_MESSAGE ReplyMessage
)
194 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
195 PORT_MESSAGE CapturedReplyMessage
;
196 PLPCP_PORT_OBJECT Port
;
197 PLPCP_MESSAGE Message
;
198 PETHREAD Thread
= PsGetCurrentThread(), WakeupThread
;
201 LPCTRACE(LPC_REPLY_DEBUG
,
202 "Handle: %p. Message: %p.\n",
206 /* Check if the call comes from user mode */
207 if (PreviousMode
!= KernelMode
)
211 ProbeForRead(ReplyMessage
, sizeof(*ReplyMessage
), sizeof(ULONG
));
212 CapturedReplyMessage
= *(volatile PORT_MESSAGE
*)ReplyMessage
;
214 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
216 _SEH2_YIELD(return _SEH2_GetExceptionCode());
222 CapturedReplyMessage
= *ReplyMessage
;
225 /* Validate its length */
226 if (((ULONG
)CapturedReplyMessage
.u1
.s1
.DataLength
+ sizeof(PORT_MESSAGE
)) >
227 (ULONG
)CapturedReplyMessage
.u1
.s1
.TotalLength
)
230 return STATUS_INVALID_PARAMETER
;
233 /* Make sure it has a valid ID */
234 if (!CapturedReplyMessage
.MessageId
) return STATUS_INVALID_PARAMETER
;
236 /* Get the Port object */
237 Status
= ObReferenceObjectByHandle(PortHandle
,
243 if (!NT_SUCCESS(Status
)) return Status
;
245 /* Validate its length in respect to the port object */
246 if (((ULONG
)CapturedReplyMessage
.u1
.s1
.TotalLength
> Port
->MaxMessageLength
) ||
247 ((ULONG
)CapturedReplyMessage
.u1
.s1
.TotalLength
<=
248 (ULONG
)CapturedReplyMessage
.u1
.s1
.DataLength
))
250 /* Too large, fail */
251 ObDereferenceObject(Port
);
252 return STATUS_PORT_MESSAGE_TOO_LONG
;
255 /* Get the ETHREAD corresponding to it */
256 Status
= PsLookupProcessThreadByCid(&CapturedReplyMessage
.ClientId
,
259 if (!NT_SUCCESS(Status
))
261 /* No thread found, fail */
262 ObDereferenceObject(Port
);
266 /* Allocate a message from the port zone */
267 Message
= LpcpAllocateFromPortZone();
270 /* Fail if we couldn't allocate a message */
271 ObDereferenceObject(WakeupThread
);
272 ObDereferenceObject(Port
);
273 return STATUS_NO_MEMORY
;
276 /* Keep the lock acquired */
277 KeAcquireGuardedMutex(&LpcpLock
);
279 /* Make sure this is the reply the thread is waiting for */
280 if ((WakeupThread
->LpcReplyMessageId
!= CapturedReplyMessage
.MessageId
) ||
281 ((LpcpGetMessageFromThread(WakeupThread
)) &&
282 (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread
)-> Request
)
286 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
287 ObDereferenceObject(WakeupThread
);
288 ObDereferenceObject(Port
);
289 return STATUS_REPLY_MESSAGE_MISMATCH
;
292 /* Copy the message */
295 LpcpMoveMessage(&Message
->Request
,
296 &CapturedReplyMessage
,
301 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
303 /* Cleanup and return the exception code */
304 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
305 ObDereferenceObject(WakeupThread
);
306 ObDereferenceObject(Port
);
307 _SEH2_YIELD(return _SEH2_GetExceptionCode());
311 /* Reference the thread while we use it */
312 ObReferenceObject(WakeupThread
);
313 Message
->RepliedToThread
= WakeupThread
;
315 /* Set this as the reply message */
316 WakeupThread
->LpcReplyMessageId
= 0;
317 WakeupThread
->LpcReplyMessage
= (PVOID
)Message
;
319 /* Check if we have messages on the reply chain */
320 if (!(WakeupThread
->LpcExitThreadCalled
) &&
321 !(IsListEmpty(&WakeupThread
->LpcReplyChain
)))
323 /* Remove us from it and reinitialize it */
324 RemoveEntryList(&WakeupThread
->LpcReplyChain
);
325 InitializeListHead(&WakeupThread
->LpcReplyChain
);
328 /* Check if this is the message the thread had received */
329 if ((Thread
->LpcReceivedMsgIdValid
) &&
330 (Thread
->LpcReceivedMessageId
== CapturedReplyMessage
.MessageId
))
332 /* Clear this data */
333 Thread
->LpcReceivedMessageId
= 0;
334 Thread
->LpcReceivedMsgIdValid
= FALSE
;
337 /* Free any data information */
338 LpcpFreeDataInfoMessage(Port
,
339 CapturedReplyMessage
.MessageId
,
340 CapturedReplyMessage
.CallbackId
,
341 CapturedReplyMessage
.ClientId
);
343 /* Release the lock and release the LPC semaphore to wake up waiters */
344 KeReleaseGuardedMutex(&LpcpLock
);
345 LpcpCompleteWait(&WakeupThread
->LpcReplySemaphore
);
347 /* Now we can let go of the thread */
348 ObDereferenceObject(WakeupThread
);
350 /* Dereference port object */
351 ObDereferenceObject(Port
);
360 NtReplyWaitReceivePortEx(IN HANDLE PortHandle
,
361 OUT PVOID
*PortContext OPTIONAL
,
362 IN PPORT_MESSAGE ReplyMessage OPTIONAL
,
363 OUT PPORT_MESSAGE ReceiveMessage
,
364 IN PLARGE_INTEGER Timeout OPTIONAL
)
367 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode(), WaitMode
= PreviousMode
;
368 PORT_MESSAGE CapturedReplyMessage
;
369 LARGE_INTEGER CapturedTimeout
;
370 PLPCP_PORT_OBJECT Port
, ReceivePort
, ConnectionPort
= NULL
;
371 PLPCP_MESSAGE Message
;
372 PETHREAD Thread
= PsGetCurrentThread(), WakeupThread
;
373 PLPCP_CONNECTION_MESSAGE ConnectMessage
;
374 ULONG ConnectionInfoLength
;
377 LPCTRACE(LPC_REPLY_DEBUG
,
378 "Handle: %p. Messages: %p/%p. Context: %p\n",
384 /* Check if the call comes from user mode */
385 if (PreviousMode
!= KernelMode
)
389 if (PortContext
!= NULL
)
390 ProbeForWritePointer(PortContext
);
392 if (ReplyMessage
!= NULL
)
394 ProbeForRead(ReplyMessage
, sizeof(*ReplyMessage
), sizeof(ULONG
));
395 CapturedReplyMessage
= *(volatile PORT_MESSAGE
*)ReplyMessage
;
400 ProbeForReadLargeInteger(Timeout
);
401 CapturedTimeout
= *(volatile LARGE_INTEGER
*)Timeout
;
402 Timeout
= &CapturedTimeout
;
405 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
407 _SEH2_YIELD(return _SEH2_GetExceptionCode());
413 /* If this is a system thread, then let it page out its stack */
414 if (Thread
->SystemThread
) WaitMode
= UserMode
;
416 if (ReplyMessage
!= NULL
)
417 CapturedReplyMessage
= *ReplyMessage
;
420 /* Check if caller has a reply message */
423 /* Validate its length */
424 if (((ULONG
)CapturedReplyMessage
.u1
.s1
.DataLength
+ sizeof(PORT_MESSAGE
)) >
425 (ULONG
)CapturedReplyMessage
.u1
.s1
.TotalLength
)
428 return STATUS_INVALID_PARAMETER
;
431 /* Make sure it has a valid ID */
432 if (!CapturedReplyMessage
.MessageId
) return STATUS_INVALID_PARAMETER
;
435 /* Get the Port object */
436 Status
= ObReferenceObjectByHandle(PortHandle
,
442 if (!NT_SUCCESS(Status
)) return Status
;
444 /* Check if the caller has a reply message */
447 /* Validate its length in respect to the port object */
448 if (((ULONG
)CapturedReplyMessage
.u1
.s1
.TotalLength
> Port
->MaxMessageLength
) ||
449 ((ULONG
)CapturedReplyMessage
.u1
.s1
.TotalLength
<=
450 (ULONG
)CapturedReplyMessage
.u1
.s1
.DataLength
))
452 /* Too large, fail */
453 ObDereferenceObject(Port
);
454 return STATUS_PORT_MESSAGE_TOO_LONG
;
458 /* Check if this is anything but a client port */
459 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) != LPCP_CLIENT_PORT
)
461 /* Check if this is the connection port */
462 if (Port
->ConnectionPort
== Port
)
465 ConnectionPort
= ReceivePort
= Port
;
466 ObReferenceObject(ConnectionPort
);
470 /* Acquire the lock */
471 KeAcquireGuardedMutex(&LpcpLock
);
474 ConnectionPort
= ReceivePort
= Port
->ConnectionPort
;
478 KeReleaseGuardedMutex(&LpcpLock
);
479 ObDereferenceObject(Port
);
480 return STATUS_PORT_DISCONNECTED
;
483 /* Release lock and reference */
484 ObReferenceObject(ConnectionPort
);
485 KeReleaseGuardedMutex(&LpcpLock
);
490 /* Otherwise, use the port itself */
494 /* Check if the caller gave a reply message */
497 /* Get the ETHREAD corresponding to it */
498 Status
= PsLookupProcessThreadByCid(&CapturedReplyMessage
.ClientId
,
501 if (!NT_SUCCESS(Status
))
503 /* No thread found, fail */
504 ObDereferenceObject(Port
);
505 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
509 /* Allocate a message from the port zone */
510 Message
= LpcpAllocateFromPortZone();
513 /* Fail if we couldn't allocate a message */
514 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
515 ObDereferenceObject(WakeupThread
);
516 ObDereferenceObject(Port
);
517 return STATUS_NO_MEMORY
;
520 /* Keep the lock acquired */
521 KeAcquireGuardedMutex(&LpcpLock
);
523 /* Make sure this is the reply the thread is waiting for */
524 if ((WakeupThread
->LpcReplyMessageId
!= CapturedReplyMessage
.MessageId
) ||
525 ((LpcpGetMessageFromThread(WakeupThread
)) &&
526 (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread
)->Request
)
530 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
531 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
532 ObDereferenceObject(WakeupThread
);
533 ObDereferenceObject(Port
);
534 return STATUS_REPLY_MESSAGE_MISMATCH
;
537 /* Copy the message */
540 LpcpMoveMessage(&Message
->Request
,
541 &CapturedReplyMessage
,
546 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
548 /* Cleanup and return the exception code */
549 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
550 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
551 ObDereferenceObject(WakeupThread
);
552 ObDereferenceObject(Port
);
553 _SEH2_YIELD(return _SEH2_GetExceptionCode());
557 /* Reference the thread while we use it */
558 ObReferenceObject(WakeupThread
);
559 Message
->RepliedToThread
= WakeupThread
;
561 /* Set this as the reply message */
562 WakeupThread
->LpcReplyMessageId
= 0;
563 WakeupThread
->LpcReplyMessage
= (PVOID
)Message
;
565 /* Check if we have messages on the reply chain */
566 if (!(WakeupThread
->LpcExitThreadCalled
) &&
567 !(IsListEmpty(&WakeupThread
->LpcReplyChain
)))
569 /* Remove us from it and reinitialize it */
570 RemoveEntryList(&WakeupThread
->LpcReplyChain
);
571 InitializeListHead(&WakeupThread
->LpcReplyChain
);
574 /* Check if this is the message the thread had received */
575 if ((Thread
->LpcReceivedMsgIdValid
) &&
576 (Thread
->LpcReceivedMessageId
== CapturedReplyMessage
.MessageId
))
578 /* Clear this data */
579 Thread
->LpcReceivedMessageId
= 0;
580 Thread
->LpcReceivedMsgIdValid
= FALSE
;
583 /* Free any data information */
584 LpcpFreeDataInfoMessage(Port
,
585 CapturedReplyMessage
.MessageId
,
586 CapturedReplyMessage
.CallbackId
,
587 CapturedReplyMessage
.ClientId
);
589 /* Release the lock and release the LPC semaphore to wake up waiters */
590 KeReleaseGuardedMutex(&LpcpLock
);
591 LpcpCompleteWait(&WakeupThread
->LpcReplySemaphore
);
593 /* Now we can let go of the thread */
594 ObDereferenceObject(WakeupThread
);
597 /* Now wait for someone to reply to us */
598 LpcpReceiveWait(ReceivePort
->MsgQueue
.Semaphore
, WaitMode
);
599 if (Status
!= STATUS_SUCCESS
) goto Cleanup
;
601 /* Wait done, get the LPC lock */
602 KeAcquireGuardedMutex(&LpcpLock
);
604 /* Check if we've received nothing */
605 if (IsListEmpty(&ReceivePort
->MsgQueue
.ReceiveHead
))
607 /* Check if this was a waitable port and wake it */
608 if (ReceivePort
->Flags
& LPCP_WAITABLE_PORT
)
610 /* Reset its event */
611 KeClearEvent(&ReceivePort
->WaitEvent
);
614 /* Release the lock and fail */
615 KeReleaseGuardedMutex(&LpcpLock
);
616 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
617 ObDereferenceObject(Port
);
618 return STATUS_UNSUCCESSFUL
;
621 /* Get the message on the queue */
622 Message
= CONTAINING_RECORD(RemoveHeadList(&ReceivePort
->MsgQueue
.ReceiveHead
),
626 /* Check if the queue is empty now */
627 if (IsListEmpty(&ReceivePort
->MsgQueue
.ReceiveHead
))
629 /* Check if this was a waitable port */
630 if (ReceivePort
->Flags
& LPCP_WAITABLE_PORT
)
632 /* Reset its event */
633 KeClearEvent(&ReceivePort
->WaitEvent
);
637 /* Re-initialize the message's list entry */
638 InitializeListHead(&Message
->Entry
);
640 /* Set this as the received message */
641 Thread
->LpcReceivedMessageId
= Message
->Request
.MessageId
;
642 Thread
->LpcReceivedMsgIdValid
= TRUE
;
646 /* Check if this was a connection request */
647 if (LpcpGetMessageType(&Message
->Request
) == LPC_CONNECTION_REQUEST
)
649 /* Get the connection message */
650 ConnectMessage
= (PLPCP_CONNECTION_MESSAGE
)(Message
+ 1);
651 LPCTRACE(LPC_REPLY_DEBUG
,
652 "Request Messages: %p/%p\n",
657 ConnectionInfoLength
= Message
->Request
.u1
.s1
.DataLength
-
658 sizeof(LPCP_CONNECTION_MESSAGE
);
660 /* Return it as the receive message */
661 *ReceiveMessage
= Message
->Request
;
663 /* Clear our stack variable so the message doesn't get freed */
666 /* Setup the receive message */
667 ReceiveMessage
->u1
.s1
.TotalLength
= (CSHORT
)(sizeof(LPCP_MESSAGE
) +
668 ConnectionInfoLength
);
669 ReceiveMessage
->u1
.s1
.DataLength
= (CSHORT
)ConnectionInfoLength
;
670 RtlCopyMemory(ReceiveMessage
+ 1,
672 ConnectionInfoLength
);
674 /* Clear the port context if the caller requested one */
675 if (PortContext
) *PortContext
= NULL
;
677 else if (LpcpGetMessageType(&Message
->Request
) != LPC_REPLY
)
679 /* Otherwise, this is a new message or event */
680 LPCTRACE(LPC_REPLY_DEBUG
,
681 "Non-Reply Messages: %p/%p\n",
683 (&Message
->Request
) + 1);
686 LpcpMoveMessage(ReceiveMessage
,
688 (&Message
->Request
) + 1,
692 /* Return its context */
693 if (PortContext
) *PortContext
= Message
->PortContext
;
695 /* And check if it has data information */
696 if (Message
->Request
.u2
.s2
.DataInfoOffset
)
698 /* It does, save it, and don't free the message below */
699 LpcpSaveDataInfoMessage(Port
, Message
, LPCP_LOCK_HELD
);
705 /* This is a reply message, should never happen! */
709 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
711 Status
= _SEH2_GetExceptionCode();
715 /* Check if we have a message pointer here */
718 /* Free it and release the lock */
719 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
723 /* Just release the lock */
724 KeReleaseGuardedMutex(&LpcpLock
);
728 /* All done, dereference the port and return the status */
729 LPCTRACE(LPC_REPLY_DEBUG
,
730 "Port: %p. Status: %d\n",
733 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
734 ObDereferenceObject(Port
);
743 NtReplyWaitReceivePort(IN HANDLE PortHandle
,
744 OUT PVOID
*PortContext OPTIONAL
,
745 IN PPORT_MESSAGE ReplyMessage OPTIONAL
,
746 OUT PPORT_MESSAGE ReceiveMessage
)
748 /* Call the newer API */
749 return NtReplyWaitReceivePortEx(PortHandle
,
761 NtReplyWaitReplyPort(IN HANDLE PortHandle
,
762 IN PPORT_MESSAGE ReplyMessage
)
765 return STATUS_NOT_IMPLEMENTED
;
772 IN HANDLE PortHandle
,
773 IN PPORT_MESSAGE Message
,
776 IN ULONG BufferLength
,
777 OUT PULONG ReturnLength
)
780 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
781 PORT_MESSAGE CapturedMessage
;
782 PLPCP_PORT_OBJECT Port
= NULL
;
783 PETHREAD ClientThread
= NULL
;
784 SIZE_T LocalReturnLength
;
785 PLPCP_MESSAGE InfoMessage
;
786 PLPCP_DATA_INFO DataInfo
;
787 PVOID DataInfoBaseAddress
;
791 /* Check if the call comes from user mode */
792 if (PreviousMode
!= KernelMode
)
796 ProbeForRead(Message
, sizeof(*Message
), sizeof(PVOID
));
797 CapturedMessage
= *(volatile PORT_MESSAGE
*)Message
;
799 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
801 _SEH2_YIELD(return _SEH2_GetExceptionCode());
807 CapturedMessage
= *Message
;
810 /* Make sure there is any data to copy */
811 if (CapturedMessage
.u2
.s2
.DataInfoOffset
== 0)
813 return STATUS_INVALID_PARAMETER
;
816 /* Reference the port handle */
817 Status
= ObReferenceObjectByHandle(PortHandle
,
823 if (!NT_SUCCESS(Status
))
825 DPRINT1("Failed to reference port handle: 0x%ls\n", Status
);
829 /* Look up the client thread */
830 Status
= PsLookupProcessThreadByCid(&CapturedMessage
.ClientId
,
833 if (!NT_SUCCESS(Status
))
835 DPRINT1("Failed to lookup client thread for [0x%lx:0x%lx]: 0x%ls\n",
836 CapturedMessage
.ClientId
.UniqueProcess
,
837 CapturedMessage
.ClientId
.UniqueThread
, Status
);
841 /* Acquire the global LPC lock */
842 KeAcquireGuardedMutex(&LpcpLock
);
844 /* Check for message id mismatch */
845 if ((ClientThread
->LpcReplyMessageId
!= CapturedMessage
.MessageId
) ||
846 (CapturedMessage
.MessageId
== 0))
848 DPRINT1("LpcReplyMessageId mismatch: 0x%lx/0x%lx.\n",
849 ClientThread
->LpcReplyMessageId
, CapturedMessage
.MessageId
);
850 Status
= STATUS_REPLY_MESSAGE_MISMATCH
;
851 goto CleanupWithLock
;
854 /* Validate the port */
855 if (!LpcpValidateClientPort(ClientThread
, Port
))
857 DPRINT1("LpcpValidateClientPort failed\n");
858 Status
= STATUS_REPLY_MESSAGE_MISMATCH
;
859 goto CleanupWithLock
;
862 /* Find the message with the data */
863 InfoMessage
= LpcpFindDataInfoMessage(Port
,
864 CapturedMessage
.MessageId
,
865 CapturedMessage
.ClientId
);
866 if (InfoMessage
== NULL
)
868 DPRINT1("LpcpFindDataInfoMessage failed\n");
869 Status
= STATUS_INVALID_PARAMETER
;
870 goto CleanupWithLock
;
873 /* Get the data info */
874 DataInfo
= LpcpGetDataInfoFromMessage(&InfoMessage
->Request
);
876 /* Check if the index is within bounds */
877 if (Index
>= DataInfo
->NumberOfEntries
)
879 DPRINT1("Message data index %lu out of bounds (%lu in msg)\n",
880 Index
, DataInfo
->NumberOfEntries
);
881 Status
= STATUS_INVALID_PARAMETER
;
882 goto CleanupWithLock
;
885 /* Check if the caller wants to read/write more data than expected */
886 if (BufferLength
> DataInfo
->Entries
[Index
].DataLength
)
888 DPRINT1("Trying to read more data (%lu) than available (%lu)\n",
889 BufferLength
, DataInfo
->Entries
[Index
].DataLength
);
890 Status
= STATUS_INVALID_PARAMETER
;
891 goto CleanupWithLock
;
894 /* Get the data pointer */
895 DataInfoBaseAddress
= DataInfo
->Entries
[Index
].BaseAddress
;
897 /* Release the lock */
898 KeReleaseGuardedMutex(&LpcpLock
);
902 /* Copy data from the caller to the message sender */
903 Status
= MmCopyVirtualMemory(PsGetCurrentProcess(),
905 ClientThread
->ThreadsProcess
,
913 /* Copy data from the message sender to the caller */
914 Status
= MmCopyVirtualMemory(ClientThread
->ThreadsProcess
,
916 PsGetCurrentProcess(),
923 if (!NT_SUCCESS(Status
))
925 DPRINT1("MmCopyVirtualMemory failed: 0x%ls\n", Status
);
929 /* Check if the caller asked to return the copied length */
930 if (ReturnLength
!= NULL
)
934 *ReturnLength
= LocalReturnLength
;
936 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
939 DPRINT1("Exception writing ReturnLength, ignoring\n");
946 if (ClientThread
!= NULL
)
947 ObDereferenceObject(ClientThread
);
949 ObDereferenceObject(Port
);
955 /* Release the lock */
956 KeReleaseGuardedMutex(&LpcpLock
);
965 NtReadRequestData(IN HANDLE PortHandle
,
966 IN PPORT_MESSAGE Message
,
969 IN ULONG BufferLength
,
970 OUT PULONG ReturnLength
)
972 /* Call the internal function */
973 return LpcpCopyRequestData(FALSE
,
987 NtWriteRequestData(IN HANDLE PortHandle
,
988 IN PPORT_MESSAGE Message
,
991 IN ULONG BufferLength
,
992 OUT PULONG ReturnLength
)
994 /* Call the internal function */
995 return LpcpCopyRequestData(TRUE
,