744c9105232321978d7da0989e090101881c6aeb
[reactos.git] / reactos / ntoskrnl / lpc / reply.c
1 /*
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)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* PRIVATE FUNCTIONS *********************************************************/
16
17 VOID
18 NTAPI
19 LpcpFreeDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
20 IN ULONG MessageId,
21 IN ULONG CallbackId,
22 IN CLIENT_ID ClientId)
23 {
24 PLPCP_MESSAGE Message;
25 PLIST_ENTRY ListHead, NextEntry;
26
27 /* Check if the port we want is the connection port */
28 if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT)
29 {
30 /* Use it */
31 Port = Port->ConnectionPort;
32 if (!Port) return;
33 }
34
35 /* Loop the list */
36 ListHead = &Port->LpcDataInfoChainHead;
37 NextEntry = ListHead->Flink;
38 while (ListHead != NextEntry)
39 {
40 /* Get the message */
41 Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
42
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))
47 {
48 /* Unlink and free it */
49 RemoveEntryList(&Message->Entry);
50 InitializeListHead(&Message->Entry);
51 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD);
52 break;
53 }
54
55 /* Go to the next entry */
56 NextEntry = NextEntry->Flink;
57 }
58 }
59
60 VOID
61 NTAPI
62 LpcpSaveDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
63 IN PLPCP_MESSAGE Message,
64 IN ULONG LockFlags)
65 {
66 BOOLEAN LockHeld = (LockFlags & LPCP_LOCK_HELD);
67
68 PAGED_CODE();
69
70 /* Acquire the lock */
71 if (!LockHeld) KeAcquireGuardedMutex(&LpcpLock);
72
73 /* Check if the port we want is the connection port */
74 if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT)
75 {
76 /* Use it */
77 Port = Port->ConnectionPort;
78 if (!Port)
79 {
80 /* Release the lock and return */
81 if (!LockHeld) KeReleaseGuardedMutex(&LpcpLock);
82 return;
83 }
84 }
85
86 /* Link the message */
87 InsertTailList(&Port->LpcDataInfoChainHead, &Message->Entry);
88
89 /* Release the lock */
90 if (!LockHeld) KeReleaseGuardedMutex(&LpcpLock);
91 }
92
93 VOID
94 NTAPI
95 LpcpMoveMessage(IN PPORT_MESSAGE Destination,
96 IN PPORT_MESSAGE Origin,
97 IN PVOID Data,
98 IN ULONG MessageType,
99 IN PCLIENT_ID ClientId)
100 {
101 /* Set the Message size */
102 LPCTRACE((LPC_REPLY_DEBUG | LPC_SEND_DEBUG),
103 "Destination/Origin: %p/%p. Data: %p. Length: %lx\n",
104 Destination,
105 Origin,
106 Data,
107 Origin->u1.Length);
108 Destination->u1.Length = Origin->u1.Length;
109
110 /* Set the Message Type */
111 Destination->u2.s2.Type = !MessageType ?
112 Origin->u2.s2.Type : MessageType & 0xFFFF;
113
114 /* Check if we have a Client ID */
115 if (ClientId)
116 {
117 /* Set the Client ID */
118 Destination->ClientId.UniqueProcess = ClientId->UniqueProcess;
119 Destination->ClientId.UniqueThread = ClientId->UniqueThread;
120 }
121 else
122 {
123 /* Otherwise, copy it */
124 Destination->ClientId.UniqueProcess = Origin->ClientId.UniqueProcess;
125 Destination->ClientId.UniqueThread = Origin->ClientId.UniqueThread;
126 }
127
128 /* Copy the MessageId and ClientViewSize */
129 Destination->MessageId = Origin->MessageId;
130 Destination->ClientViewSize = Origin->ClientViewSize;
131
132 /* Copy the Message Data */
133 RtlCopyMemory(Destination + 1,
134 Data,
135 ((Destination->u1.Length & 0xFFFF) + 3) &~3);
136 }
137
138 /* PUBLIC FUNCTIONS **********************************************************/
139
140 /*
141 * @implemented
142 */
143 NTSTATUS
144 NTAPI
145 NtReplyPort(IN HANDLE PortHandle,
146 IN PPORT_MESSAGE ReplyMessage)
147 {
148 PLPCP_PORT_OBJECT Port, ConnectionPort = NULL;
149 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
150 NTSTATUS Status;
151 PLPCP_MESSAGE Message;
152 PETHREAD Thread = PsGetCurrentThread(), WakeupThread;
153 //PORT_MESSAGE CapturedReplyMessage;
154
155 PAGED_CODE();
156 LPCTRACE(LPC_REPLY_DEBUG,
157 "Handle: %p. Message: %p.\n",
158 PortHandle,
159 ReplyMessage);
160
161 if (KeGetPreviousMode() == UserMode)
162 {
163 _SEH2_TRY
164 {
165 ProbeForRead(ReplyMessage, sizeof(PORT_MESSAGE), sizeof(ULONG));
166 /*RtlCopyMemory(&CapturedReplyMessage, ReplyMessage, sizeof(PORT_MESSAGE));
167 ReplyMessage = &CapturedReplyMessage;*/
168 }
169 _SEH2_EXCEPT(ExSystemExceptionFilter())
170 {
171 DPRINT1("SEH crash [1]\n");
172 DbgBreakPoint();
173 _SEH2_YIELD(return _SEH2_GetExceptionCode());
174 }
175 _SEH2_END;
176 }
177
178 /* Validate its length */
179 if (((ULONG)ReplyMessage->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
180 (ULONG)ReplyMessage->u1.s1.TotalLength)
181 {
182 /* Fail */
183 return STATUS_INVALID_PARAMETER;
184 }
185
186 /* Make sure it has a valid ID */
187 if (!ReplyMessage->MessageId) return STATUS_INVALID_PARAMETER;
188
189 /* Get the Port object */
190 Status = ObReferenceObjectByHandle(PortHandle,
191 0,
192 LpcPortObjectType,
193 PreviousMode,
194 (PVOID*)&Port,
195 NULL);
196 if (!NT_SUCCESS(Status)) return Status;
197
198 /* Validate its length in respect to the port object */
199 if (((ULONG)ReplyMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
200 ((ULONG)ReplyMessage->u1.s1.TotalLength <=
201 (ULONG)ReplyMessage->u1.s1.DataLength))
202 {
203 /* Too large, fail */
204 ObDereferenceObject(Port);
205 return STATUS_PORT_MESSAGE_TOO_LONG;
206 }
207
208 /* Get the ETHREAD corresponding to it */
209 Status = PsLookupProcessThreadByCid(&ReplyMessage->ClientId,
210 NULL,
211 &WakeupThread);
212 if (!NT_SUCCESS(Status))
213 {
214 /* No thread found, fail */
215 ObDereferenceObject(Port);
216 if (ConnectionPort) ObDereferenceObject(ConnectionPort);
217 return Status;
218 }
219
220 /* Allocate a message from the port zone */
221 Message = LpcpAllocateFromPortZone();
222 if (!Message)
223 {
224 /* Fail if we couldn't allocate a message */
225 if (ConnectionPort) ObDereferenceObject(ConnectionPort);
226 ObDereferenceObject(WakeupThread);
227 ObDereferenceObject(Port);
228 return STATUS_NO_MEMORY;
229 }
230
231 /* Keep the lock acquired */
232 KeAcquireGuardedMutex(&LpcpLock);
233
234 /* Make sure this is the reply the thread is waiting for */
235 if ((WakeupThread->LpcReplyMessageId != ReplyMessage->MessageId) ||
236 ((LpcpGetMessageFromThread(WakeupThread)) &&
237 (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)->
238 Request) != LPC_REQUEST)))
239 {
240 /* It isn't, fail */
241 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
242 if (ConnectionPort) ObDereferenceObject(ConnectionPort);
243 ObDereferenceObject(WakeupThread);
244 ObDereferenceObject(Port);
245 return STATUS_REPLY_MESSAGE_MISMATCH;
246 }
247
248 /* Copy the message */
249 _SEH2_TRY
250 {
251 LpcpMoveMessage(&Message->Request,
252 ReplyMessage,
253 ReplyMessage + 1,
254 LPC_REPLY,
255 NULL);
256 }
257 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
258 {
259 /* Fail */
260 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
261 ObDereferenceObject(WakeupThread);
262 ObDereferenceObject(Port);
263 _SEH2_YIELD(return _SEH2_GetExceptionCode());
264 }
265 _SEH2_END;
266
267 /* Reference the thread while we use it */
268 ObReferenceObject(WakeupThread);
269 Message->RepliedToThread = WakeupThread;
270
271 /* Set this as the reply message */
272 WakeupThread->LpcReplyMessageId = 0;
273 WakeupThread->LpcReplyMessage = (PVOID)Message;
274
275 /* Check if we have messages on the reply chain */
276 if (!(WakeupThread->LpcExitThreadCalled) &&
277 !(IsListEmpty(&WakeupThread->LpcReplyChain)))
278 {
279 /* Remove us from it and reinitialize it */
280 RemoveEntryList(&WakeupThread->LpcReplyChain);
281 InitializeListHead(&WakeupThread->LpcReplyChain);
282 }
283
284 /* Check if this is the message the thread had received */
285 if ((Thread->LpcReceivedMsgIdValid) &&
286 (Thread->LpcReceivedMessageId == ReplyMessage->MessageId))
287 {
288 /* Clear this data */
289 Thread->LpcReceivedMessageId = 0;
290 Thread->LpcReceivedMsgIdValid = FALSE;
291 }
292
293 /* Free any data information */
294 LpcpFreeDataInfoMessage(Port,
295 ReplyMessage->MessageId,
296 ReplyMessage->CallbackId,
297 ReplyMessage->ClientId);
298
299 /* Release the lock and release the LPC semaphore to wake up waiters */
300 KeReleaseGuardedMutex(&LpcpLock);
301 LpcpCompleteWait(&WakeupThread->LpcReplySemaphore);
302
303 /* Now we can let go of the thread */
304 ObDereferenceObject(WakeupThread);
305
306 /* Dereference port object */
307 ObDereferenceObject(Port);
308 return Status;
309 }
310
311 /*
312 * @implemented
313 */
314 NTSTATUS
315 NTAPI
316 NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
317 OUT PVOID *PortContext OPTIONAL,
318 IN PPORT_MESSAGE ReplyMessage OPTIONAL,
319 OUT PPORT_MESSAGE ReceiveMessage,
320 IN PLARGE_INTEGER Timeout OPTIONAL)
321 {
322 PLPCP_PORT_OBJECT Port, ReceivePort, ConnectionPort = NULL;
323 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(), WaitMode = PreviousMode;
324 NTSTATUS Status;
325 PLPCP_MESSAGE Message;
326 PETHREAD Thread = PsGetCurrentThread(), WakeupThread;
327 PLPCP_CONNECTION_MESSAGE ConnectMessage;
328 ULONG ConnectionInfoLength;
329 //PORT_MESSAGE CapturedReplyMessage;
330 LARGE_INTEGER CapturedTimeout;
331
332 PAGED_CODE();
333 LPCTRACE(LPC_REPLY_DEBUG,
334 "Handle: %p. Messages: %p/%p. Context: %p\n",
335 PortHandle,
336 ReplyMessage,
337 ReceiveMessage,
338 PortContext);
339
340 if (KeGetPreviousMode() == UserMode)
341 {
342 _SEH2_TRY
343 {
344 if (ReplyMessage != NULL)
345 {
346 ProbeForRead(ReplyMessage, sizeof(PORT_MESSAGE), sizeof(ULONG));
347 /*RtlCopyMemory(&CapturedReplyMessage, ReplyMessage, sizeof(PORT_MESSAGE));
348 ReplyMessage = &CapturedReplyMessage;*/
349 }
350
351 if (Timeout != NULL)
352 {
353 ProbeForReadLargeInteger(Timeout);
354 RtlCopyMemory(&CapturedTimeout, Timeout, sizeof(LARGE_INTEGER));
355 Timeout = &CapturedTimeout;
356 }
357
358 if (PortContext != NULL)
359 ProbeForWritePointer(PortContext);
360 }
361 _SEH2_EXCEPT(ExSystemExceptionFilter())
362 {
363 DPRINT1("SEH crash [1]\n");
364 DbgBreakPoint();
365 _SEH2_YIELD(return _SEH2_GetExceptionCode());
366 }
367 _SEH2_END;
368 }
369 else
370 {
371 /* If this is a system thread, then let it page out its stack */
372 if (Thread->SystemThread) WaitMode = UserMode;
373 }
374
375 /* Check if caller has a reply message */
376 if (ReplyMessage)
377 {
378 /* Validate its length */
379 if (((ULONG)ReplyMessage->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
380 (ULONG)ReplyMessage->u1.s1.TotalLength)
381 {
382 /* Fail */
383 return STATUS_INVALID_PARAMETER;
384 }
385
386 /* Make sure it has a valid ID */
387 if (!ReplyMessage->MessageId) return STATUS_INVALID_PARAMETER;
388 }
389
390 /* Get the Port object */
391 Status = ObReferenceObjectByHandle(PortHandle,
392 0,
393 LpcPortObjectType,
394 PreviousMode,
395 (PVOID*)&Port,
396 NULL);
397 if (!NT_SUCCESS(Status)) return Status;
398
399 /* Check if the caller has a reply message */
400 if (ReplyMessage)
401 {
402 /* Validate its length in respect to the port object */
403 if (((ULONG)ReplyMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
404 ((ULONG)ReplyMessage->u1.s1.TotalLength <=
405 (ULONG)ReplyMessage->u1.s1.DataLength))
406 {
407 /* Too large, fail */
408 ObDereferenceObject(Port);
409 return STATUS_PORT_MESSAGE_TOO_LONG;
410 }
411 }
412
413 /* Check if this is anything but a client port */
414 if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CLIENT_PORT)
415 {
416 /* Check if this is the connection port */
417 if (Port->ConnectionPort == Port)
418 {
419 /* Use this port */
420 ConnectionPort = ReceivePort = Port;
421 ObReferenceObject(ConnectionPort);
422 }
423 else
424 {
425 /* Acquire the lock */
426 KeAcquireGuardedMutex(&LpcpLock);
427
428 /* Get the port */
429 ConnectionPort = ReceivePort = Port->ConnectionPort;
430 if (!ConnectionPort)
431 {
432 /* Fail */
433 KeReleaseGuardedMutex(&LpcpLock);
434 ObDereferenceObject(Port);
435 return STATUS_PORT_DISCONNECTED;
436 }
437
438 /* Release lock and reference */
439 ObReferenceObject(ConnectionPort);
440 KeReleaseGuardedMutex(&LpcpLock);
441 }
442 }
443 else
444 {
445 /* Otherwise, use the port itself */
446 ReceivePort = Port;
447 }
448
449 /* Check if the caller gave a reply message */
450 if (ReplyMessage)
451 {
452 /* Get the ETHREAD corresponding to it */
453 Status = PsLookupProcessThreadByCid(&ReplyMessage->ClientId,
454 NULL,
455 &WakeupThread);
456 if (!NT_SUCCESS(Status))
457 {
458 /* No thread found, fail */
459 ObDereferenceObject(Port);
460 if (ConnectionPort) ObDereferenceObject(ConnectionPort);
461 return Status;
462 }
463
464 /* Allocate a message from the port zone */
465 Message = LpcpAllocateFromPortZone();
466 if (!Message)
467 {
468 /* Fail if we couldn't allocate a message */
469 if (ConnectionPort) ObDereferenceObject(ConnectionPort);
470 ObDereferenceObject(WakeupThread);
471 ObDereferenceObject(Port);
472 return STATUS_NO_MEMORY;
473 }
474
475 /* Keep the lock acquired */
476 KeAcquireGuardedMutex(&LpcpLock);
477
478 /* Make sure this is the reply the thread is waiting for */
479 if ((WakeupThread->LpcReplyMessageId != ReplyMessage->MessageId) ||
480 ((LpcpGetMessageFromThread(WakeupThread)) &&
481 (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)->
482 Request) != LPC_REQUEST)))
483 {
484 /* It isn't, fail */
485 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
486 if (ConnectionPort) ObDereferenceObject(ConnectionPort);
487 ObDereferenceObject(WakeupThread);
488 ObDereferenceObject(Port);
489 return STATUS_REPLY_MESSAGE_MISMATCH;
490 }
491
492 /* Copy the message */
493 LpcpMoveMessage(&Message->Request,
494 ReplyMessage,
495 ReplyMessage + 1,
496 LPC_REPLY,
497 NULL);
498
499 /* Reference the thread while we use it */
500 ObReferenceObject(WakeupThread);
501 Message->RepliedToThread = WakeupThread;
502
503 /* Set this as the reply message */
504 WakeupThread->LpcReplyMessageId = 0;
505 WakeupThread->LpcReplyMessage = (PVOID)Message;
506
507 /* Check if we have messages on the reply chain */
508 if (!(WakeupThread->LpcExitThreadCalled) &&
509 !(IsListEmpty(&WakeupThread->LpcReplyChain)))
510 {
511 /* Remove us from it and reinitialize it */
512 RemoveEntryList(&WakeupThread->LpcReplyChain);
513 InitializeListHead(&WakeupThread->LpcReplyChain);
514 }
515
516 /* Check if this is the message the thread had received */
517 if ((Thread->LpcReceivedMsgIdValid) &&
518 (Thread->LpcReceivedMessageId == ReplyMessage->MessageId))
519 {
520 /* Clear this data */
521 Thread->LpcReceivedMessageId = 0;
522 Thread->LpcReceivedMsgIdValid = FALSE;
523 }
524
525 /* Free any data information */
526 LpcpFreeDataInfoMessage(Port,
527 ReplyMessage->MessageId,
528 ReplyMessage->CallbackId,
529 ReplyMessage->ClientId);
530
531 /* Release the lock and release the LPC semaphore to wake up waiters */
532 KeReleaseGuardedMutex(&LpcpLock);
533 LpcpCompleteWait(&WakeupThread->LpcReplySemaphore);
534
535 /* Now we can let go of the thread */
536 ObDereferenceObject(WakeupThread);
537 }
538
539 /* Now wait for someone to reply to us */
540 LpcpReceiveWait(ReceivePort->MsgQueue.Semaphore, WaitMode);
541 if (Status != STATUS_SUCCESS) goto Cleanup;
542
543 /* Wait done, get the LPC lock */
544 KeAcquireGuardedMutex(&LpcpLock);
545
546 /* Check if we've received nothing */
547 if (IsListEmpty(&ReceivePort->MsgQueue.ReceiveHead))
548 {
549 /* Check if this was a waitable port and wake it */
550 if (ReceivePort->Flags & LPCP_WAITABLE_PORT)
551 {
552 /* Reset its event */
553 KeResetEvent(&ReceivePort->WaitEvent);
554 }
555
556 /* Release the lock and fail */
557 KeReleaseGuardedMutex(&LpcpLock);
558 if (ConnectionPort) ObDereferenceObject(ConnectionPort);
559 ObDereferenceObject(Port);
560 return STATUS_UNSUCCESSFUL;
561 }
562
563 /* Get the message on the queue */
564 Message = CONTAINING_RECORD(RemoveHeadList(&ReceivePort->
565 MsgQueue.ReceiveHead),
566 LPCP_MESSAGE,
567 Entry);
568
569 /* Check if the queue is empty now */
570 if (IsListEmpty(&ReceivePort->MsgQueue.ReceiveHead))
571 {
572 /* Check if this was a waitable port */
573 if (ReceivePort->Flags & LPCP_WAITABLE_PORT)
574 {
575 /* Reset its event */
576 KeResetEvent(&ReceivePort->WaitEvent);
577 }
578 }
579
580 /* Re-initialize the message's list entry */
581 InitializeListHead(&Message->Entry);
582
583 /* Set this as the received message */
584 Thread->LpcReceivedMessageId = Message->Request.MessageId;
585 Thread->LpcReceivedMsgIdValid = TRUE;
586
587 _SEH2_TRY
588 {
589 /* Check if this was a connection request */
590 if (LpcpGetMessageType(&Message->Request) == LPC_CONNECTION_REQUEST)
591 {
592 /* Get the connection message */
593 ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
594 LPCTRACE(LPC_REPLY_DEBUG,
595 "Request Messages: %p/%p\n",
596 Message,
597 ConnectMessage);
598
599 /* Get its length */
600 ConnectionInfoLength = Message->Request.u1.s1.DataLength -
601 sizeof(LPCP_CONNECTION_MESSAGE);
602
603 /* Return it as the receive message */
604 *ReceiveMessage = Message->Request;
605
606 /* Clear our stack variable so the message doesn't get freed */
607 Message = NULL;
608
609 /* Setup the receive message */
610 ReceiveMessage->u1.s1.TotalLength = (CSHORT)(sizeof(LPCP_MESSAGE) +
611 ConnectionInfoLength);
612 ReceiveMessage->u1.s1.DataLength = (CSHORT)ConnectionInfoLength;
613 RtlCopyMemory(ReceiveMessage + 1,
614 ConnectMessage + 1,
615 ConnectionInfoLength);
616
617 /* Clear the port context if the caller requested one */
618 if (PortContext) *PortContext = NULL;
619 }
620 else if (LpcpGetMessageType(&Message->Request) != LPC_REPLY)
621 {
622 /* Otherwise, this is a new message or event */
623 LPCTRACE(LPC_REPLY_DEBUG,
624 "Non-Reply Messages: %p/%p\n",
625 &Message->Request,
626 (&Message->Request) + 1);
627
628 /* Copy it */
629 LpcpMoveMessage(ReceiveMessage,
630 &Message->Request,
631 (&Message->Request) + 1,
632 0,
633 NULL);
634
635 /* Return its context */
636 if (PortContext) *PortContext = Message->PortContext;
637
638 /* And check if it has data information */
639 if (Message->Request.u2.s2.DataInfoOffset)
640 {
641 /* It does, save it, and don't free the message below */
642 LpcpSaveDataInfoMessage(Port, Message, LPCP_LOCK_HELD);
643 Message = NULL;
644 }
645 }
646 else
647 {
648 /* This is a reply message, should never happen! */
649 ASSERT(FALSE);
650 }
651 }
652 _SEH2_EXCEPT(ExSystemExceptionFilter())
653 {
654 DPRINT1("SEH crash [2]\n");
655 DbgBreakPoint();
656 Status = _SEH2_GetExceptionCode();
657 }
658 _SEH2_END;
659
660 /* Check if we have a message pointer here */
661 if (Message)
662 {
663 /* Free it and release the lock */
664 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
665 }
666 else
667 {
668 /* Just release the lock */
669 KeReleaseGuardedMutex(&LpcpLock);
670 }
671
672 Cleanup:
673 /* All done, dereference the port and return the status */
674 LPCTRACE(LPC_REPLY_DEBUG,
675 "Port: %p. Status: %d\n",
676 Port,
677 Status);
678 if (ConnectionPort) ObDereferenceObject(ConnectionPort);
679 ObDereferenceObject(Port);
680 return Status;
681 }
682
683 /*
684 * @implemented
685 */
686 NTSTATUS
687 NTAPI
688 NtReplyWaitReceivePort(IN HANDLE PortHandle,
689 OUT PVOID *PortContext OPTIONAL,
690 IN PPORT_MESSAGE ReplyMessage OPTIONAL,
691 OUT PPORT_MESSAGE ReceiveMessage)
692 {
693 /* Call the newer API */
694 return NtReplyWaitReceivePortEx(PortHandle,
695 PortContext,
696 ReplyMessage,
697 ReceiveMessage,
698 NULL);
699 }
700
701 /*
702 * @unimplemented
703 */
704 NTSTATUS
705 NTAPI
706 NtReplyWaitReplyPort(IN HANDLE PortHandle,
707 IN PPORT_MESSAGE ReplyMessage)
708 {
709 UNIMPLEMENTED;
710 return STATUS_NOT_IMPLEMENTED;
711 }
712
713 /*
714 * @unimplemented
715 */
716 NTSTATUS
717 NTAPI
718 NtReadRequestData(IN HANDLE PortHandle,
719 IN PPORT_MESSAGE Message,
720 IN ULONG Index,
721 IN PVOID Buffer,
722 IN ULONG BufferLength,
723 OUT PULONG Returnlength)
724 {
725 UNIMPLEMENTED;
726 return STATUS_NOT_IMPLEMENTED;
727 }
728
729 /*
730 * @unimplemented
731 */
732 NTSTATUS
733 NTAPI
734 NtWriteRequestData(IN HANDLE PortHandle,
735 IN PPORT_MESSAGE Message,
736 IN ULONG Index,
737 IN PVOID Buffer,
738 IN ULONG BufferLength,
739 OUT PULONG ReturnLength)
740 {
741 UNIMPLEMENTED;
742 return STATUS_NOT_IMPLEMENTED;
743 }
744
745 /* EOF */