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