88da73ababa4281928597facde786a93c4f29f79
[reactos.git] / reactos / ntoskrnl / lpc / send.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/lpc/send.c
6 * PURPOSE: Communication mechanism
7 *
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14
15 #define NDEBUG
16 #include <internal/debug.h>
17
18
19 /**********************************************************************
20 * NAME
21 * LpcSendTerminationPort/2
22 *
23 * DESCRIPTION
24 *
25 * ARGUMENTS
26 *
27 * RETURN VALUE
28 *
29 * REVISIONS
30 */
31 NTSTATUS STDCALL
32 LpcSendTerminationPort (IN PEPORT Port,
33 IN LARGE_INTEGER CreationTime)
34 {
35 NTSTATUS Status;
36 LPC_TERMINATION_MESSAGE Msg;
37
38 #ifdef __USE_NT_LPC__
39 Msg.Header.u2.s2.Type = LPC_NEW_MESSAGE;
40 #endif
41 Msg.CreationTime = CreationTime;
42 Status = LpcRequestPort (Port, &Msg.Header);
43 return(Status);
44 }
45
46
47 /**********************************************************************
48 * NAME
49 * LpcSendDebugMessagePort/3
50 *
51 * DESCRIPTION
52 *
53 * ARGUMENTS
54 *
55 * RETURN VALUE
56 *
57 * REVISIONS
58 */
59 NTSTATUS STDCALL
60 LpcSendDebugMessagePort (IN PEPORT Port,
61 IN PLPC_DBG_MESSAGE Message,
62 OUT PLPC_DBG_MESSAGE Reply)
63 {
64 NTSTATUS Status;
65 KIRQL oldIrql;
66 PQUEUEDMESSAGE ReplyMessage;
67
68 Status = EiReplyOrRequestPort(Port,
69 &Message->Header,
70 LPC_REQUEST,
71 Port);
72 if (!NT_SUCCESS(Status))
73 {
74 ObDereferenceObject(Port);
75 return(Status);
76 }
77 KeReleaseSemaphore(&Port->OtherPort->Semaphore, IO_NO_INCREMENT, 1, FALSE);
78
79 /*
80 * Wait for a reply
81 */
82 KeWaitForSingleObject(&Port->Semaphore,
83 UserRequest,
84 UserMode,
85 FALSE,
86 NULL);
87
88 /*
89 * Dequeue the reply
90 */
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);
96
97 return(STATUS_SUCCESS);
98 }
99
100
101 /**********************************************************************
102 * NAME
103 * LpcRequestPort/2
104 *
105 * DESCRIPTION
106 *
107 * ARGUMENTS
108 *
109 * RETURN VALUE
110 *
111 * REVISIONS
112 * 2002-03-01 EA
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.
117 *
118 * @implemented
119 */
120 NTSTATUS STDCALL LpcRequestPort (IN PEPORT Port,
121 IN PPORT_MESSAGE LpcMessage)
122 {
123 NTSTATUS Status;
124
125 DPRINT("LpcRequestPort(PortHandle %08x, LpcMessage %08x)\n", Port, LpcMessage);
126
127 #ifdef __USE_NT_LPC__
128 /* Check the message's type */
129 if (LPC_NEW_MESSAGE == LpcMessage->u2.s2.Type)
130 {
131 LpcMessage->u2.s2.Type = LPC_DATAGRAM;
132 }
133 else if (LPC_DATAGRAM == LpcMessage->u2.s2.Type)
134 {
135 return STATUS_INVALID_PARAMETER;
136 }
137 else if (LpcMessage->u2.s2.Type > LPC_CLIENT_DIED)
138 {
139 return STATUS_INVALID_PARAMETER;
140 }
141 /* Check the range offset */
142 if (0 != LpcMessage->VirtualRangesOffset)
143 {
144 return STATUS_INVALID_PARAMETER;
145 }
146 #endif
147
148 Status = EiReplyOrRequestPort(Port,
149 LpcMessage,
150 LPC_DATAGRAM,
151 Port);
152 KeReleaseSemaphore( &Port->Semaphore, IO_NO_INCREMENT, 1, FALSE );
153
154 return(Status);
155 }
156
157
158 /**********************************************************************
159 * NAME
160 * NtRequestPort/2
161 *
162 * DESCRIPTION
163 *
164 * ARGUMENTS
165 *
166 * RETURN VALUE
167 *
168 * REVISIONS
169 *
170 * @implemented
171 */
172 NTSTATUS STDCALL NtRequestPort (IN HANDLE PortHandle,
173 IN PPORT_MESSAGE LpcMessage)
174 {
175 NTSTATUS Status;
176 PEPORT Port;
177
178 DPRINT("NtRequestPort(PortHandle %x LpcMessage %x)\n", PortHandle,
179 LpcMessage);
180
181 Status = ObReferenceObjectByHandle(PortHandle,
182 PORT_ALL_ACCESS,
183 LpcPortObjectType,
184 UserMode,
185 (PVOID*)&Port,
186 NULL);
187 if (!NT_SUCCESS(Status))
188 {
189 DPRINT("NtRequestPort() = %x\n", Status);
190 return(Status);
191 }
192
193 Status = LpcRequestPort(Port->OtherPort,
194 LpcMessage);
195
196 ObDereferenceObject(Port);
197 return(Status);
198 }
199
200
201 /**********************************************************************
202 * NAME
203 * NtRequestWaitReplyPort/3
204 *
205 * DESCRIPTION
206 *
207 * ARGUMENTS
208 *
209 * RETURN VALUE
210 *
211 * REVISIONS
212 *
213 * @implemented
214 */
215 NTSTATUS STDCALL
216 NtRequestWaitReplyPort (IN HANDLE PortHandle,
217 PPORT_MESSAGE UnsafeLpcRequest,
218 PPORT_MESSAGE UnsafeLpcReply)
219 {
220 PETHREAD CurrentThread;
221 struct _KPROCESS *AttachedProcess;
222 PEPORT Port;
223 PQUEUEDMESSAGE Message;
224 KIRQL oldIrql;
225 PPORT_MESSAGE LpcRequest;
226 USHORT LpcRequestMessageSize = 0, LpcRequestDataSize = 0;
227 KPROCESSOR_MODE PreviousMode;
228 NTSTATUS Status = STATUS_SUCCESS;
229
230 PreviousMode = ExGetPreviousMode();
231
232 if (PreviousMode != KernelMode)
233 {
234 _SEH_TRY
235 {
236 ProbeForRead(UnsafeLpcRequest,
237 sizeof(PORT_MESSAGE),
238 1);
239 ProbeForWrite(UnsafeLpcReply,
240 sizeof(PORT_MESSAGE),
241 1);
242 LpcRequestMessageSize = UnsafeLpcRequest->u1.s1.TotalLength;
243 }
244 _SEH_HANDLE
245 {
246 Status = _SEH_GetExceptionCode();
247 }
248 _SEH_END;
249
250 if (!NT_SUCCESS(Status))
251 {
252 return Status;
253 }
254 }
255 else
256 {
257 LpcRequestMessageSize = UnsafeLpcRequest->u1.s1.TotalLength;
258 }
259
260 DPRINT("NtRequestWaitReplyPort(PortHandle %x, LpcRequest %x, "
261 "LpcReply %x)\n", PortHandle, UnsafeLpcRequest, UnsafeLpcReply);
262
263 Status = ObReferenceObjectByHandle(PortHandle,
264 PORT_ALL_ACCESS,
265 LpcPortObjectType,
266 UserMode,
267 (PVOID*)&Port,
268 NULL);
269 if (!NT_SUCCESS(Status))
270 {
271 return(Status);
272 }
273
274 if (EPORT_DISCONNECTED == Port->State)
275 {
276 ObDereferenceObject(Port);
277 return STATUS_PORT_DISCONNECTED;
278 }
279
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)
286 {
287 AttachedProcess = NULL;
288 }
289 else
290 {
291 AttachedProcess = CurrentThread->Tcb.ApcState.Process;
292 KeDetachProcess();
293 }
294
295 if (LpcRequestMessageSize > LPC_MAX_MESSAGE_LENGTH)
296 {
297 if (NULL != AttachedProcess)
298 {
299 KeAttachProcess(AttachedProcess);
300 }
301 ObDereferenceObject(Port);
302 return(STATUS_PORT_MESSAGE_TOO_LONG);
303 }
304 LpcRequest = ExAllocatePool(NonPagedPool, LpcRequestMessageSize);
305 if (LpcRequest == NULL)
306 {
307 if (NULL != AttachedProcess)
308 {
309 KeAttachProcess(AttachedProcess);
310 }
311 ObDereferenceObject(Port);
312 return(STATUS_NO_MEMORY);
313 }
314 if (PreviousMode != KernelMode)
315 {
316 _SEH_TRY
317 {
318 RtlCopyMemory(LpcRequest,
319 UnsafeLpcRequest,
320 LpcRequestMessageSize);
321 LpcRequestMessageSize = LpcRequest->u1.s1.TotalLength;
322 LpcRequestDataSize = LpcRequest->u1.s1.DataLength;
323 }
324 _SEH_HANDLE
325 {
326 Status = _SEH_GetExceptionCode();
327 }
328 _SEH_END;
329
330 if (!NT_SUCCESS(Status))
331 {
332 ExFreePool(LpcRequest);
333 if (NULL != AttachedProcess)
334 {
335 KeAttachProcess(AttachedProcess);
336 }
337 ObDereferenceObject(Port);
338 return(Status);
339 }
340 }
341 else
342 {
343 RtlCopyMemory(LpcRequest,
344 UnsafeLpcRequest,
345 LpcRequestMessageSize);
346 LpcRequestMessageSize = LpcRequest->u1.s1.TotalLength;
347 LpcRequestDataSize = LpcRequest->u1.s1.DataLength;
348 }
349
350 if (LpcRequestMessageSize > LPC_MAX_MESSAGE_LENGTH)
351 {
352 ExFreePool(LpcRequest);
353 if (NULL != AttachedProcess)
354 {
355 KeAttachProcess(AttachedProcess);
356 }
357 ObDereferenceObject(Port);
358 return(STATUS_PORT_MESSAGE_TOO_LONG);
359 }
360 if (LpcRequestDataSize > LPC_MAX_DATA_LENGTH)
361 {
362 ExFreePool(LpcRequest);
363 if (NULL != AttachedProcess)
364 {
365 KeAttachProcess(AttachedProcess);
366 }
367 ObDereferenceObject(Port);
368 return(STATUS_PORT_MESSAGE_TOO_LONG);
369 }
370
371 Status = EiReplyOrRequestPort(Port->OtherPort,
372 LpcRequest,
373 LPC_REQUEST,
374 Port);
375 if (!NT_SUCCESS(Status))
376 {
377 DPRINT1("Enqueue failed\n");
378 ExFreePool(LpcRequest);
379 if (NULL != AttachedProcess)
380 {
381 KeAttachProcess(AttachedProcess);
382 }
383 ObDereferenceObject(Port);
384 return(Status);
385 }
386 ExFreePool(LpcRequest);
387 KeReleaseSemaphore (&Port->OtherPort->Semaphore, IO_NO_INCREMENT,
388 1, FALSE);
389
390 /*
391 * Wait for a reply
392 */
393 Status = KeWaitForSingleObject(&Port->Semaphore,
394 UserRequest,
395 UserMode,
396 FALSE,
397 NULL);
398 if (Status == STATUS_SUCCESS)
399 {
400
401 /*
402 * Dequeue the reply
403 */
404 KeAcquireSpinLock(&Port->Lock, &oldIrql);
405 Message = EiDequeueMessagePort(Port);
406 KeReleaseSpinLock(&Port->Lock, oldIrql);
407 if (Message)
408 {
409 DPRINT("Message->Message.u1.s1.TotalLength %d\n",
410 Message->Message.u1.s1.TotalLength);
411 if (PreviousMode != KernelMode)
412 {
413 _SEH_TRY
414 {
415 RtlCopyMemory(UnsafeLpcReply,
416 &Message->Message,
417 Message->Message.u1.s1.TotalLength);
418 }
419 _SEH_HANDLE
420 {
421 Status = _SEH_GetExceptionCode();
422 }
423 _SEH_END;
424 }
425 else
426 {
427 RtlCopyMemory(UnsafeLpcReply,
428 &Message->Message,
429 Message->Message.u1.s1.TotalLength);
430 }
431 ExFreePool(Message);
432 }
433 else
434 Status = STATUS_UNSUCCESSFUL;
435 }
436 else
437 {
438 if (NT_SUCCESS(Status))
439 {
440 Status = STATUS_UNSUCCESSFUL;
441 }
442 }
443 if (NULL != AttachedProcess)
444 {
445 KeAttachProcess(AttachedProcess);
446 }
447 ObDereferenceObject(Port);
448
449 return(Status);
450 }
451
452
453 /**********************************************************************
454 * NAME
455 * NtWriteRequestData/6
456 *
457 * DESCRIPTION
458 *
459 * ARGUMENTS
460 *
461 * RETURN VALUE
462 *
463 * REVISIONS
464 */
465 NTSTATUS STDCALL NtWriteRequestData (HANDLE PortHandle,
466 PPORT_MESSAGE Message,
467 ULONG Index,
468 PVOID Buffer,
469 ULONG BufferLength,
470 PULONG ReturnLength)
471 {
472 UNIMPLEMENTED;
473 return(STATUS_NOT_IMPLEMENTED);
474 }
475
476
477 /* EOF */