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");
215 _SEH2_YIELD(return _SEH2_GetExceptionCode());
220 /* Validate its length */
221 if (((ULONG
)ReplyMessage
->u1
.s1
.DataLength
+ sizeof(PORT_MESSAGE
)) >
222 (ULONG
)ReplyMessage
->u1
.s1
.TotalLength
)
225 return STATUS_INVALID_PARAMETER
;
228 /* Make sure it has a valid ID */
229 if (!ReplyMessage
->MessageId
) return STATUS_INVALID_PARAMETER
;
231 /* Get the Port object */
232 Status
= ObReferenceObjectByHandle(PortHandle
,
238 if (!NT_SUCCESS(Status
)) return Status
;
240 /* Validate its length in respect to the port object */
241 if (((ULONG
)ReplyMessage
->u1
.s1
.TotalLength
> Port
->MaxMessageLength
) ||
242 ((ULONG
)ReplyMessage
->u1
.s1
.TotalLength
<=
243 (ULONG
)ReplyMessage
->u1
.s1
.DataLength
))
245 /* Too large, fail */
246 ObDereferenceObject(Port
);
247 return STATUS_PORT_MESSAGE_TOO_LONG
;
250 /* Get the ETHREAD corresponding to it */
251 Status
= PsLookupProcessThreadByCid(&ReplyMessage
->ClientId
,
254 if (!NT_SUCCESS(Status
))
256 /* No thread found, fail */
257 ObDereferenceObject(Port
);
261 /* Allocate a message from the port zone */
262 Message
= LpcpAllocateFromPortZone();
265 /* Fail if we couldn't allocate a message */
266 ObDereferenceObject(WakeupThread
);
267 ObDereferenceObject(Port
);
268 return STATUS_NO_MEMORY
;
271 /* Keep the lock acquired */
272 KeAcquireGuardedMutex(&LpcpLock
);
274 /* Make sure this is the reply the thread is waiting for */
275 if ((WakeupThread
->LpcReplyMessageId
!= ReplyMessage
->MessageId
) ||
276 ((LpcpGetMessageFromThread(WakeupThread
)) &&
277 (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread
)->
278 Request
) != LPC_REQUEST
)))
281 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
282 ObDereferenceObject(WakeupThread
);
283 ObDereferenceObject(Port
);
284 return STATUS_REPLY_MESSAGE_MISMATCH
;
287 /* Copy the message */
290 LpcpMoveMessage(&Message
->Request
,
296 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
299 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
300 ObDereferenceObject(WakeupThread
);
301 ObDereferenceObject(Port
);
302 _SEH2_YIELD(return _SEH2_GetExceptionCode());
306 /* Reference the thread while we use it */
307 ObReferenceObject(WakeupThread
);
308 Message
->RepliedToThread
= WakeupThread
;
310 /* Set this as the reply message */
311 WakeupThread
->LpcReplyMessageId
= 0;
312 WakeupThread
->LpcReplyMessage
= (PVOID
)Message
;
314 /* Check if we have messages on the reply chain */
315 if (!(WakeupThread
->LpcExitThreadCalled
) &&
316 !(IsListEmpty(&WakeupThread
->LpcReplyChain
)))
318 /* Remove us from it and reinitialize it */
319 RemoveEntryList(&WakeupThread
->LpcReplyChain
);
320 InitializeListHead(&WakeupThread
->LpcReplyChain
);
323 /* Check if this is the message the thread had received */
324 if ((Thread
->LpcReceivedMsgIdValid
) &&
325 (Thread
->LpcReceivedMessageId
== ReplyMessage
->MessageId
))
327 /* Clear this data */
328 Thread
->LpcReceivedMessageId
= 0;
329 Thread
->LpcReceivedMsgIdValid
= FALSE
;
332 /* Free any data information */
333 LpcpFreeDataInfoMessage(Port
,
334 ReplyMessage
->MessageId
,
335 ReplyMessage
->CallbackId
,
336 ReplyMessage
->ClientId
);
338 /* Release the lock and release the LPC semaphore to wake up waiters */
339 KeReleaseGuardedMutex(&LpcpLock
);
340 LpcpCompleteWait(&WakeupThread
->LpcReplySemaphore
);
342 /* Now we can let go of the thread */
343 ObDereferenceObject(WakeupThread
);
345 /* Dereference port object */
346 ObDereferenceObject(Port
);
355 NtReplyWaitReceivePortEx(IN HANDLE PortHandle
,
356 OUT PVOID
*PortContext OPTIONAL
,
357 IN PPORT_MESSAGE ReplyMessage OPTIONAL
,
358 OUT PPORT_MESSAGE ReceiveMessage
,
359 IN PLARGE_INTEGER Timeout OPTIONAL
)
361 PLPCP_PORT_OBJECT Port
, ReceivePort
, ConnectionPort
= NULL
;
362 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode(), WaitMode
= PreviousMode
;
364 PLPCP_MESSAGE Message
;
365 PETHREAD Thread
= PsGetCurrentThread(), WakeupThread
;
366 PLPCP_CONNECTION_MESSAGE ConnectMessage
;
367 ULONG ConnectionInfoLength
;
368 //PORT_MESSAGE CapturedReplyMessage;
369 LARGE_INTEGER CapturedTimeout
;
372 LPCTRACE(LPC_REPLY_DEBUG
,
373 "Handle: %p. Messages: %p/%p. Context: %p\n",
379 if (KeGetPreviousMode() == UserMode
)
383 if (ReplyMessage
!= NULL
)
385 ProbeForRead(ReplyMessage
, sizeof(PORT_MESSAGE
), sizeof(ULONG
));
386 /*RtlCopyMemory(&CapturedReplyMessage, ReplyMessage, sizeof(PORT_MESSAGE));
387 ReplyMessage = &CapturedReplyMessage;*/
392 ProbeForReadLargeInteger(Timeout
);
393 RtlCopyMemory(&CapturedTimeout
, Timeout
, sizeof(LARGE_INTEGER
));
394 Timeout
= &CapturedTimeout
;
397 if (PortContext
!= NULL
)
398 ProbeForWritePointer(PortContext
);
400 _SEH2_EXCEPT(ExSystemExceptionFilter())
402 DPRINT1("SEH crash [1]\n");
403 _SEH2_YIELD(return _SEH2_GetExceptionCode());
409 /* If this is a system thread, then let it page out its stack */
410 if (Thread
->SystemThread
) WaitMode
= UserMode
;
413 /* Check if caller has a reply message */
416 /* Validate its length */
417 if (((ULONG
)ReplyMessage
->u1
.s1
.DataLength
+ sizeof(PORT_MESSAGE
)) >
418 (ULONG
)ReplyMessage
->u1
.s1
.TotalLength
)
421 return STATUS_INVALID_PARAMETER
;
424 /* Make sure it has a valid ID */
425 if (!ReplyMessage
->MessageId
) return STATUS_INVALID_PARAMETER
;
428 /* Get the Port object */
429 Status
= ObReferenceObjectByHandle(PortHandle
,
435 if (!NT_SUCCESS(Status
)) return Status
;
437 /* Check if the caller has a reply message */
440 /* Validate its length in respect to the port object */
441 if (((ULONG
)ReplyMessage
->u1
.s1
.TotalLength
> Port
->MaxMessageLength
) ||
442 ((ULONG
)ReplyMessage
->u1
.s1
.TotalLength
<=
443 (ULONG
)ReplyMessage
->u1
.s1
.DataLength
))
445 /* Too large, fail */
446 ObDereferenceObject(Port
);
447 return STATUS_PORT_MESSAGE_TOO_LONG
;
451 /* Check if this is anything but a client port */
452 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) != LPCP_CLIENT_PORT
)
454 /* Check if this is the connection port */
455 if (Port
->ConnectionPort
== Port
)
458 ConnectionPort
= ReceivePort
= Port
;
459 ObReferenceObject(ConnectionPort
);
463 /* Acquire the lock */
464 KeAcquireGuardedMutex(&LpcpLock
);
467 ConnectionPort
= ReceivePort
= Port
->ConnectionPort
;
471 KeReleaseGuardedMutex(&LpcpLock
);
472 ObDereferenceObject(Port
);
473 return STATUS_PORT_DISCONNECTED
;
476 /* Release lock and reference */
477 ObReferenceObject(ConnectionPort
);
478 KeReleaseGuardedMutex(&LpcpLock
);
483 /* Otherwise, use the port itself */
487 /* Check if the caller gave a reply message */
490 /* Get the ETHREAD corresponding to it */
491 Status
= PsLookupProcessThreadByCid(&ReplyMessage
->ClientId
,
494 if (!NT_SUCCESS(Status
))
496 /* No thread found, fail */
497 ObDereferenceObject(Port
);
498 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
502 /* Allocate a message from the port zone */
503 Message
= LpcpAllocateFromPortZone();
506 /* Fail if we couldn't allocate a message */
507 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
508 ObDereferenceObject(WakeupThread
);
509 ObDereferenceObject(Port
);
510 return STATUS_NO_MEMORY
;
513 /* Keep the lock acquired */
514 KeAcquireGuardedMutex(&LpcpLock
);
516 /* Make sure this is the reply the thread is waiting for */
517 if ((WakeupThread
->LpcReplyMessageId
!= ReplyMessage
->MessageId
) ||
518 ((LpcpGetMessageFromThread(WakeupThread
)) &&
519 (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread
)->
520 Request
) != LPC_REQUEST
)))
523 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
524 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
525 ObDereferenceObject(WakeupThread
);
526 ObDereferenceObject(Port
);
527 return STATUS_REPLY_MESSAGE_MISMATCH
;
530 /* Copy the message */
531 LpcpMoveMessage(&Message
->Request
,
537 /* Reference the thread while we use it */
538 ObReferenceObject(WakeupThread
);
539 Message
->RepliedToThread
= WakeupThread
;
541 /* Set this as the reply message */
542 WakeupThread
->LpcReplyMessageId
= 0;
543 WakeupThread
->LpcReplyMessage
= (PVOID
)Message
;
545 /* Check if we have messages on the reply chain */
546 if (!(WakeupThread
->LpcExitThreadCalled
) &&
547 !(IsListEmpty(&WakeupThread
->LpcReplyChain
)))
549 /* Remove us from it and reinitialize it */
550 RemoveEntryList(&WakeupThread
->LpcReplyChain
);
551 InitializeListHead(&WakeupThread
->LpcReplyChain
);
554 /* Check if this is the message the thread had received */
555 if ((Thread
->LpcReceivedMsgIdValid
) &&
556 (Thread
->LpcReceivedMessageId
== ReplyMessage
->MessageId
))
558 /* Clear this data */
559 Thread
->LpcReceivedMessageId
= 0;
560 Thread
->LpcReceivedMsgIdValid
= FALSE
;
563 /* Free any data information */
564 LpcpFreeDataInfoMessage(Port
,
565 ReplyMessage
->MessageId
,
566 ReplyMessage
->CallbackId
,
567 ReplyMessage
->ClientId
);
569 /* Release the lock and release the LPC semaphore to wake up waiters */
570 KeReleaseGuardedMutex(&LpcpLock
);
571 LpcpCompleteWait(&WakeupThread
->LpcReplySemaphore
);
573 /* Now we can let go of the thread */
574 ObDereferenceObject(WakeupThread
);
577 /* Now wait for someone to reply to us */
578 LpcpReceiveWait(ReceivePort
->MsgQueue
.Semaphore
, WaitMode
);
579 if (Status
!= STATUS_SUCCESS
) goto Cleanup
;
581 /* Wait done, get the LPC lock */
582 KeAcquireGuardedMutex(&LpcpLock
);
584 /* Check if we've received nothing */
585 if (IsListEmpty(&ReceivePort
->MsgQueue
.ReceiveHead
))
587 /* Check if this was a waitable port and wake it */
588 if (ReceivePort
->Flags
& LPCP_WAITABLE_PORT
)
590 /* Reset its event */
591 KeResetEvent(&ReceivePort
->WaitEvent
);
594 /* Release the lock and fail */
595 KeReleaseGuardedMutex(&LpcpLock
);
596 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
597 ObDereferenceObject(Port
);
598 return STATUS_UNSUCCESSFUL
;
601 /* Get the message on the queue */
602 Message
= CONTAINING_RECORD(RemoveHeadList(&ReceivePort
->
603 MsgQueue
.ReceiveHead
),
607 /* Check if the queue is empty now */
608 if (IsListEmpty(&ReceivePort
->MsgQueue
.ReceiveHead
))
610 /* Check if this was a waitable port */
611 if (ReceivePort
->Flags
& LPCP_WAITABLE_PORT
)
613 /* Reset its event */
614 KeResetEvent(&ReceivePort
->WaitEvent
);
618 /* Re-initialize the message's list entry */
619 InitializeListHead(&Message
->Entry
);
621 /* Set this as the received message */
622 Thread
->LpcReceivedMessageId
= Message
->Request
.MessageId
;
623 Thread
->LpcReceivedMsgIdValid
= TRUE
;
627 /* Check if this was a connection request */
628 if (LpcpGetMessageType(&Message
->Request
) == LPC_CONNECTION_REQUEST
)
630 /* Get the connection message */
631 ConnectMessage
= (PLPCP_CONNECTION_MESSAGE
)(Message
+ 1);
632 LPCTRACE(LPC_REPLY_DEBUG
,
633 "Request Messages: %p/%p\n",
638 ConnectionInfoLength
= Message
->Request
.u1
.s1
.DataLength
-
639 sizeof(LPCP_CONNECTION_MESSAGE
);
641 /* Return it as the receive message */
642 *ReceiveMessage
= Message
->Request
;
644 /* Clear our stack variable so the message doesn't get freed */
647 /* Setup the receive message */
648 ReceiveMessage
->u1
.s1
.TotalLength
= (CSHORT
)(sizeof(LPCP_MESSAGE
) +
649 ConnectionInfoLength
);
650 ReceiveMessage
->u1
.s1
.DataLength
= (CSHORT
)ConnectionInfoLength
;
651 RtlCopyMemory(ReceiveMessage
+ 1,
653 ConnectionInfoLength
);
655 /* Clear the port context if the caller requested one */
656 if (PortContext
) *PortContext
= NULL
;
658 else if (LpcpGetMessageType(&Message
->Request
) != LPC_REPLY
)
660 /* Otherwise, this is a new message or event */
661 LPCTRACE(LPC_REPLY_DEBUG
,
662 "Non-Reply Messages: %p/%p\n",
664 (&Message
->Request
) + 1);
667 LpcpMoveMessage(ReceiveMessage
,
669 (&Message
->Request
) + 1,
673 /* Return its context */
674 if (PortContext
) *PortContext
= Message
->PortContext
;
676 /* And check if it has data information */
677 if (Message
->Request
.u2
.s2
.DataInfoOffset
)
679 /* It does, save it, and don't free the message below */
680 LpcpSaveDataInfoMessage(Port
, Message
, LPCP_LOCK_HELD
);
686 /* This is a reply message, should never happen! */
690 _SEH2_EXCEPT(ExSystemExceptionFilter())
692 DPRINT1("SEH crash [2]\n");
693 Status
= _SEH2_GetExceptionCode();
697 /* Check if we have a message pointer here */
700 /* Free it and release the lock */
701 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
| LPCP_LOCK_RELEASE
);
705 /* Just release the lock */
706 KeReleaseGuardedMutex(&LpcpLock
);
710 /* All done, dereference the port and return the status */
711 LPCTRACE(LPC_REPLY_DEBUG
,
712 "Port: %p. Status: %d\n",
715 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
716 ObDereferenceObject(Port
);
725 NtReplyWaitReceivePort(IN HANDLE PortHandle
,
726 OUT PVOID
*PortContext OPTIONAL
,
727 IN PPORT_MESSAGE ReplyMessage OPTIONAL
,
728 OUT PPORT_MESSAGE ReceiveMessage
)
730 /* Call the newer API */
731 return NtReplyWaitReceivePortEx(PortHandle
,
743 NtReplyWaitReplyPort(IN HANDLE PortHandle
,
744 IN PPORT_MESSAGE ReplyMessage
)
747 return STATUS_NOT_IMPLEMENTED
;
754 IN HANDLE PortHandle
,
755 IN PPORT_MESSAGE Message
,
758 IN ULONG BufferLength
,
759 OUT PULONG Returnlength
)
761 KPROCESSOR_MODE PreviousMode
;
762 PORT_MESSAGE CapturedMessage
;
763 PLPCP_PORT_OBJECT Port
= NULL
;
764 PETHREAD ClientThread
= NULL
;
765 SIZE_T LocalReturnlength
;
766 PLPCP_MESSAGE InfoMessage
;
767 PLPCP_DATA_INFO DataInfo
;
768 PVOID DataInfoBaseAddress
;
772 /* Check the previous mode */
773 PreviousMode
= ExGetPreviousMode();
774 if (PreviousMode
== KernelMode
)
776 CapturedMessage
= *Message
;
782 ProbeForRead(Message
, sizeof(*Message
), sizeof(PVOID
));
783 CapturedMessage
= *Message
;
785 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
787 DPRINT1("Got exception!\n");
788 return _SEH2_GetExceptionCode();
793 /* Make sure there is any data to copy */
794 if (CapturedMessage
.u2
.s2
.DataInfoOffset
== 0)
796 return STATUS_INVALID_PARAMETER
;
799 /* Reference the port handle */
800 Status
= ObReferenceObjectByHandle(PortHandle
,
806 if (!NT_SUCCESS(Status
))
808 DPRINT1("Failed to reference port handle: 0x%ls\n", Status
);
812 /* Look up the client thread */
813 Status
= PsLookupProcessThreadByCid(&CapturedMessage
.ClientId
,
816 if (!NT_SUCCESS(Status
))
818 DPRINT1("Failed to lookup client thread for [0x%lx:0x%lx]: 0x%ls\n",
819 CapturedMessage
.ClientId
.UniqueProcess
,
820 CapturedMessage
.ClientId
.UniqueThread
, Status
);
824 /* Acquire the global LPC lock */
825 KeAcquireGuardedMutex(&LpcpLock
);
827 /* Check for message id mismatch */
828 if ((ClientThread
->LpcReplyMessageId
!= CapturedMessage
.MessageId
) ||
829 (CapturedMessage
.MessageId
== 0))
831 DPRINT1("LpcReplyMessageId mismatch: 0x%lx/0x%lx.\n",
832 ClientThread
->LpcReplyMessageId
, CapturedMessage
.MessageId
);
833 Status
= STATUS_REPLY_MESSAGE_MISMATCH
;
834 goto CleanupWithLock
;
837 /* Validate the port */
838 if (!LpcpValidateClientPort(ClientThread
, Port
))
840 DPRINT1("LpcpValidateClientPort failed\n");
841 Status
= STATUS_REPLY_MESSAGE_MISMATCH
;
842 goto CleanupWithLock
;
845 /* Find the message with the data */
846 InfoMessage
= LpcpFindDataInfoMessage(Port
,
847 CapturedMessage
.MessageId
,
848 CapturedMessage
.ClientId
);
849 if (InfoMessage
== NULL
)
851 DPRINT1("LpcpFindDataInfoMessage failed\n");
852 Status
= STATUS_INVALID_PARAMETER
;
853 goto CleanupWithLock
;
856 /* Get the data info */
857 DataInfo
= LpcpGetDataInfoFromMessage(&InfoMessage
->Request
);
859 /* Check if the index is within bounds */
860 if (Index
>= DataInfo
->NumberOfEntries
)
862 DPRINT1("Message data index %lu out of bounds (%lu in msg)\n",
863 Index
, DataInfo
->NumberOfEntries
);
864 Status
= STATUS_INVALID_PARAMETER
;
865 goto CleanupWithLock
;
868 /* Check if the caller wants to read/write more data than expected */
869 if (BufferLength
> DataInfo
->Entries
[Index
].DataLength
)
871 DPRINT1("Trying to read more data (%lu) than available (%lu)\n",
872 BufferLength
, DataInfo
->Entries
[Index
].DataLength
);
873 Status
= STATUS_INVALID_PARAMETER
;
874 goto CleanupWithLock
;
877 /* Get the data pointer */
878 DataInfoBaseAddress
= DataInfo
->Entries
[Index
].BaseAddress
;
880 /* Release the lock */
881 KeReleaseGuardedMutex(&LpcpLock
);
885 /* Copy data from the caller to the message sender */
886 Status
= MmCopyVirtualMemory(PsGetCurrentProcess(),
888 ClientThread
->ThreadsProcess
,
896 /* Copy data from the message sender to the caller */
897 Status
= MmCopyVirtualMemory(ClientThread
->ThreadsProcess
,
899 PsGetCurrentProcess(),
906 if (!NT_SUCCESS(Status
))
908 DPRINT1("MmCopyVirtualMemory failed: 0x%ls\n", Status
);
912 /* Check if the caller asked to return the copied length */
913 if (Returnlength
!= NULL
)
917 *Returnlength
= LocalReturnlength
;
919 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
922 DPRINT1("Exception writing Returnlength, ignoring\n");
929 if (ClientThread
!= NULL
)
930 ObDereferenceObject(ClientThread
);
932 ObDereferenceObject(Port
);
938 /* Release the lock */
939 KeReleaseGuardedMutex(&LpcpLock
);
948 NtReadRequestData(IN HANDLE PortHandle
,
949 IN PPORT_MESSAGE Message
,
952 IN ULONG BufferLength
,
953 OUT PULONG ReturnLength
)
955 /* Call the internal function */
956 return LpcpCopyRequestData(FALSE
,
970 NtWriteRequestData(IN HANDLE PortHandle
,
971 IN PPORT_MESSAGE Message
,
974 IN ULONG BufferLength
,
975 OUT PULONG ReturnLength
)
977 /* Call the internal function */
978 return LpcpCopyRequestData(TRUE
,