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
, ConnectionPort
= NULL
;
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
);
259 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
263 /* Allocate a message from the port zone */
264 Message
= LpcpAllocateFromPortZone();
267 /* Fail if we couldn't allocate a message */
268 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
269 ObDereferenceObject(WakeupThread
);
270 ObDereferenceObject(Port
);
271 return STATUS_NO_MEMORY
;
274 /* Keep the lock acquired */
275 KeAcquireGuardedMutex(&LpcpLock
);
277 /* Make sure this is the reply the thread is waiting for */
278 if ((WakeupThread
->LpcReplyMessageId
!= ReplyMessage
->MessageId
) ||
279 ((LpcpGetMessageFromThread(WakeupThread
)) &&
280 (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread
)->
281 Request
) != LPC_REQUEST
)))
284 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
285 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
286 ObDereferenceObject(WakeupThread
);
287 ObDereferenceObject(Port
);
288 return STATUS_REPLY_MESSAGE_MISMATCH
;
291 /* Copy the message */
294 LpcpMoveMessage(&Message
->Request
,
300 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
303 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
304 ObDereferenceObject(WakeupThread
);
305 ObDereferenceObject(Port
);
306 _SEH2_YIELD(return _SEH2_GetExceptionCode());
310 /* Reference the thread while we use it */
311 ObReferenceObject(WakeupThread
);
312 Message
->RepliedToThread
= WakeupThread
;
314 /* Set this as the reply message */
315 WakeupThread
->LpcReplyMessageId
= 0;
316 WakeupThread
->LpcReplyMessage
= (PVOID
)Message
;
318 /* Check if we have messages on the reply chain */
319 if (!(WakeupThread
->LpcExitThreadCalled
) &&
320 !(IsListEmpty(&WakeupThread
->LpcReplyChain
)))
322 /* Remove us from it and reinitialize it */
323 RemoveEntryList(&WakeupThread
->LpcReplyChain
);
324 InitializeListHead(&WakeupThread
->LpcReplyChain
);
327 /* Check if this is the message the thread had received */
328 if ((Thread
->LpcReceivedMsgIdValid
) &&
329 (Thread
->LpcReceivedMessageId
== ReplyMessage
->MessageId
))
331 /* Clear this data */
332 Thread
->LpcReceivedMessageId
= 0;
333 Thread
->LpcReceivedMsgIdValid
= FALSE
;
336 /* Free any data information */
337 LpcpFreeDataInfoMessage(Port
,
338 ReplyMessage
->MessageId
,
339 ReplyMessage
->CallbackId
,
340 ReplyMessage
->ClientId
);
342 /* Release the lock and release the LPC semaphore to wake up waiters */
343 KeReleaseGuardedMutex(&LpcpLock
);
344 LpcpCompleteWait(&WakeupThread
->LpcReplySemaphore
);
346 /* Now we can let go of the thread */
347 ObDereferenceObject(WakeupThread
);
349 /* Dereference port object */
350 ObDereferenceObject(Port
);
359 NtReplyWaitReceivePortEx(IN HANDLE PortHandle
,
360 OUT PVOID
*PortContext OPTIONAL
,
361 IN PPORT_MESSAGE ReplyMessage OPTIONAL
,
362 OUT PPORT_MESSAGE ReceiveMessage
,
363 IN PLARGE_INTEGER Timeout OPTIONAL
)
365 PLPCP_PORT_OBJECT Port
, ReceivePort
, ConnectionPort
= NULL
;
366 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode(), WaitMode
= PreviousMode
;
368 PLPCP_MESSAGE Message
;
369 PETHREAD Thread
= PsGetCurrentThread(), WakeupThread
;
370 PLPCP_CONNECTION_MESSAGE ConnectMessage
;
371 ULONG ConnectionInfoLength
;
372 //PORT_MESSAGE CapturedReplyMessage;
373 LARGE_INTEGER CapturedTimeout
;
376 LPCTRACE(LPC_REPLY_DEBUG
,
377 "Handle: %p. Messages: %p/%p. Context: %p\n",
383 if (KeGetPreviousMode() == UserMode
)
387 if (ReplyMessage
!= NULL
)
389 ProbeForRead(ReplyMessage
, sizeof(PORT_MESSAGE
), sizeof(ULONG
));
390 /*RtlCopyMemory(&CapturedReplyMessage, ReplyMessage, sizeof(PORT_MESSAGE));
391 ReplyMessage = &CapturedReplyMessage;*/
396 ProbeForReadLargeInteger(Timeout
);
397 RtlCopyMemory(&CapturedTimeout
, Timeout
, sizeof(LARGE_INTEGER
));
398 Timeout
= &CapturedTimeout
;
401 if (PortContext
!= NULL
)
402 ProbeForWritePointer(PortContext
);
404 _SEH2_EXCEPT(ExSystemExceptionFilter())
406 DPRINT1("SEH crash [1]\n");
408 _SEH2_YIELD(return _SEH2_GetExceptionCode());
414 /* If this is a system thread, then let it page out its stack */
415 if (Thread
->SystemThread
) WaitMode
= UserMode
;
418 /* Check if caller has a reply message */
421 /* Validate its length */
422 if (((ULONG
)ReplyMessage
->u1
.s1
.DataLength
+ sizeof(PORT_MESSAGE
)) >
423 (ULONG
)ReplyMessage
->u1
.s1
.TotalLength
)
426 return STATUS_INVALID_PARAMETER
;
429 /* Make sure it has a valid ID */
430 if (!ReplyMessage
->MessageId
) return STATUS_INVALID_PARAMETER
;
433 /* Get the Port object */
434 Status
= ObReferenceObjectByHandle(PortHandle
,
440 if (!NT_SUCCESS(Status
)) return Status
;
442 /* Check if the caller has a reply message */
445 /* Validate its length in respect to the port object */
446 if (((ULONG
)ReplyMessage
->u1
.s1
.TotalLength
> Port
->MaxMessageLength
) ||
447 ((ULONG
)ReplyMessage
->u1
.s1
.TotalLength
<=
448 (ULONG
)ReplyMessage
->u1
.s1
.DataLength
))
450 /* Too large, fail */
451 ObDereferenceObject(Port
);
452 return STATUS_PORT_MESSAGE_TOO_LONG
;
456 /* Check if this is anything but a client port */
457 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) != LPCP_CLIENT_PORT
)
459 /* Check if this is the connection port */
460 if (Port
->ConnectionPort
== Port
)
463 ConnectionPort
= ReceivePort
= Port
;
464 ObReferenceObject(ConnectionPort
);
468 /* Acquire the lock */
469 KeAcquireGuardedMutex(&LpcpLock
);
472 ConnectionPort
= ReceivePort
= Port
->ConnectionPort
;
476 KeReleaseGuardedMutex(&LpcpLock
);
477 ObDereferenceObject(Port
);
478 return STATUS_PORT_DISCONNECTED
;
481 /* Release lock and reference */
482 ObReferenceObject(ConnectionPort
);
483 KeReleaseGuardedMutex(&LpcpLock
);
488 /* Otherwise, use the port itself */
492 /* Check if the caller gave a reply message */
495 /* Get the ETHREAD corresponding to it */
496 Status
= PsLookupProcessThreadByCid(&ReplyMessage
->ClientId
,
499 if (!NT_SUCCESS(Status
))
501 /* No thread found, fail */
502 ObDereferenceObject(Port
);
503 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
507 /* Allocate a message from the port zone */
508 Message
= LpcpAllocateFromPortZone();
511 /* Fail if we couldn't allocate a message */
512 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
513 ObDereferenceObject(WakeupThread
);
514 ObDereferenceObject(Port
);
515 return STATUS_NO_MEMORY
;
518 /* Keep the lock acquired */
519 KeAcquireGuardedMutex(&LpcpLock
);
521 /* Make sure this is the reply the thread is waiting for */
522 if ((WakeupThread
->LpcReplyMessageId
!= ReplyMessage
->MessageId
) ||
523 ((LpcpGetMessageFromThread(WakeupThread
)) &&
524 (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread
)->
525 Request
) != LPC_REQUEST
)))
528 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
529 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
530 ObDereferenceObject(WakeupThread
);
531 ObDereferenceObject(Port
);
532 return STATUS_REPLY_MESSAGE_MISMATCH
;
535 /* Copy the message */
536 LpcpMoveMessage(&Message
->Request
,
542 /* Reference the thread while we use it */
543 ObReferenceObject(WakeupThread
);
544 Message
->RepliedToThread
= WakeupThread
;
546 /* Set this as the reply message */
547 WakeupThread
->LpcReplyMessageId
= 0;
548 WakeupThread
->LpcReplyMessage
= (PVOID
)Message
;
550 /* Check if we have messages on the reply chain */
551 if (!(WakeupThread
->LpcExitThreadCalled
) &&
552 !(IsListEmpty(&WakeupThread
->LpcReplyChain
)))
554 /* Remove us from it and reinitialize it */
555 RemoveEntryList(&WakeupThread
->LpcReplyChain
);
556 InitializeListHead(&WakeupThread
->LpcReplyChain
);
559 /* Check if this is the message the thread had received */
560 if ((Thread
->LpcReceivedMsgIdValid
) &&
561 (Thread
->LpcReceivedMessageId
== ReplyMessage
->MessageId
))
563 /* Clear this data */
564 Thread
->LpcReceivedMessageId
= 0;
565 Thread
->LpcReceivedMsgIdValid
= FALSE
;
568 /* Free any data information */
569 LpcpFreeDataInfoMessage(Port
,
570 ReplyMessage
->MessageId
,
571 ReplyMessage
->CallbackId
,
572 ReplyMessage
->ClientId
);
574 /* Release the lock and release the LPC semaphore to wake up waiters */
575 KeReleaseGuardedMutex(&LpcpLock
);
576 LpcpCompleteWait(&WakeupThread
->LpcReplySemaphore
);
578 /* Now we can let go of the thread */
579 ObDereferenceObject(WakeupThread
);
582 /* Now wait for someone to reply to us */
583 LpcpReceiveWait(ReceivePort
->MsgQueue
.Semaphore
, WaitMode
);
584 if (Status
!= STATUS_SUCCESS
) goto Cleanup
;
586 /* Wait done, get the LPC lock */
587 KeAcquireGuardedMutex(&LpcpLock
);
589 /* Check if we've received nothing */
590 if (IsListEmpty(&ReceivePort
->MsgQueue
.ReceiveHead
))
592 /* Check if this was a waitable port and wake it */
593 if (ReceivePort
->Flags
& LPCP_WAITABLE_PORT
)
595 /* Reset its event */
596 KeResetEvent(&ReceivePort
->WaitEvent
);
599 /* Release the lock and fail */
600 KeReleaseGuardedMutex(&LpcpLock
);
601 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
602 ObDereferenceObject(Port
);
603 return STATUS_UNSUCCESSFUL
;
606 /* Get the message on the queue */
607 Message
= CONTAINING_RECORD(RemoveHeadList(&ReceivePort
->
608 MsgQueue
.ReceiveHead
),
612 /* Check if the queue is empty now */
613 if (IsListEmpty(&ReceivePort
->MsgQueue
.ReceiveHead
))
615 /* Check if this was a waitable port */
616 if (ReceivePort
->Flags
& LPCP_WAITABLE_PORT
)
618 /* Reset its event */
619 KeResetEvent(&ReceivePort
->WaitEvent
);
623 /* Re-initialize the message's list entry */
624 InitializeListHead(&Message
->Entry
);
626 /* Set this as the received message */
627 Thread
->LpcReceivedMessageId
= Message
->Request
.MessageId
;
628 Thread
->LpcReceivedMsgIdValid
= TRUE
;
632 /* Check if this was a connection request */
633 if (LpcpGetMessageType(&Message
->Request
) == LPC_CONNECTION_REQUEST
)
635 /* Get the connection message */
636 ConnectMessage
= (PLPCP_CONNECTION_MESSAGE
)(Message
+ 1);
637 LPCTRACE(LPC_REPLY_DEBUG
,
638 "Request Messages: %p/%p\n",
643 ConnectionInfoLength
= Message
->Request
.u1
.s1
.DataLength
-
644 sizeof(LPCP_CONNECTION_MESSAGE
);
646 /* Return it as the receive message */
647 *ReceiveMessage
= Message
->Request
;
649 /* Clear our stack variable so the message doesn't get freed */
652 /* Setup the receive message */
653 ReceiveMessage
->u1
.s1
.TotalLength
= (CSHORT
)(sizeof(LPCP_MESSAGE
) +
654 ConnectionInfoLength
);
655 ReceiveMessage
->u1
.s1
.DataLength
= (CSHORT
)ConnectionInfoLength
;
656 RtlCopyMemory(ReceiveMessage
+ 1,
658 ConnectionInfoLength
);
660 /* Clear the port context if the caller requested one */
661 if (PortContext
) *PortContext
= NULL
;
663 else if (LpcpGetMessageType(&Message
->Request
) != LPC_REPLY
)
665 /* Otherwise, this is a new message or event */
666 LPCTRACE(LPC_REPLY_DEBUG
,
667 "Non-Reply Messages: %p/%p\n",
669 (&Message
->Request
) + 1);
672 LpcpMoveMessage(ReceiveMessage
,
674 (&Message
->Request
) + 1,
678 /* Return its context */
679 if (PortContext
) *PortContext
= Message
->PortContext
;
681 /* And check if it has data information */
682 if (Message
->Request
.u2
.s2
.DataInfoOffset
)
684 /* It does, save it, and don't free the message below */
685 LpcpSaveDataInfoMessage(Port
, Message
, LPCP_LOCK_HELD
);
691 /* This is a reply message, should never happen! */
695 _SEH2_EXCEPT(ExSystemExceptionFilter())
697 DPRINT1("SEH crash [2]\n");
699 Status
= _SEH2_GetExceptionCode();
703 /* Check if we have a message pointer here */
706 /* Free it and release the lock */
707 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
711 /* Just release the lock */
712 KeReleaseGuardedMutex(&LpcpLock
);
716 /* All done, dereference the port and return the status */
717 LPCTRACE(LPC_REPLY_DEBUG
,
718 "Port: %p. Status: %d\n",
721 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
722 ObDereferenceObject(Port
);
731 NtReplyWaitReceivePort(IN HANDLE PortHandle
,
732 OUT PVOID
*PortContext OPTIONAL
,
733 IN PPORT_MESSAGE ReplyMessage OPTIONAL
,
734 OUT PPORT_MESSAGE ReceiveMessage
)
736 /* Call the newer API */
737 return NtReplyWaitReceivePortEx(PortHandle
,
749 NtReplyWaitReplyPort(IN HANDLE PortHandle
,
750 IN PPORT_MESSAGE ReplyMessage
)
753 return STATUS_NOT_IMPLEMENTED
;
760 IN HANDLE PortHandle
,
761 IN PPORT_MESSAGE Message
,
764 IN ULONG BufferLength
,
765 OUT PULONG Returnlength
)
767 KPROCESSOR_MODE PreviousMode
;
768 PORT_MESSAGE CapturedMessage
;
769 PLPCP_PORT_OBJECT Port
= NULL
;
770 PETHREAD ClientThread
= NULL
;
771 ULONG LocalReturnlength
;
772 PLPCP_MESSAGE InfoMessage
;
773 PLPCP_DATA_INFO DataInfo
;
774 PVOID DataInfoBaseAddress
;
778 /* Check the previous mode */
779 PreviousMode
= ExGetPreviousMode();
780 if (PreviousMode
== KernelMode
)
782 CapturedMessage
= *Message
;
788 ProbeForRead(Message
, sizeof(*Message
), sizeof(PVOID
));
789 CapturedMessage
= *Message
;
791 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
793 DPRINT1("Got exception!\n");
794 return _SEH2_GetExceptionCode();
799 /* Make sure there is any data to copy */
800 if (CapturedMessage
.u2
.s2
.DataInfoOffset
== 0)
802 return STATUS_INVALID_PARAMETER
;
805 /* Reference the port handle */
806 Status
= ObReferenceObjectByHandle(PortHandle
,
812 if (!NT_SUCCESS(Status
))
814 DPRINT1("Failed to reference port handle: 0x%ls\n", Status
);
818 /* Look up the client thread */
819 Status
= PsLookupProcessThreadByCid(&CapturedMessage
.ClientId
,
822 if (!NT_SUCCESS(Status
))
824 DPRINT1("Failed to lookup client thread for [0x%lx:0x%lx]: 0x%ls\n",
825 CapturedMessage
.ClientId
.UniqueProcess
,
826 CapturedMessage
.ClientId
.UniqueThread
, Status
);
830 /* Acquire the global LPC lock */
831 KeAcquireGuardedMutex(&LpcpLock
);
833 /* Check for message id mismatch */
834 if ((ClientThread
->LpcReplyMessageId
!= CapturedMessage
.MessageId
) ||
835 (CapturedMessage
.MessageId
== 0))
837 DPRINT1("LpcReplyMessageId mismatch: 0x%lx/0x%lx.\n",
838 ClientThread
->LpcReplyMessageId
, CapturedMessage
.MessageId
);
839 Status
= STATUS_REPLY_MESSAGE_MISMATCH
;
840 goto CleanupWithLock
;
843 /* Validate the port */
844 if (!LpcpValidateClientPort(ClientThread
, Port
))
846 DPRINT1("LpcpValidateClientPort failed\n");
847 Status
= STATUS_REPLY_MESSAGE_MISMATCH
;
848 goto CleanupWithLock
;
851 /* Find the message with the data */
852 InfoMessage
= LpcpFindDataInfoMessage(Port
,
853 CapturedMessage
.MessageId
,
854 CapturedMessage
.ClientId
);
855 if (InfoMessage
== NULL
)
857 DPRINT1("LpcpFindDataInfoMessage failed\n");
858 Status
= STATUS_INVALID_PARAMETER
;
859 goto CleanupWithLock
;
862 /* Get the data info */
863 DataInfo
= LpcpGetDataInfoFromMessage(&InfoMessage
->Request
);
865 /* Check if the index is within bounds */
866 if (Index
>= DataInfo
->NumberOfEntries
)
868 DPRINT1("Message data index %lu out of bounds (%lu in msg)\n",
869 Index
, DataInfo
->NumberOfEntries
);
870 Status
= STATUS_INVALID_PARAMETER
;
871 goto CleanupWithLock
;
874 /* Check if the caller wants to read/write more data than expected */
875 if (BufferLength
> DataInfo
->Entries
[Index
].DataLength
)
877 DPRINT1("Trying to read more data (%lu) than available (%lu)\n",
878 BufferLength
, DataInfo
->Entries
[Index
].DataLength
);
879 Status
= STATUS_INVALID_PARAMETER
;
880 goto CleanupWithLock
;
883 /* Get the data pointer */
884 DataInfoBaseAddress
= DataInfo
->Entries
[Index
].BaseAddress
;
886 /* Release the lock */
887 KeReleaseGuardedMutex(&LpcpLock
);
891 /* Copy data from the caller to the message sender */
892 Status
= MmCopyVirtualMemory(PsGetCurrentProcess(),
894 ClientThread
->ThreadsProcess
,
902 /* Copy data from the message sender to the caller */
903 Status
= MmCopyVirtualMemory(ClientThread
->ThreadsProcess
,
905 PsGetCurrentProcess(),
912 if (!NT_SUCCESS(Status
))
914 DPRINT1("MmCopyVirtualMemory failed: 0x%ls\n", Status
);
918 /* Check if the caller asked to return the copied length */
919 if (Returnlength
!= NULL
)
923 *Returnlength
= LocalReturnlength
;
925 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
928 DPRINT1("Exception writing Returnlength, ignoring\n");
935 if (ClientThread
!= NULL
)
936 ObDereferenceObject(ClientThread
);
938 ObDereferenceObject(Port
);
944 /* Release the lock */
945 KeReleaseGuardedMutex(&LpcpLock
);
954 NtReadRequestData(IN HANDLE PortHandle
,
955 IN PPORT_MESSAGE Message
,
958 IN ULONG BufferLength
,
959 OUT PULONG ReturnLength
)
961 /* Call the internal function */
962 return LpcpCopyRequestData(FALSE
,
976 NtWriteRequestData(IN HANDLE PortHandle
,
977 IN PPORT_MESSAGE Message
,
980 IN ULONG BufferLength
,
981 OUT PULONG ReturnLength
)
983 /* Call the internal function */
984 return LpcpCopyRequestData(TRUE
,