3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/lpc/send.c
6 * PURPOSE: Communication mechanism
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
11 /* INCLUDES *****************************************************************/
16 #include <internal/debug.h>
19 /**********************************************************************
21 * LpcSendTerminationPort/2
32 LpcSendTerminationPort (IN PEPORT Port
,
33 IN LARGE_INTEGER CreateTime
)
39 Msg
.h
.u2
.s2
.Type
= LPC_CLIENT_DIED
;
41 Msg
.CreateTime
= CreateTime
;
42 Status
= LpcRequestPort (Port
, &Msg
.h
);
47 /**********************************************************************
49 * LpcSendDebugMessagePort/3
60 LpcSendDebugMessagePort (IN PEPORT Port
,
61 IN PDBGKM_MSG Message
,
66 PQUEUEDMESSAGE ReplyMessage
;
68 Status
= EiReplyOrRequestPort(Port
,
72 if (!NT_SUCCESS(Status
))
74 ObDereferenceObject(Port
);
77 KeReleaseSemaphore(&Port
->OtherPort
->Semaphore
, IO_NO_INCREMENT
, 1, FALSE
);
82 KeWaitForSingleObject(&Port
->Semaphore
,
91 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
92 ReplyMessage
= EiDequeueMessagePort(Port
);
93 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
94 memcpy(Reply
, &ReplyMessage
->Message
, ReplyMessage
->Message
.u1
.s1
.TotalLength
);
95 ExFreePool(ReplyMessage
);
97 return(STATUS_SUCCESS
);
101 /**********************************************************************
113 * I investigated this function a bit more in depth.
114 * It looks like the legal values for the MessageType field in the
115 * message to send are in the range LPC_NEW_MESSAGE .. LPC_CLIENT_DIED,
116 * but LPC_DATAGRAM is explicitly forbidden.
120 NTSTATUS STDCALL
LpcRequestPort (IN PEPORT Port
,
121 IN PPORT_MESSAGE LpcMessage
)
125 DPRINT("LpcRequestPort(PortHandle %08x, LpcMessage %08x)\n", Port
, LpcMessage
);
127 #ifdef __USE_NT_LPC__
128 /* Check the message's type */
129 if (LPC_NEW_MESSAGE
== LpcMessage
->u2
.s2
.Type
)
131 LpcMessage
->u2
.s2
.Type
= LPC_DATAGRAM
;
133 else if (LPC_DATAGRAM
== LpcMessage
->u2
.s2
.Type
)
135 return STATUS_INVALID_PARAMETER
;
137 else if (LpcMessage
->u2
.s2
.Type
> LPC_CLIENT_DIED
)
139 return STATUS_INVALID_PARAMETER
;
141 /* Check the range offset */
142 if (0 != LpcMessage
->VirtualRangesOffset
)
144 return STATUS_INVALID_PARAMETER
;
148 Status
= EiReplyOrRequestPort(Port
,
152 KeReleaseSemaphore( &Port
->Semaphore
, IO_NO_INCREMENT
, 1, FALSE
);
158 /**********************************************************************
172 NTSTATUS STDCALL
NtRequestPort (IN HANDLE PortHandle
,
173 IN PPORT_MESSAGE LpcMessage
)
178 DPRINT("NtRequestPort(PortHandle %x LpcMessage %x)\n", PortHandle
,
181 Status
= ObReferenceObjectByHandle(PortHandle
,
187 if (!NT_SUCCESS(Status
))
189 DPRINT("NtRequestPort() = %x\n", Status
);
193 Status
= LpcRequestPort(Port
->OtherPort
,
196 ObDereferenceObject(Port
);
201 /**********************************************************************
203 * NtRequestWaitReplyPort/3
216 NtRequestWaitReplyPort (IN HANDLE PortHandle
,
217 PPORT_MESSAGE UnsafeLpcRequest
,
218 PPORT_MESSAGE UnsafeLpcReply
)
220 PETHREAD CurrentThread
;
221 struct _KPROCESS
*AttachedProcess
;
223 PQUEUEDMESSAGE Message
;
225 PPORT_MESSAGE LpcRequest
;
226 USHORT LpcRequestMessageSize
= 0, LpcRequestDataSize
= 0;
227 KPROCESSOR_MODE PreviousMode
;
228 NTSTATUS Status
= STATUS_SUCCESS
;
230 PreviousMode
= ExGetPreviousMode();
232 if (PreviousMode
!= KernelMode
)
236 ProbeForRead(UnsafeLpcRequest
,
237 sizeof(PORT_MESSAGE
),
239 ProbeForWrite(UnsafeLpcReply
,
240 sizeof(PORT_MESSAGE
),
242 LpcRequestMessageSize
= UnsafeLpcRequest
->u1
.s1
.TotalLength
;
246 Status
= _SEH_GetExceptionCode();
250 if (!NT_SUCCESS(Status
))
257 LpcRequestMessageSize
= UnsafeLpcRequest
->u1
.s1
.TotalLength
;
260 DPRINT("NtRequestWaitReplyPort(PortHandle %x, LpcRequest %x, "
261 "LpcReply %x)\n", PortHandle
, UnsafeLpcRequest
, UnsafeLpcReply
);
263 Status
= ObReferenceObjectByHandle(PortHandle
,
269 if (!NT_SUCCESS(Status
))
274 if (EPORT_DISCONNECTED
== Port
->State
)
276 ObDereferenceObject(Port
);
277 return STATUS_PORT_DISCONNECTED
;
280 /* win32k sometimes needs to KeAttach() the CSRSS process in order to make
281 the PortHandle valid. Now that we've got the EPORT structure from the
282 handle we can undo this, so everything is normal again. Need to
283 re-KeAttach() before returning though */
284 CurrentThread
= PsGetCurrentThread();
285 if (&CurrentThread
->ThreadsProcess
->Pcb
== CurrentThread
->Tcb
.ApcState
.Process
)
287 AttachedProcess
= NULL
;
291 AttachedProcess
= CurrentThread
->Tcb
.ApcState
.Process
;
295 if (LpcRequestMessageSize
> LPC_MAX_MESSAGE_LENGTH
)
297 if (NULL
!= AttachedProcess
)
299 KeAttachProcess(AttachedProcess
);
301 ObDereferenceObject(Port
);
302 return(STATUS_PORT_MESSAGE_TOO_LONG
);
304 LpcRequest
= ExAllocatePool(NonPagedPool
, LpcRequestMessageSize
);
305 if (LpcRequest
== NULL
)
307 if (NULL
!= AttachedProcess
)
309 KeAttachProcess(AttachedProcess
);
311 ObDereferenceObject(Port
);
312 return(STATUS_NO_MEMORY
);
314 if (PreviousMode
!= KernelMode
)
318 RtlCopyMemory(LpcRequest
,
320 LpcRequestMessageSize
);
321 LpcRequestMessageSize
= LpcRequest
->u1
.s1
.TotalLength
;
322 LpcRequestDataSize
= LpcRequest
->u1
.s1
.DataLength
;
326 Status
= _SEH_GetExceptionCode();
330 if (!NT_SUCCESS(Status
))
332 ExFreePool(LpcRequest
);
333 if (NULL
!= AttachedProcess
)
335 KeAttachProcess(AttachedProcess
);
337 ObDereferenceObject(Port
);
343 RtlCopyMemory(LpcRequest
,
345 LpcRequestMessageSize
);
346 LpcRequestMessageSize
= LpcRequest
->u1
.s1
.TotalLength
;
347 LpcRequestDataSize
= LpcRequest
->u1
.s1
.DataLength
;
350 if (LpcRequestMessageSize
> LPC_MAX_MESSAGE_LENGTH
)
352 ExFreePool(LpcRequest
);
353 if (NULL
!= AttachedProcess
)
355 KeAttachProcess(AttachedProcess
);
357 ObDereferenceObject(Port
);
358 return(STATUS_PORT_MESSAGE_TOO_LONG
);
360 if (LpcRequestDataSize
> LPC_MAX_DATA_LENGTH
)
362 ExFreePool(LpcRequest
);
363 if (NULL
!= AttachedProcess
)
365 KeAttachProcess(AttachedProcess
);
367 ObDereferenceObject(Port
);
368 return(STATUS_PORT_MESSAGE_TOO_LONG
);
371 Status
= EiReplyOrRequestPort(Port
->OtherPort
,
375 if (!NT_SUCCESS(Status
))
377 DPRINT1("Enqueue failed\n");
378 ExFreePool(LpcRequest
);
379 if (NULL
!= AttachedProcess
)
381 KeAttachProcess(AttachedProcess
);
383 ObDereferenceObject(Port
);
386 ExFreePool(LpcRequest
);
387 KeReleaseSemaphore (&Port
->OtherPort
->Semaphore
, IO_NO_INCREMENT
,
393 Status
= KeWaitForSingleObject(&Port
->Semaphore
,
398 if (Status
== STATUS_SUCCESS
)
404 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
405 Message
= EiDequeueMessagePort(Port
);
406 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
409 DPRINT("Message->Message.u1.s1.TotalLength %d\n",
410 Message
->Message
.u1
.s1
.TotalLength
);
411 if (PreviousMode
!= KernelMode
)
415 RtlCopyMemory(UnsafeLpcReply
,
417 Message
->Message
.u1
.s1
.TotalLength
);
421 Status
= _SEH_GetExceptionCode();
427 RtlCopyMemory(UnsafeLpcReply
,
429 Message
->Message
.u1
.s1
.TotalLength
);
434 Status
= STATUS_UNSUCCESSFUL
;
438 if (NT_SUCCESS(Status
))
440 Status
= STATUS_UNSUCCESSFUL
;
443 if (NULL
!= AttachedProcess
)
445 KeAttachProcess(AttachedProcess
);
447 ObDereferenceObject(Port
);
453 /**********************************************************************
455 * NtWriteRequestData/6
465 NTSTATUS STDCALL
NtWriteRequestData (HANDLE PortHandle
,
466 PPORT_MESSAGE Message
,
473 return(STATUS_NOT_IMPLEMENTED
);