xref: /reactos/ntoskrnl/lpc/send.c (revision b3c55b9e)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:         ReactOS Kernel
3c2c66affSColin Finck  * LICENSE:         GPL - See COPYING in the top level directory
4c2c66affSColin Finck  * FILE:            ntoskrnl/lpc/send.c
5c2c66affSColin Finck  * PURPOSE:         Local Procedure Call: Sending (Requests)
6c2c66affSColin Finck  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7c2c66affSColin Finck  */
8c2c66affSColin Finck 
9c2c66affSColin Finck /* INCLUDES ******************************************************************/
10c2c66affSColin Finck 
11c2c66affSColin Finck #include <ntoskrnl.h>
12c2c66affSColin Finck #define NDEBUG
13c2c66affSColin Finck #include <debug.h>
14c2c66affSColin Finck 
15c2c66affSColin Finck /* PUBLIC FUNCTIONS **********************************************************/
16c2c66affSColin Finck 
17c2c66affSColin Finck /*
18c2c66affSColin Finck  * @implemented
19c2c66affSColin Finck  */
20c2c66affSColin Finck NTSTATUS
21c2c66affSColin Finck NTAPI
LpcRequestPort(IN PVOID PortObject,IN PPORT_MESSAGE LpcMessage)22c2c66affSColin Finck LpcRequestPort(IN PVOID PortObject,
23c2c66affSColin Finck                IN PPORT_MESSAGE LpcMessage)
24c2c66affSColin Finck {
25c2c66affSColin Finck     PLPCP_PORT_OBJECT Port = PortObject, QueuePort, ConnectionPort = NULL;
26c2c66affSColin Finck     ULONG MessageType;
27c2c66affSColin Finck     PLPCP_MESSAGE Message;
28c2c66affSColin Finck     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
29c2c66affSColin Finck     PETHREAD Thread = PsGetCurrentThread();
30c2c66affSColin Finck 
31c2c66affSColin Finck     PAGED_CODE();
32c2c66affSColin Finck 
33c2c66affSColin Finck     LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", Port, LpcMessage);
34c2c66affSColin Finck 
35c2c66affSColin Finck     /* Check if this is a non-datagram message */
36c2c66affSColin Finck     if (LpcMessage->u2.s2.Type)
37c2c66affSColin Finck     {
38c2c66affSColin Finck         /* Get the message type */
39c2c66affSColin Finck         MessageType = LpcpGetMessageType(LpcMessage);
40c2c66affSColin Finck 
41c2c66affSColin Finck         /* Validate it */
42c2c66affSColin Finck         if ((MessageType < LPC_DATAGRAM) || (MessageType > LPC_CLIENT_DIED))
43c2c66affSColin Finck         {
44c2c66affSColin Finck             /* Fail */
45c2c66affSColin Finck             return STATUS_INVALID_PARAMETER;
46c2c66affSColin Finck         }
47c2c66affSColin Finck 
48c2c66affSColin Finck         /* Mark this as a kernel-mode message only if we really came from it */
49c2c66affSColin Finck         if ((PreviousMode == KernelMode) &&
50c2c66affSColin Finck             (LpcMessage->u2.s2.Type & LPC_KERNELMODE_MESSAGE))
51c2c66affSColin Finck         {
52c2c66affSColin Finck             /* We did, this is a kernel mode message */
53c2c66affSColin Finck             MessageType |= LPC_KERNELMODE_MESSAGE;
54c2c66affSColin Finck         }
55c2c66affSColin Finck     }
56c2c66affSColin Finck     else
57c2c66affSColin Finck     {
58c2c66affSColin Finck         /* This is a datagram */
59c2c66affSColin Finck         MessageType = LPC_DATAGRAM;
60c2c66affSColin Finck     }
61c2c66affSColin Finck 
62c2c66affSColin Finck     /* Can't have data information on this type of call */
63c2c66affSColin Finck     if (LpcMessage->u2.s2.DataInfoOffset) return STATUS_INVALID_PARAMETER;
64c2c66affSColin Finck 
65c2c66affSColin Finck     /* Validate the message length */
66c2c66affSColin Finck     if (((ULONG)LpcMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
67c2c66affSColin Finck         ((ULONG)LpcMessage->u1.s1.TotalLength <= (ULONG)LpcMessage->u1.s1.DataLength))
68c2c66affSColin Finck     {
69c2c66affSColin Finck         /* Fail */
70c2c66affSColin Finck         return STATUS_PORT_MESSAGE_TOO_LONG;
71c2c66affSColin Finck     }
72c2c66affSColin Finck 
73c2c66affSColin Finck     /* Allocate a new message */
74c2c66affSColin Finck     Message = LpcpAllocateFromPortZone();
75c2c66affSColin Finck     if (!Message) return STATUS_NO_MEMORY;
76c2c66affSColin Finck 
77c2c66affSColin Finck     /* Clear the context */
78c2c66affSColin Finck     Message->RepliedToThread = NULL;
79c2c66affSColin Finck     Message->PortContext = NULL;
80c2c66affSColin Finck 
81c2c66affSColin Finck     /* Copy the message */
82c2c66affSColin Finck     LpcpMoveMessage(&Message->Request,
83c2c66affSColin Finck                     LpcMessage,
84c2c66affSColin Finck                     LpcMessage + 1,
85c2c66affSColin Finck                     MessageType,
86c2c66affSColin Finck                     &Thread->Cid);
87c2c66affSColin Finck 
88c2c66affSColin Finck     /* Acquire the LPC lock */
89c2c66affSColin Finck     KeAcquireGuardedMutex(&LpcpLock);
90c2c66affSColin Finck 
91c2c66affSColin Finck     /* Check if this is anything but a connection port */
92c2c66affSColin Finck     if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
93c2c66affSColin Finck     {
94c2c66affSColin Finck         /* The queue port is the connected port */
95c2c66affSColin Finck         QueuePort = Port->ConnectedPort;
96c2c66affSColin Finck         if (QueuePort)
97c2c66affSColin Finck         {
98c2c66affSColin Finck             /* Check if this is a client port */
99c2c66affSColin Finck             if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
100c2c66affSColin Finck             {
101c2c66affSColin Finck                 /* Then copy the context */
102c2c66affSColin Finck                 Message->PortContext = QueuePort->PortContext;
103c2c66affSColin Finck                 ConnectionPort = QueuePort = Port->ConnectionPort;
104c2c66affSColin Finck                 if (!ConnectionPort)
105c2c66affSColin Finck                 {
106c2c66affSColin Finck                     /* Fail */
107c2c66affSColin Finck                     LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
108c2c66affSColin Finck                     return STATUS_PORT_DISCONNECTED;
109c2c66affSColin Finck                 }
110c2c66affSColin Finck             }
111c2c66affSColin Finck             else if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT)
112c2c66affSColin Finck             {
113c2c66affSColin Finck                 /* Any other kind of port, use the connection port */
114c2c66affSColin Finck                 ConnectionPort = QueuePort = Port->ConnectionPort;
115c2c66affSColin Finck                 if (!ConnectionPort)
116c2c66affSColin Finck                 {
117c2c66affSColin Finck                     /* Fail */
118c2c66affSColin Finck                     LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
119c2c66affSColin Finck                     return STATUS_PORT_DISCONNECTED;
120c2c66affSColin Finck                 }
121c2c66affSColin Finck             }
122c2c66affSColin Finck 
123c2c66affSColin Finck             /* If we have a connection port, reference it */
124c2c66affSColin Finck             if (ConnectionPort) ObReferenceObject(ConnectionPort);
125c2c66affSColin Finck         }
126c2c66affSColin Finck     }
127c2c66affSColin Finck     else
128c2c66affSColin Finck     {
129c2c66affSColin Finck         /* For connection ports, use the port itself */
130c2c66affSColin Finck         QueuePort = PortObject;
131c2c66affSColin Finck     }
132c2c66affSColin Finck 
133c2c66affSColin Finck     /* Make sure we have a port */
134c2c66affSColin Finck     if (QueuePort)
135c2c66affSColin Finck     {
136c2c66affSColin Finck         /* Generate the Message ID and set it */
137c2c66affSColin Finck         Message->Request.MessageId = LpcpNextMessageId++;
138c2c66affSColin Finck         if (!LpcpNextMessageId) LpcpNextMessageId = 1;
139c2c66affSColin Finck         Message->Request.CallbackId = 0;
140c2c66affSColin Finck 
141c2c66affSColin Finck         /* No Message ID for the thread */
142c2c66affSColin Finck         Thread->LpcReplyMessageId = 0;
143c2c66affSColin Finck 
144c2c66affSColin Finck         /* Insert the message in our chain */
145c2c66affSColin Finck         InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);
146c2c66affSColin Finck 
147c2c66affSColin Finck         /* Release the lock and the semaphore */
148c2c66affSColin Finck         KeEnterCriticalRegion();
149c2c66affSColin Finck         KeReleaseGuardedMutex(&LpcpLock);
150c2c66affSColin Finck         LpcpCompleteWait(QueuePort->MsgQueue.Semaphore);
151c2c66affSColin Finck 
152c2c66affSColin Finck         /* If this is a waitable port, wake it up */
153c2c66affSColin Finck         if (QueuePort->Flags & LPCP_WAITABLE_PORT)
154c2c66affSColin Finck         {
155c2c66affSColin Finck             /* Wake it */
156c2c66affSColin Finck             KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
157c2c66affSColin Finck         }
158c2c66affSColin Finck 
159c2c66affSColin Finck         KeLeaveCriticalRegion();
160c2c66affSColin Finck 
161c2c66affSColin Finck         /* We're done */
162c2c66affSColin Finck         if (ConnectionPort) ObDereferenceObject(ConnectionPort);
163c2c66affSColin Finck         LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", QueuePort, Message);
164c2c66affSColin Finck         return STATUS_SUCCESS;
165c2c66affSColin Finck     }
166c2c66affSColin Finck 
167c2c66affSColin Finck     /* If we got here, then free the message and fail */
168c2c66affSColin Finck     LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
169c2c66affSColin Finck     if (ConnectionPort) ObDereferenceObject(ConnectionPort);
170c2c66affSColin Finck     return STATUS_PORT_DISCONNECTED;
171c2c66affSColin Finck }
172c2c66affSColin Finck 
173c2c66affSColin Finck /*
174c2c66affSColin Finck * @implemented
175c2c66affSColin Finck */
176c2c66affSColin Finck NTSTATUS
177c2c66affSColin Finck NTAPI
LpcRequestWaitReplyPort(IN PVOID PortObject,IN PPORT_MESSAGE LpcRequest,OUT PPORT_MESSAGE LpcReply)178c2c66affSColin Finck LpcRequestWaitReplyPort(IN PVOID PortObject,
179c2c66affSColin Finck                         IN PPORT_MESSAGE LpcRequest,
180c2c66affSColin Finck                         OUT PPORT_MESSAGE LpcReply)
181c2c66affSColin Finck {
182c2c66affSColin Finck     NTSTATUS Status = STATUS_SUCCESS;
183c2c66affSColin Finck     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
184c2c66affSColin Finck     PETHREAD Thread = PsGetCurrentThread();
185c2c66affSColin Finck     PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)PortObject;
186c2c66affSColin Finck     PLPCP_PORT_OBJECT QueuePort, ReplyPort, ConnectionPort = NULL;
187c2c66affSColin Finck     USHORT MessageType;
188c2c66affSColin Finck     PLPCP_MESSAGE Message;
189c2c66affSColin Finck     BOOLEAN Callback = FALSE;
190c2c66affSColin Finck     PKSEMAPHORE Semaphore;
191c2c66affSColin Finck 
192c2c66affSColin Finck     PAGED_CODE();
193c2c66affSColin Finck 
194c2c66affSColin Finck     LPCTRACE(LPC_SEND_DEBUG,
195c2c66affSColin Finck              "Port: %p. Messages: %p/%p. Type: %lx\n",
196c2c66affSColin Finck              Port,
197c2c66affSColin Finck              LpcRequest,
198c2c66affSColin Finck              LpcReply,
199c2c66affSColin Finck              LpcpGetMessageType(LpcRequest));
200c2c66affSColin Finck 
201c2c66affSColin Finck     /* Check if the thread is dying */
202c2c66affSColin Finck     if (Thread->LpcExitThreadCalled) return STATUS_THREAD_IS_TERMINATING;
203c2c66affSColin Finck 
204c2c66affSColin Finck     /* Check if this is an LPC Request */
205c2c66affSColin Finck     MessageType = LpcpGetMessageType(LpcRequest);
206c2c66affSColin Finck     switch (MessageType)
207c2c66affSColin Finck     {
208c2c66affSColin Finck         /* No type, assume LPC request */
209c2c66affSColin Finck         case 0:
210c2c66affSColin Finck             MessageType = LPC_REQUEST;
211c2c66affSColin Finck             break;
212c2c66affSColin Finck 
213c2c66affSColin Finck         /* LPC request callback */
214c2c66affSColin Finck         case LPC_REQUEST:
215c2c66affSColin Finck             Callback = TRUE;
216c2c66affSColin Finck             break;
217c2c66affSColin Finck 
218c2c66affSColin Finck         /* Anything else, nothing to do */
219c2c66affSColin Finck         case LPC_CLIENT_DIED:
220c2c66affSColin Finck         case LPC_PORT_CLOSED:
221c2c66affSColin Finck         case LPC_EXCEPTION:
222c2c66affSColin Finck         case LPC_DEBUG_EVENT:
223c2c66affSColin Finck         case LPC_ERROR_EVENT:
224c2c66affSColin Finck             break;
225c2c66affSColin Finck 
226c2c66affSColin Finck         /* Invalid message type */
227c2c66affSColin Finck         default:
228c2c66affSColin Finck             return STATUS_INVALID_PARAMETER;
229c2c66affSColin Finck     }
230c2c66affSColin Finck 
231c2c66affSColin Finck     /* Set the request type */
232c2c66affSColin Finck     LpcRequest->u2.s2.Type = MessageType;
233c2c66affSColin Finck 
234c2c66affSColin Finck     /* Validate the message length */
235c2c66affSColin Finck     if (((ULONG)LpcRequest->u1.s1.TotalLength > Port->MaxMessageLength) ||
236c2c66affSColin Finck         ((ULONG)LpcRequest->u1.s1.TotalLength <= (ULONG)LpcRequest->u1.s1.DataLength))
237c2c66affSColin Finck     {
238c2c66affSColin Finck         /* Fail */
239c2c66affSColin Finck         return STATUS_PORT_MESSAGE_TOO_LONG;
240c2c66affSColin Finck     }
241c2c66affSColin Finck 
242c2c66affSColin Finck     /* Allocate a message from the port zone */
243c2c66affSColin Finck     Message = LpcpAllocateFromPortZone();
244c2c66affSColin Finck     if (!Message)
245c2c66affSColin Finck     {
246c2c66affSColin Finck         /* Fail if we couldn't allocate a message */
247c2c66affSColin Finck         return STATUS_NO_MEMORY;
248c2c66affSColin Finck     }
249c2c66affSColin Finck 
250c2c66affSColin Finck     /* Check if this is a callback */
251c2c66affSColin Finck     if (Callback)
252c2c66affSColin Finck     {
253c2c66affSColin Finck         /* FIXME: TODO */
254c2c66affSColin Finck         Semaphore = NULL; // we'd use the Thread Semaphore here
255c2c66affSColin Finck         ASSERT(FALSE);
256c2c66affSColin Finck         return STATUS_NOT_IMPLEMENTED;
257c2c66affSColin Finck     }
258c2c66affSColin Finck     else
259c2c66affSColin Finck     {
260c2c66affSColin Finck         /* No callback, just copy the message */
261c2c66affSColin Finck         LpcpMoveMessage(&Message->Request,
262c2c66affSColin Finck                         LpcRequest,
263c2c66affSColin Finck                         LpcRequest + 1,
264c2c66affSColin Finck                         0,
265c2c66affSColin Finck                         &Thread->Cid);
266c2c66affSColin Finck 
267c2c66affSColin Finck         /* Acquire the LPC lock */
268c2c66affSColin Finck         KeAcquireGuardedMutex(&LpcpLock);
269c2c66affSColin Finck 
270c2c66affSColin Finck         /* Right now clear the port context */
271c2c66affSColin Finck         Message->PortContext = NULL;
272c2c66affSColin Finck 
273c2c66affSColin Finck         /* Check if this is a not connection port */
274c2c66affSColin Finck         if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
275c2c66affSColin Finck         {
276c2c66affSColin Finck             /* We want the connected port */
277c2c66affSColin Finck             QueuePort = Port->ConnectedPort;
278c2c66affSColin Finck             if (!QueuePort)
279c2c66affSColin Finck             {
280c2c66affSColin Finck                 /* We have no connected port, fail */
281c2c66affSColin Finck                 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
282c2c66affSColin Finck                 return STATUS_PORT_DISCONNECTED;
283c2c66affSColin Finck             }
284c2c66affSColin Finck 
285c2c66affSColin Finck             /* This will be the rundown port */
286c2c66affSColin Finck             ReplyPort = QueuePort;
287c2c66affSColin Finck 
288c2c66affSColin Finck             /* Check if this is a communication port */
289c2c66affSColin Finck             if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
290c2c66affSColin Finck             {
291c2c66affSColin Finck                 /* Copy the port context and use the connection port */
292c2c66affSColin Finck                 Message->PortContext = QueuePort->PortContext;
293c2c66affSColin Finck                 ConnectionPort = QueuePort = Port->ConnectionPort;
294c2c66affSColin Finck                 if (!ConnectionPort)
295c2c66affSColin Finck                 {
296c2c66affSColin Finck                     /* Fail */
297c2c66affSColin Finck                     LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
298c2c66affSColin Finck                     return STATUS_PORT_DISCONNECTED;
299c2c66affSColin Finck                 }
300c2c66affSColin Finck             }
301c2c66affSColin Finck             else if ((Port->Flags & LPCP_PORT_TYPE_MASK) !=
302c2c66affSColin Finck                       LPCP_COMMUNICATION_PORT)
303c2c66affSColin Finck             {
304c2c66affSColin Finck                 /* Use the connection port for anything but communication ports */
305c2c66affSColin Finck                 ConnectionPort = QueuePort = Port->ConnectionPort;
306c2c66affSColin Finck                 if (!ConnectionPort)
307c2c66affSColin Finck                 {
308c2c66affSColin Finck                     /* Fail */
309c2c66affSColin Finck                     LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
310c2c66affSColin Finck                     return STATUS_PORT_DISCONNECTED;
311c2c66affSColin Finck                 }
312c2c66affSColin Finck             }
313c2c66affSColin Finck 
314c2c66affSColin Finck             /* Reference the connection port if it exists */
315c2c66affSColin Finck             if (ConnectionPort) ObReferenceObject(ConnectionPort);
316c2c66affSColin Finck         }
317c2c66affSColin Finck         else
318c2c66affSColin Finck         {
319c2c66affSColin Finck             /* Otherwise, for a connection port, use the same port object */
320c2c66affSColin Finck             QueuePort = ReplyPort = Port;
321c2c66affSColin Finck         }
322c2c66affSColin Finck 
323c2c66affSColin Finck         /* No reply thread */
324c2c66affSColin Finck         Message->RepliedToThread = NULL;
325c2c66affSColin Finck         Message->SenderPort = Port;
326c2c66affSColin Finck 
327c2c66affSColin Finck         /* Generate the Message ID and set it */
328c2c66affSColin Finck         Message->Request.MessageId = LpcpNextMessageId++;
329c2c66affSColin Finck         if (!LpcpNextMessageId) LpcpNextMessageId = 1;
330c2c66affSColin Finck         Message->Request.CallbackId = 0;
331c2c66affSColin Finck 
332c2c66affSColin Finck         /* Set the message ID for our thread now */
333c2c66affSColin Finck         Thread->LpcReplyMessageId = Message->Request.MessageId;
334c2c66affSColin Finck         Thread->LpcReplyMessage = NULL;
335c2c66affSColin Finck 
336c2c66affSColin Finck         /* Insert the message in our chain */
337c2c66affSColin Finck         InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);
338c2c66affSColin Finck         InsertTailList(&ReplyPort->LpcReplyChainHead, &Thread->LpcReplyChain);
339c2c66affSColin Finck         LpcpSetPortToThread(Thread, Port);
340c2c66affSColin Finck 
341c2c66affSColin Finck         /* Release the lock and get the semaphore we'll use later */
342c2c66affSColin Finck         KeEnterCriticalRegion();
343c2c66affSColin Finck         KeReleaseGuardedMutex(&LpcpLock);
344c2c66affSColin Finck         Semaphore = QueuePort->MsgQueue.Semaphore;
345c2c66affSColin Finck 
346c2c66affSColin Finck         /* If this is a waitable port, wake it up */
347c2c66affSColin Finck         if (QueuePort->Flags & LPCP_WAITABLE_PORT)
348c2c66affSColin Finck         {
349c2c66affSColin Finck             /* Wake it */
350c2c66affSColin Finck             KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
351c2c66affSColin Finck         }
352c2c66affSColin Finck     }
353c2c66affSColin Finck 
354c2c66affSColin Finck     /* Now release the semaphore */
355c2c66affSColin Finck     LpcpCompleteWait(Semaphore);
356c2c66affSColin Finck     KeLeaveCriticalRegion();
357c2c66affSColin Finck 
358c2c66affSColin Finck     /* And let's wait for the reply */
359c2c66affSColin Finck     LpcpReplyWait(&Thread->LpcReplySemaphore, PreviousMode);
360c2c66affSColin Finck 
361c2c66affSColin Finck     /* Acquire the LPC lock */
362c2c66affSColin Finck     KeAcquireGuardedMutex(&LpcpLock);
363c2c66affSColin Finck 
364c2c66affSColin Finck     /* Get the LPC Message and clear our thread's reply data */
365c2c66affSColin Finck     Message = LpcpGetMessageFromThread(Thread);
366c2c66affSColin Finck     Thread->LpcReplyMessage = NULL;
367c2c66affSColin Finck     Thread->LpcReplyMessageId = 0;
368c2c66affSColin Finck 
369c2c66affSColin Finck     /* Check if we have anything on the reply chain*/
370c2c66affSColin Finck     if (!IsListEmpty(&Thread->LpcReplyChain))
371c2c66affSColin Finck     {
372c2c66affSColin Finck         /* Remove this thread and reinitialize the list */
373c2c66affSColin Finck         RemoveEntryList(&Thread->LpcReplyChain);
374c2c66affSColin Finck         InitializeListHead(&Thread->LpcReplyChain);
375c2c66affSColin Finck     }
376c2c66affSColin Finck 
377c2c66affSColin Finck     /* Release the lock */
378c2c66affSColin Finck     KeReleaseGuardedMutex(&LpcpLock);
379c2c66affSColin Finck 
380c2c66affSColin Finck     /* Check if we got a reply */
381c2c66affSColin Finck     if (Status == STATUS_SUCCESS)
382c2c66affSColin Finck     {
383c2c66affSColin Finck         /* Check if we have a valid message */
384c2c66affSColin Finck         if (Message)
385c2c66affSColin Finck         {
386c2c66affSColin Finck             LPCTRACE(LPC_SEND_DEBUG,
387c2c66affSColin Finck                      "Reply Messages: %p/%p\n",
388c2c66affSColin Finck                      &Message->Request,
389c2c66affSColin Finck                      (&Message->Request) + 1);
390c2c66affSColin Finck 
391c2c66affSColin Finck             /* Move the message */
392c2c66affSColin Finck             LpcpMoveMessage(LpcReply,
393c2c66affSColin Finck                             &Message->Request,
394c2c66affSColin Finck                             (&Message->Request) + 1,
395c2c66affSColin Finck                             0,
396c2c66affSColin Finck                             NULL);
397c2c66affSColin Finck 
398c2c66affSColin Finck             /* Acquire the lock */
399c2c66affSColin Finck             KeAcquireGuardedMutex(&LpcpLock);
400c2c66affSColin Finck 
401c2c66affSColin Finck             /* Check if we replied to a thread */
402c2c66affSColin Finck             if (Message->RepliedToThread)
403c2c66affSColin Finck             {
404c2c66affSColin Finck                 /* Dereference */
405c2c66affSColin Finck                 ObDereferenceObject(Message->RepliedToThread);
406c2c66affSColin Finck                 Message->RepliedToThread = NULL;
407c2c66affSColin Finck             }
408c2c66affSColin Finck 
409c2c66affSColin Finck             /* Free the message */
410c2c66affSColin Finck             LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
411c2c66affSColin Finck         }
412c2c66affSColin Finck         else
413c2c66affSColin Finck         {
414c2c66affSColin Finck             /* We don't have a reply */
415c2c66affSColin Finck             Status = STATUS_LPC_REPLY_LOST;
416c2c66affSColin Finck         }
417c2c66affSColin Finck     }
418c2c66affSColin Finck     else
419c2c66affSColin Finck     {
420c2c66affSColin Finck         /* The wait failed, free the message */
421c2c66affSColin Finck         if (Message) LpcpFreeToPortZone(Message, 0);
422c2c66affSColin Finck     }
423c2c66affSColin Finck 
424c2c66affSColin Finck     /* All done */
425c2c66affSColin Finck     LPCTRACE(LPC_SEND_DEBUG,
426c2c66affSColin Finck              "Port: %p. Status: %d\n",
427c2c66affSColin Finck              Port,
428c2c66affSColin Finck              Status);
429c2c66affSColin Finck 
430c2c66affSColin Finck     /* Dereference the connection port */
431c2c66affSColin Finck     if (ConnectionPort) ObDereferenceObject(ConnectionPort);
432c2c66affSColin Finck     return Status;
433c2c66affSColin Finck }
434c2c66affSColin Finck 
435c2c66affSColin Finck /*
436c2c66affSColin Finck  * @implemented
437c2c66affSColin Finck  */
438c2c66affSColin Finck NTSTATUS
439c2c66affSColin Finck NTAPI
NtRequestPort(IN HANDLE PortHandle,IN PPORT_MESSAGE LpcRequest)440c2c66affSColin Finck NtRequestPort(IN HANDLE PortHandle,
441c2c66affSColin Finck               IN PPORT_MESSAGE LpcRequest)
442c2c66affSColin Finck {
443c2c66affSColin Finck     NTSTATUS Status;
444c2c66affSColin Finck     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
445c2c66affSColin Finck     PETHREAD Thread = PsGetCurrentThread();
446c2c66affSColin Finck     PORT_MESSAGE CapturedLpcRequest;
447c2c66affSColin Finck     PLPCP_PORT_OBJECT Port, QueuePort, ConnectionPort = NULL;
448c2c66affSColin Finck     ULONG MessageType;
449c2c66affSColin Finck     PLPCP_MESSAGE Message;
450c2c66affSColin Finck 
451c2c66affSColin Finck     PAGED_CODE();
452c2c66affSColin Finck 
453c2c66affSColin Finck     /* Check if the call comes from user mode */
454c2c66affSColin Finck     if (PreviousMode != KernelMode)
455c2c66affSColin Finck     {
456c2c66affSColin Finck         _SEH2_TRY
457c2c66affSColin Finck         {
458c2c66affSColin Finck             /* Probe and capture the LpcRequest */
459c2c66affSColin Finck             ProbeForRead(LpcRequest, sizeof(*LpcRequest), sizeof(ULONG));
460c2c66affSColin Finck             CapturedLpcRequest = *(volatile PORT_MESSAGE*)LpcRequest;
461c2c66affSColin Finck         }
462c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
463c2c66affSColin Finck         {
464c2c66affSColin Finck             _SEH2_YIELD(return _SEH2_GetExceptionCode());
465c2c66affSColin Finck         }
466c2c66affSColin Finck         _SEH2_END;
467c2c66affSColin Finck     }
468c2c66affSColin Finck     else
469c2c66affSColin Finck     {
470c2c66affSColin Finck         /* Access the LpcRequest directly */
471c2c66affSColin Finck         CapturedLpcRequest = *LpcRequest;
472c2c66affSColin Finck     }
473c2c66affSColin Finck 
474*b3c55b9eSHermès Bélusca-Maïto     LPCTRACE(LPC_SEND_DEBUG,
475*b3c55b9eSHermès Bélusca-Maïto              "Handle: %p. Message: %p. Type: %lx\n",
476*b3c55b9eSHermès Bélusca-Maïto              PortHandle,
477*b3c55b9eSHermès Bélusca-Maïto              LpcRequest,
478*b3c55b9eSHermès Bélusca-Maïto              LpcpGetMessageType(&CapturedLpcRequest));
479*b3c55b9eSHermès Bélusca-Maïto 
480c2c66affSColin Finck     /* Get the message type */
481c2c66affSColin Finck     MessageType = CapturedLpcRequest.u2.s2.Type | LPC_DATAGRAM;
482c2c66affSColin Finck 
483c2c66affSColin Finck     /* Can't have data information on this type of call */
484c2c66affSColin Finck     if (CapturedLpcRequest.u2.s2.DataInfoOffset) return STATUS_INVALID_PARAMETER;
485c2c66affSColin Finck 
486c2c66affSColin Finck     /* Validate the length */
487c2c66affSColin Finck     if (((ULONG)CapturedLpcRequest.u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
488c2c66affSColin Finck          (ULONG)CapturedLpcRequest.u1.s1.TotalLength)
489c2c66affSColin Finck     {
490c2c66affSColin Finck         /* Fail */
491c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
492c2c66affSColin Finck     }
493c2c66affSColin Finck 
494c2c66affSColin Finck     /* Reference the object */
495c2c66affSColin Finck     Status = ObReferenceObjectByHandle(PortHandle,
496c2c66affSColin Finck                                        0,
497c2c66affSColin Finck                                        LpcPortObjectType,
498c2c66affSColin Finck                                        PreviousMode,
499c2c66affSColin Finck                                        (PVOID*)&Port,
500c2c66affSColin Finck                                        NULL);
501c2c66affSColin Finck     if (!NT_SUCCESS(Status)) return Status;
502c2c66affSColin Finck 
503c2c66affSColin Finck     /* Validate the message length */
504c2c66affSColin Finck     if (((ULONG)CapturedLpcRequest.u1.s1.TotalLength > Port->MaxMessageLength) ||
505c2c66affSColin Finck         ((ULONG)CapturedLpcRequest.u1.s1.TotalLength <= (ULONG)CapturedLpcRequest.u1.s1.DataLength))
506c2c66affSColin Finck     {
507c2c66affSColin Finck         /* Fail */
508c2c66affSColin Finck         ObDereferenceObject(Port);
509c2c66affSColin Finck         return STATUS_PORT_MESSAGE_TOO_LONG;
510c2c66affSColin Finck     }
511c2c66affSColin Finck 
512c2c66affSColin Finck     /* Allocate a message from the port zone */
513c2c66affSColin Finck     Message = LpcpAllocateFromPortZone();
514c2c66affSColin Finck     if (!Message)
515c2c66affSColin Finck     {
516c2c66affSColin Finck         /* Fail if we couldn't allocate a message */
517c2c66affSColin Finck         ObDereferenceObject(Port);
518c2c66affSColin Finck         return STATUS_NO_MEMORY;
519c2c66affSColin Finck     }
520c2c66affSColin Finck 
521c2c66affSColin Finck     /* No callback, just copy the message */
522c2c66affSColin Finck     _SEH2_TRY
523c2c66affSColin Finck     {
524c2c66affSColin Finck         /* Copy it */
525c2c66affSColin Finck         LpcpMoveMessage(&Message->Request,
526c2c66affSColin Finck                         &CapturedLpcRequest,
527c2c66affSColin Finck                         LpcRequest + 1,
528c2c66affSColin Finck                         MessageType,
529c2c66affSColin Finck                         &Thread->Cid);
530c2c66affSColin Finck     }
531c2c66affSColin Finck     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
532c2c66affSColin Finck     {
533c2c66affSColin Finck         /* Cleanup and return the exception code */
534c2c66affSColin Finck         LpcpFreeToPortZone(Message, 0);
535c2c66affSColin Finck         ObDereferenceObject(Port);
536c2c66affSColin Finck         _SEH2_YIELD(return _SEH2_GetExceptionCode());
537c2c66affSColin Finck     }
538c2c66affSColin Finck     _SEH2_END;
539c2c66affSColin Finck 
540c2c66affSColin Finck     /* Acquire the LPC lock */
541c2c66affSColin Finck     KeAcquireGuardedMutex(&LpcpLock);
542c2c66affSColin Finck 
543c2c66affSColin Finck     /* Right now clear the port context */
544c2c66affSColin Finck     Message->PortContext = NULL;
545c2c66affSColin Finck 
546c2c66affSColin Finck     /* Check if this is a not connection port */
547c2c66affSColin Finck     if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
548c2c66affSColin Finck     {
549c2c66affSColin Finck         /* We want the connected port */
550c2c66affSColin Finck         QueuePort = Port->ConnectedPort;
551c2c66affSColin Finck         if (!QueuePort)
552c2c66affSColin Finck         {
553c2c66affSColin Finck             /* We have no connected port, fail */
554c2c66affSColin Finck             LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
555c2c66affSColin Finck             ObDereferenceObject(Port);
556c2c66affSColin Finck             return STATUS_PORT_DISCONNECTED;
557c2c66affSColin Finck         }
558c2c66affSColin Finck 
559c2c66affSColin Finck         /* Check if this is a communication port */
560c2c66affSColin Finck         if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
561c2c66affSColin Finck         {
562c2c66affSColin Finck             /* Copy the port context and use the connection port */
563c2c66affSColin Finck             Message->PortContext = QueuePort->PortContext;
564c2c66affSColin Finck             ConnectionPort = QueuePort = Port->ConnectionPort;
565c2c66affSColin Finck             if (!ConnectionPort)
566c2c66affSColin Finck             {
567c2c66affSColin Finck                 /* Fail */
568c2c66affSColin Finck                 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
569c2c66affSColin Finck                 ObDereferenceObject(Port);
570c2c66affSColin Finck                 return STATUS_PORT_DISCONNECTED;
571c2c66affSColin Finck             }
572c2c66affSColin Finck         }
573c2c66affSColin Finck         else if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT)
574c2c66affSColin Finck         {
575c2c66affSColin Finck             /* Use the connection port for anything but communication ports */
576c2c66affSColin Finck             ConnectionPort = QueuePort = Port->ConnectionPort;
577c2c66affSColin Finck             if (!ConnectionPort)
578c2c66affSColin Finck             {
579c2c66affSColin Finck                 /* Fail */
580c2c66affSColin Finck                 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
581c2c66affSColin Finck                 ObDereferenceObject(Port);
582c2c66affSColin Finck                 return STATUS_PORT_DISCONNECTED;
583c2c66affSColin Finck             }
584c2c66affSColin Finck         }
585c2c66affSColin Finck 
586c2c66affSColin Finck         /* Reference the connection port if it exists */
587c2c66affSColin Finck         if (ConnectionPort) ObReferenceObject(ConnectionPort);
588c2c66affSColin Finck     }
589c2c66affSColin Finck     else
590c2c66affSColin Finck     {
591c2c66affSColin Finck         /* Otherwise, for a connection port, use the same port object */
592c2c66affSColin Finck         QueuePort = Port;
593c2c66affSColin Finck     }
594c2c66affSColin Finck 
595c2c66affSColin Finck     /* Reference QueuePort if we have it */
596c2c66affSColin Finck     if (QueuePort && ObReferenceObjectSafe(QueuePort))
597c2c66affSColin Finck     {
598c2c66affSColin Finck         /* Set sender's port */
599c2c66affSColin Finck         Message->SenderPort = Port;
600c2c66affSColin Finck 
601c2c66affSColin Finck         /* Generate the Message ID and set it */
602c2c66affSColin Finck         Message->Request.MessageId = LpcpNextMessageId++;
603c2c66affSColin Finck         if (!LpcpNextMessageId) LpcpNextMessageId = 1;
604c2c66affSColin Finck         Message->Request.CallbackId = 0;
605c2c66affSColin Finck 
606c2c66affSColin Finck         /* No Message ID for the thread */
607c2c66affSColin Finck         Thread->LpcReplyMessageId = 0;
608c2c66affSColin Finck 
609c2c66affSColin Finck         /* Insert the message in our chain */
610c2c66affSColin Finck         InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);
611c2c66affSColin Finck 
612c2c66affSColin Finck         /* Release the lock and the semaphore */
613c2c66affSColin Finck         KeEnterCriticalRegion();
614c2c66affSColin Finck         KeReleaseGuardedMutex(&LpcpLock);
615c2c66affSColin Finck         LpcpCompleteWait(QueuePort->MsgQueue.Semaphore);
616c2c66affSColin Finck 
617c2c66affSColin Finck         /* If this is a waitable port, wake it up */
618c2c66affSColin Finck         if (QueuePort->Flags & LPCP_WAITABLE_PORT)
619c2c66affSColin Finck         {
620c2c66affSColin Finck             /* Wake it */
621c2c66affSColin Finck             KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
622c2c66affSColin Finck         }
623c2c66affSColin Finck 
624c2c66affSColin Finck         KeLeaveCriticalRegion();
625c2c66affSColin Finck 
626c2c66affSColin Finck         /* Dereference objects */
627c2c66affSColin Finck         if (ConnectionPort) ObDereferenceObject(ConnectionPort);
628c2c66affSColin Finck         ObDereferenceObject(QueuePort);
629c2c66affSColin Finck         ObDereferenceObject(Port);
630c2c66affSColin Finck         LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", QueuePort, Message);
631c2c66affSColin Finck         return STATUS_SUCCESS;
632c2c66affSColin Finck     }
633c2c66affSColin Finck 
634c2c66affSColin Finck     Status = STATUS_PORT_DISCONNECTED;
635c2c66affSColin Finck 
636c2c66affSColin Finck     /* All done with a failure*/
637c2c66affSColin Finck     LPCTRACE(LPC_SEND_DEBUG,
638c2c66affSColin Finck              "Port: %p. Status: %d\n",
639c2c66affSColin Finck              Port,
640c2c66affSColin Finck              Status);
641c2c66affSColin Finck 
642c2c66affSColin Finck     /* The wait failed, free the message */
643c2c66affSColin Finck     if (Message) LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
644c2c66affSColin Finck 
645c2c66affSColin Finck     ObDereferenceObject(Port);
646c2c66affSColin Finck     if (ConnectionPort) ObDereferenceObject(ConnectionPort);
647c2c66affSColin Finck     return Status;
648c2c66affSColin Finck }
649c2c66affSColin Finck 
650c2c66affSColin Finck NTSTATUS
651c2c66affSColin Finck NTAPI
LpcpVerifyMessageDataInfo(_In_ PPORT_MESSAGE Message,_Out_ PULONG NumberOfDataEntries)652c2c66affSColin Finck LpcpVerifyMessageDataInfo(
653c2c66affSColin Finck     _In_ PPORT_MESSAGE Message,
654c2c66affSColin Finck     _Out_ PULONG NumberOfDataEntries)
655c2c66affSColin Finck {
656c2c66affSColin Finck     PLPCP_DATA_INFO DataInfo;
657c2c66affSColin Finck     PUCHAR EndOfEntries;
658c2c66affSColin Finck 
659c2c66affSColin Finck     /* Check if we have no data info at all */
660c2c66affSColin Finck     if (Message->u2.s2.DataInfoOffset == 0)
661c2c66affSColin Finck     {
662c2c66affSColin Finck         *NumberOfDataEntries = 0;
663c2c66affSColin Finck         return STATUS_SUCCESS;
664c2c66affSColin Finck     }
665c2c66affSColin Finck 
666c2c66affSColin Finck     /* Make sure the data info structure is within the message */
667c2c66affSColin Finck     if (((ULONG)Message->u1.s1.TotalLength <
668c2c66affSColin Finck             sizeof(PORT_MESSAGE) + sizeof(LPCP_DATA_INFO)) ||
669c2c66affSColin Finck         ((ULONG)Message->u2.s2.DataInfoOffset < sizeof(PORT_MESSAGE)) ||
670c2c66affSColin Finck         ((ULONG)Message->u2.s2.DataInfoOffset >
671c2c66affSColin Finck             ((ULONG)Message->u1.s1.TotalLength - sizeof(LPCP_DATA_INFO))))
672c2c66affSColin Finck     {
673c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
674c2c66affSColin Finck     }
675c2c66affSColin Finck 
676c2c66affSColin Finck     /* Get a pointer to the data info */
677c2c66affSColin Finck     DataInfo = LpcpGetDataInfoFromMessage(Message);
678c2c66affSColin Finck 
679c2c66affSColin Finck     /* Make sure the full data info with all entries is within the message */
680c2c66affSColin Finck     EndOfEntries = (PUCHAR)&DataInfo->Entries[DataInfo->NumberOfEntries];
681c2c66affSColin Finck     if ((EndOfEntries > ((PUCHAR)Message + (ULONG)Message->u1.s1.TotalLength)) ||
682c2c66affSColin Finck         (EndOfEntries < (PUCHAR)Message))
683c2c66affSColin Finck     {
684c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
685c2c66affSColin Finck     }
686c2c66affSColin Finck 
687c2c66affSColin Finck     *NumberOfDataEntries = DataInfo->NumberOfEntries;
688c2c66affSColin Finck     return STATUS_SUCCESS;
689c2c66affSColin Finck }
690c2c66affSColin Finck 
691c2c66affSColin Finck /*
692c2c66affSColin Finck  * @implemented
693c2c66affSColin Finck  */
694c2c66affSColin Finck NTSTATUS
695c2c66affSColin Finck NTAPI
NtRequestWaitReplyPort(IN HANDLE PortHandle,IN PPORT_MESSAGE LpcRequest,IN OUT PPORT_MESSAGE LpcReply)696c2c66affSColin Finck NtRequestWaitReplyPort(IN HANDLE PortHandle,
697c2c66affSColin Finck                        IN PPORT_MESSAGE LpcRequest,
698c2c66affSColin Finck                        IN OUT PPORT_MESSAGE LpcReply)
699c2c66affSColin Finck {
700c2c66affSColin Finck     NTSTATUS Status;
701c2c66affSColin Finck     PORT_MESSAGE CapturedLpcRequest;
702c2c66affSColin Finck     ULONG NumberOfDataEntries;
703c2c66affSColin Finck     PLPCP_PORT_OBJECT Port, QueuePort, ReplyPort, ConnectionPort = NULL;
704c2c66affSColin Finck     PLPCP_MESSAGE Message;
705c2c66affSColin Finck     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
706c2c66affSColin Finck     PETHREAD Thread = PsGetCurrentThread();
707c2c66affSColin Finck     BOOLEAN Callback;
708c2c66affSColin Finck     PKSEMAPHORE Semaphore;
709c2c66affSColin Finck     ULONG MessageType;
710c2c66affSColin Finck     PLPCP_DATA_INFO DataInfo;
711c2c66affSColin Finck 
712c2c66affSColin Finck     PAGED_CODE();
713c2c66affSColin Finck 
714c2c66affSColin Finck     /* Check if the thread is dying */
715*b3c55b9eSHermès Bélusca-Maïto     if (Thread->LpcExitThreadCalled)
716*b3c55b9eSHermès Bélusca-Maïto         return STATUS_THREAD_IS_TERMINATING;
717c2c66affSColin Finck 
718c2c66affSColin Finck     /* Check for user mode access */
719c2c66affSColin Finck     if (PreviousMode != KernelMode)
720c2c66affSColin Finck     {
721c2c66affSColin Finck         _SEH2_TRY
722c2c66affSColin Finck         {
723c2c66affSColin Finck             /* Probe and capture the LpcRequest */
724c2c66affSColin Finck             ProbeForRead(LpcRequest, sizeof(*LpcRequest), sizeof(ULONG));
725c2c66affSColin Finck             CapturedLpcRequest = *(volatile PORT_MESSAGE*)LpcRequest;
726c2c66affSColin Finck 
727c2c66affSColin Finck             /* Probe the reply message for write */
728c2c66affSColin Finck             ProbeForWrite(LpcReply, sizeof(*LpcReply), sizeof(ULONG));
729c2c66affSColin Finck 
730c2c66affSColin Finck             /* Make sure the data entries in the request message are valid */
731c2c66affSColin Finck             Status = LpcpVerifyMessageDataInfo(LpcRequest, &NumberOfDataEntries);
732c2c66affSColin Finck             if (!NT_SUCCESS(Status))
733c2c66affSColin Finck             {
734c2c66affSColin Finck                 DPRINT1("LpcpVerifyMessageDataInfo failed\n");
735c2c66affSColin Finck                 _SEH2_YIELD(return Status);
736c2c66affSColin Finck             }
737c2c66affSColin Finck         }
738c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
739c2c66affSColin Finck         {
740c2c66affSColin Finck             DPRINT1("Got exception\n");
741c2c66affSColin Finck             _SEH2_YIELD(return _SEH2_GetExceptionCode());
742c2c66affSColin Finck         }
743c2c66affSColin Finck         _SEH2_END;
744c2c66affSColin Finck     }
745c2c66affSColin Finck     else
746c2c66affSColin Finck     {
747c2c66affSColin Finck         CapturedLpcRequest = *LpcRequest;
748c2c66affSColin Finck         Status = LpcpVerifyMessageDataInfo(LpcRequest, &NumberOfDataEntries);
749c2c66affSColin Finck         if (!NT_SUCCESS(Status))
750c2c66affSColin Finck         {
751c2c66affSColin Finck             DPRINT1("LpcpVerifyMessageDataInfo failed\n");
752c2c66affSColin Finck             return Status;
753c2c66affSColin Finck         }
754c2c66affSColin Finck     }
755c2c66affSColin Finck 
756*b3c55b9eSHermès Bélusca-Maïto     LPCTRACE(LPC_SEND_DEBUG,
757*b3c55b9eSHermès Bélusca-Maïto              "Handle: %p. Messages: %p/%p. Type: %lx\n",
758*b3c55b9eSHermès Bélusca-Maïto              PortHandle,
759*b3c55b9eSHermès Bélusca-Maïto              LpcRequest,
760*b3c55b9eSHermès Bélusca-Maïto              LpcReply,
761*b3c55b9eSHermès Bélusca-Maïto              LpcpGetMessageType(&CapturedLpcRequest));
762*b3c55b9eSHermès Bélusca-Maïto 
763c2c66affSColin Finck     /* This flag is undocumented. Remove it before continuing */
764c2c66affSColin Finck     CapturedLpcRequest.u2.s2.Type &= ~0x4000;
765c2c66affSColin Finck 
766c2c66affSColin Finck     /* Check if this is an LPC Request */
767c2c66affSColin Finck     if (LpcpGetMessageType(&CapturedLpcRequest) == LPC_REQUEST)
768c2c66affSColin Finck     {
769c2c66affSColin Finck         /* Then it's a callback */
770c2c66affSColin Finck         Callback = TRUE;
771c2c66affSColin Finck     }
772c2c66affSColin Finck     else if (LpcpGetMessageType(&CapturedLpcRequest))
773c2c66affSColin Finck     {
774c2c66affSColin Finck         /* This is a not kernel-mode message */
775c2c66affSColin Finck         DPRINT1("Not a kernel-mode message!\n");
776c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
777c2c66affSColin Finck     }
778c2c66affSColin Finck     else
779c2c66affSColin Finck     {
780c2c66affSColin Finck         /* This is a kernel-mode message without a callback */
781c2c66affSColin Finck         CapturedLpcRequest.u2.s2.Type |= LPC_REQUEST;
782c2c66affSColin Finck         Callback = FALSE;
783c2c66affSColin Finck     }
784c2c66affSColin Finck 
785c2c66affSColin Finck     /* Get the message type */
786c2c66affSColin Finck     MessageType = CapturedLpcRequest.u2.s2.Type;
787c2c66affSColin Finck 
788c2c66affSColin Finck     /* Due to the above probe, we know that TotalLength is positive */
789c2c66affSColin Finck     ASSERT(CapturedLpcRequest.u1.s1.TotalLength >= 0);
790c2c66affSColin Finck 
791c2c66affSColin Finck     /* Validate the length */
792c2c66affSColin Finck     if ((((ULONG)(USHORT)CapturedLpcRequest.u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
793c2c66affSColin Finck          (ULONG)CapturedLpcRequest.u1.s1.TotalLength))
794c2c66affSColin Finck     {
795c2c66affSColin Finck         /* Fail */
796c2c66affSColin Finck         DPRINT1("Invalid message length: %u, %u\n",
797c2c66affSColin Finck                 CapturedLpcRequest.u1.s1.DataLength,
798c2c66affSColin Finck                 CapturedLpcRequest.u1.s1.TotalLength);
799c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
800c2c66affSColin Finck     }
801c2c66affSColin Finck 
802c2c66affSColin Finck     /* Reference the object */
803c2c66affSColin Finck     Status = ObReferenceObjectByHandle(PortHandle,
804c2c66affSColin Finck                                        0,
805c2c66affSColin Finck                                        LpcPortObjectType,
806c2c66affSColin Finck                                        PreviousMode,
807c2c66affSColin Finck                                        (PVOID*)&Port,
808c2c66affSColin Finck                                        NULL);
809c2c66affSColin Finck     if (!NT_SUCCESS(Status)) return Status;
810c2c66affSColin Finck 
811c2c66affSColin Finck     /* Validate the message length */
812c2c66affSColin Finck     if (((ULONG)CapturedLpcRequest.u1.s1.TotalLength > Port->MaxMessageLength) ||
813c2c66affSColin Finck         ((ULONG)CapturedLpcRequest.u1.s1.TotalLength <= (ULONG)CapturedLpcRequest.u1.s1.DataLength))
814c2c66affSColin Finck     {
815c2c66affSColin Finck         /* Fail */
816c2c66affSColin Finck         DPRINT1("Invalid message length: %u, %u\n",
817c2c66affSColin Finck                 CapturedLpcRequest.u1.s1.DataLength,
818c2c66affSColin Finck                 CapturedLpcRequest.u1.s1.TotalLength);
819c2c66affSColin Finck         ObDereferenceObject(Port);
820c2c66affSColin Finck         return STATUS_PORT_MESSAGE_TOO_LONG;
821c2c66affSColin Finck     }
822c2c66affSColin Finck 
823c2c66affSColin Finck     /* Allocate a message from the port zone */
824c2c66affSColin Finck     Message = LpcpAllocateFromPortZone();
825c2c66affSColin Finck     if (!Message)
826c2c66affSColin Finck     {
827c2c66affSColin Finck         /* Fail if we couldn't allocate a message */
828c2c66affSColin Finck         DPRINT1("Failed to allocate a message!\n");
829c2c66affSColin Finck         ObDereferenceObject(Port);
830c2c66affSColin Finck         return STATUS_NO_MEMORY;
831c2c66affSColin Finck     }
832c2c66affSColin Finck 
833c2c66affSColin Finck     /* Check if this is a callback */
834c2c66affSColin Finck     if (Callback)
835c2c66affSColin Finck     {
836c2c66affSColin Finck         /* FIXME: TODO */
837c2c66affSColin Finck         Semaphore = NULL; // we'd use the Thread Semaphore here
838c2c66affSColin Finck         ASSERT(FALSE);
839c2c66affSColin Finck     }
840c2c66affSColin Finck     else
841c2c66affSColin Finck     {
842c2c66affSColin Finck         /* No callback, just copy the message */
843c2c66affSColin Finck         _SEH2_TRY
844c2c66affSColin Finck         {
845c2c66affSColin Finck             /* Check if we have data info entries */
846c2c66affSColin Finck             if (LpcRequest->u2.s2.DataInfoOffset != 0)
847c2c66affSColin Finck             {
848c2c66affSColin Finck                 /* Get the data info and check if the number of entries matches
849c2c66affSColin Finck                    what we expect */
850c2c66affSColin Finck                 DataInfo = LpcpGetDataInfoFromMessage(LpcRequest);
851c2c66affSColin Finck                 if (DataInfo->NumberOfEntries != NumberOfDataEntries)
852c2c66affSColin Finck                 {
853c2c66affSColin Finck                     LpcpFreeToPortZone(Message, 0);
854c2c66affSColin Finck                     ObDereferenceObject(Port);
855c2c66affSColin Finck                     DPRINT1("NumberOfEntries has changed: %u, %u\n",
856c2c66affSColin Finck                             DataInfo->NumberOfEntries, NumberOfDataEntries);
857c2c66affSColin Finck                     _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
858c2c66affSColin Finck                 }
859c2c66affSColin Finck             }
860c2c66affSColin Finck 
861c2c66affSColin Finck             /* Copy it */
862c2c66affSColin Finck             LpcpMoveMessage(&Message->Request,
863c2c66affSColin Finck                             &CapturedLpcRequest,
864c2c66affSColin Finck                             LpcRequest + 1,
865c2c66affSColin Finck                             MessageType,
866c2c66affSColin Finck                             &Thread->Cid);
867c2c66affSColin Finck         }
868c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
869c2c66affSColin Finck         {
870c2c66affSColin Finck             /* Cleanup and return the exception code */
871c2c66affSColin Finck             DPRINT1("Got exception!\n");
872c2c66affSColin Finck             LpcpFreeToPortZone(Message, 0);
873c2c66affSColin Finck             ObDereferenceObject(Port);
874c2c66affSColin Finck             _SEH2_YIELD(return _SEH2_GetExceptionCode());
875c2c66affSColin Finck         }
876c2c66affSColin Finck         _SEH2_END;
877c2c66affSColin Finck 
878c2c66affSColin Finck         /* Acquire the LPC lock */
879c2c66affSColin Finck         KeAcquireGuardedMutex(&LpcpLock);
880c2c66affSColin Finck 
881c2c66affSColin Finck         /* Right now clear the port context */
882c2c66affSColin Finck         Message->PortContext = NULL;
883c2c66affSColin Finck 
884c2c66affSColin Finck         /* Check if this is a not connection port */
885c2c66affSColin Finck         if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
886c2c66affSColin Finck         {
887c2c66affSColin Finck             /* We want the connected port */
888c2c66affSColin Finck             QueuePort = Port->ConnectedPort;
889c2c66affSColin Finck             if (!QueuePort)
890c2c66affSColin Finck             {
891c2c66affSColin Finck                 /* We have no connected port, fail */
892c2c66affSColin Finck                 DPRINT1("No connected port\n");
893c2c66affSColin Finck                 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
894c2c66affSColin Finck                 ObDereferenceObject(Port);
895c2c66affSColin Finck                 return STATUS_PORT_DISCONNECTED;
896c2c66affSColin Finck             }
897c2c66affSColin Finck 
898c2c66affSColin Finck             /* This will be the rundown port */
899c2c66affSColin Finck             ReplyPort = QueuePort;
900c2c66affSColin Finck 
901c2c66affSColin Finck             /* Check if this is a client port */
902c2c66affSColin Finck             if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
903c2c66affSColin Finck             {
904c2c66affSColin Finck                 /* Copy the port context */
905c2c66affSColin Finck                 Message->PortContext = QueuePort->PortContext;
906c2c66affSColin Finck             }
907c2c66affSColin Finck 
908c2c66affSColin Finck             if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT)
909c2c66affSColin Finck             {
910c2c66affSColin Finck                 /* Use the connection port for anything but communication ports */
911c2c66affSColin Finck                 ConnectionPort = QueuePort = Port->ConnectionPort;
912c2c66affSColin Finck                 if (!ConnectionPort)
913c2c66affSColin Finck                 {
914c2c66affSColin Finck                     /* Fail */
915c2c66affSColin Finck                     DPRINT1("No connection port\n");
916c2c66affSColin Finck                     LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
917c2c66affSColin Finck                     ObDereferenceObject(Port);
918c2c66affSColin Finck                     return STATUS_PORT_DISCONNECTED;
919c2c66affSColin Finck                 }
920c2c66affSColin Finck             }
921c2c66affSColin Finck 
922c2c66affSColin Finck             /* Reference the connection port if it exists */
923c2c66affSColin Finck             if (ConnectionPort) ObReferenceObject(ConnectionPort);
924c2c66affSColin Finck         }
925c2c66affSColin Finck         else
926c2c66affSColin Finck         {
927c2c66affSColin Finck             /* Otherwise, for a connection port, use the same port object */
928c2c66affSColin Finck             QueuePort = ReplyPort = Port;
929c2c66affSColin Finck         }
930c2c66affSColin Finck 
931c2c66affSColin Finck         /* No reply thread */
932c2c66affSColin Finck         Message->RepliedToThread = NULL;
933c2c66affSColin Finck         Message->SenderPort = Port;
934c2c66affSColin Finck 
935c2c66affSColin Finck         /* Generate the Message ID and set it */
936c2c66affSColin Finck         Message->Request.MessageId = LpcpNextMessageId++;
937c2c66affSColin Finck         if (!LpcpNextMessageId) LpcpNextMessageId = 1;
938c2c66affSColin Finck         Message->Request.CallbackId = 0;
939c2c66affSColin Finck 
940c2c66affSColin Finck         /* Set the message ID for our thread now */
941c2c66affSColin Finck         Thread->LpcReplyMessageId = Message->Request.MessageId;
942c2c66affSColin Finck         Thread->LpcReplyMessage = NULL;
943c2c66affSColin Finck 
944c2c66affSColin Finck         /* Insert the message in our chain */
945c2c66affSColin Finck         InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);
946c2c66affSColin Finck         InsertTailList(&ReplyPort->LpcReplyChainHead, &Thread->LpcReplyChain);
947c2c66affSColin Finck         LpcpSetPortToThread(Thread, Port);
948c2c66affSColin Finck 
949c2c66affSColin Finck         /* Release the lock and get the semaphore we'll use later */
950c2c66affSColin Finck         KeEnterCriticalRegion();
951c2c66affSColin Finck         KeReleaseGuardedMutex(&LpcpLock);
952c2c66affSColin Finck         Semaphore = QueuePort->MsgQueue.Semaphore;
953c2c66affSColin Finck 
954c2c66affSColin Finck         /* If this is a waitable port, wake it up */
955c2c66affSColin Finck         if (QueuePort->Flags & LPCP_WAITABLE_PORT)
956c2c66affSColin Finck         {
957c2c66affSColin Finck             /* Wake it */
958c2c66affSColin Finck             KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
959c2c66affSColin Finck         }
960c2c66affSColin Finck     }
961c2c66affSColin Finck 
962c2c66affSColin Finck     /* Now release the semaphore */
963c2c66affSColin Finck     LpcpCompleteWait(Semaphore);
964c2c66affSColin Finck     KeLeaveCriticalRegion();
965c2c66affSColin Finck 
966c2c66affSColin Finck     /* And let's wait for the reply */
967c2c66affSColin Finck     LpcpReplyWait(&Thread->LpcReplySemaphore, PreviousMode);
968c2c66affSColin Finck 
969c2c66affSColin Finck     /* Acquire the LPC lock */
970c2c66affSColin Finck     KeAcquireGuardedMutex(&LpcpLock);
971c2c66affSColin Finck 
972c2c66affSColin Finck     /* Get the LPC Message and clear our thread's reply data */
973c2c66affSColin Finck     Message = LpcpGetMessageFromThread(Thread);
974c2c66affSColin Finck     Thread->LpcReplyMessage = NULL;
975c2c66affSColin Finck     Thread->LpcReplyMessageId = 0;
976c2c66affSColin Finck 
977c2c66affSColin Finck     /* Check if we have anything on the reply chain*/
978c2c66affSColin Finck     if (!IsListEmpty(&Thread->LpcReplyChain))
979c2c66affSColin Finck     {
980c2c66affSColin Finck         /* Remove this thread and reinitialize the list */
981c2c66affSColin Finck         RemoveEntryList(&Thread->LpcReplyChain);
982c2c66affSColin Finck         InitializeListHead(&Thread->LpcReplyChain);
983c2c66affSColin Finck     }
984c2c66affSColin Finck 
985c2c66affSColin Finck     /* Release the lock */
986c2c66affSColin Finck     KeReleaseGuardedMutex(&LpcpLock);
987c2c66affSColin Finck 
988c2c66affSColin Finck     /* Check if we got a reply */
989c2c66affSColin Finck     if (Status == STATUS_SUCCESS)
990c2c66affSColin Finck     {
991c2c66affSColin Finck         /* Check if we have a valid message */
992c2c66affSColin Finck         if (Message)
993c2c66affSColin Finck         {
994c2c66affSColin Finck             LPCTRACE(LPC_SEND_DEBUG,
995c2c66affSColin Finck                      "Reply Messages: %p/%p\n",
996c2c66affSColin Finck                      &Message->Request,
997c2c66affSColin Finck                      (&Message->Request) + 1);
998c2c66affSColin Finck 
999c2c66affSColin Finck             /* Move the message */
1000c2c66affSColin Finck             _SEH2_TRY
1001c2c66affSColin Finck             {
1002c2c66affSColin Finck                 LpcpMoveMessage(LpcReply,
1003c2c66affSColin Finck                                 &Message->Request,
1004c2c66affSColin Finck                                 (&Message->Request) + 1,
1005c2c66affSColin Finck                                 0,
1006c2c66affSColin Finck                                 NULL);
1007c2c66affSColin Finck             }
1008c2c66affSColin Finck             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1009c2c66affSColin Finck             {
1010c2c66affSColin Finck                 DPRINT1("Got exception!\n");
1011c2c66affSColin Finck                 Status = _SEH2_GetExceptionCode();
1012c2c66affSColin Finck             }
1013c2c66affSColin Finck             _SEH2_END;
1014c2c66affSColin Finck 
1015c2c66affSColin Finck             /* Check if this is an LPC request with data information */
1016c2c66affSColin Finck             if ((LpcpGetMessageType(&Message->Request) == LPC_REQUEST) &&
1017c2c66affSColin Finck                 (Message->Request.u2.s2.DataInfoOffset))
1018c2c66affSColin Finck             {
1019c2c66affSColin Finck                 /* Save the data information */
1020c2c66affSColin Finck                 LpcpSaveDataInfoMessage(Port, Message, 0);
1021c2c66affSColin Finck             }
1022c2c66affSColin Finck             else
1023c2c66affSColin Finck             {
1024c2c66affSColin Finck                 /* Otherwise, just free it */
1025c2c66affSColin Finck                 LpcpFreeToPortZone(Message, 0);
1026c2c66affSColin Finck             }
1027c2c66affSColin Finck         }
1028c2c66affSColin Finck         else
1029c2c66affSColin Finck         {
1030c2c66affSColin Finck             /* We don't have a reply */
1031c2c66affSColin Finck             Status = STATUS_LPC_REPLY_LOST;
1032c2c66affSColin Finck         }
1033c2c66affSColin Finck     }
1034c2c66affSColin Finck     else
1035c2c66affSColin Finck     {
1036c2c66affSColin Finck         /* The wait failed, free the message */
1037c2c66affSColin Finck         if (Message) LpcpFreeToPortZone(Message, 0);
1038c2c66affSColin Finck     }
1039c2c66affSColin Finck 
1040c2c66affSColin Finck     /* All done */
1041c2c66affSColin Finck     LPCTRACE(LPC_SEND_DEBUG,
1042c2c66affSColin Finck              "Port: %p. Status: %d\n",
1043c2c66affSColin Finck              Port,
1044c2c66affSColin Finck              Status);
1045c2c66affSColin Finck     ObDereferenceObject(Port);
1046c2c66affSColin Finck     if (ConnectionPort) ObDereferenceObject(ConnectionPort);
1047c2c66affSColin Finck     return Status;
1048c2c66affSColin Finck }
1049c2c66affSColin Finck 
1050c2c66affSColin Finck /* EOF */
1051