- Removed the member OldProcess from the ETHREAD structure.
[reactos.git] / reactos / ntoskrnl / lpc / send.c
1 /* $Id: send.c,v 1.17 2004/08/31 20:17:18 hbirr Exp $
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 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * UPDATE HISTORY:
9 * Created 22/05/98
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
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 TIME CreationTime)
34 {
35 NTSTATUS Status;
36 LPC_TERMINATION_MESSAGE Msg;
37
38 #ifdef __USE_NT_LPC__
39 Msg.Header.MessageType = 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.MessageSize);
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 PLPC_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->MessageType)
130 {
131 LpcMessage->MessageType = LPC_DATAGRAM;
132 }
133 else if (LPC_DATAGRAM == LpcMessage->MessageType)
134 {
135 return STATUS_INVALID_PARAMETER;
136 }
137 else if (LpcMessage->MessageType > 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 PLPC_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 ExPortType,
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 PLPC_MESSAGE UnsafeLpcRequest,
218 PLPC_MESSAGE UnsafeLpcReply)
219 {
220 PETHREAD CurrentThread;
221 struct _EPROCESS *AttachedProcess;
222 NTSTATUS Status;
223 PEPORT Port;
224 PQUEUEDMESSAGE Message;
225 KIRQL oldIrql;
226 PLPC_MESSAGE LpcRequest;
227 USHORT LpcRequestMessageSize;
228
229 DPRINT("NtRequestWaitReplyPort(PortHandle %x, LpcRequest %x, "
230 "LpcReply %x)\n", PortHandle, UnsafeLpcRequest, UnsafeLpcReply);
231
232 Status = ObReferenceObjectByHandle(PortHandle,
233 PORT_ALL_ACCESS,
234 ExPortType,
235 UserMode,
236 (PVOID*)&Port,
237 NULL);
238 if (!NT_SUCCESS(Status))
239 {
240 return(Status);
241 }
242
243 /* win32k sometimes needs to KeAttach() the CSRSS process in order to make
244 the PortHandle valid. Now that we've got the EPORT structure from the
245 handle we can undo this, so everything is normal again. Need to
246 re-KeAttach() before returning though */
247 CurrentThread = PsGetCurrentThread();
248 if (&CurrentThread->ThreadsProcess->Pcb == CurrentThread->Tcb.ApcState.Process)
249 {
250 AttachedProcess = NULL;
251 }
252 else
253 {
254 AttachedProcess = (PEPROCESS)CurrentThread->Tcb.ApcState.Process;
255 KeDetachProcess();
256 }
257
258 Status = MmCopyFromCaller(&LpcRequestMessageSize,
259 &UnsafeLpcRequest->MessageSize,
260 sizeof(USHORT));
261 if (!NT_SUCCESS(Status))
262 {
263 if (NULL != AttachedProcess)
264 {
265 KeAttachProcess(AttachedProcess);
266 }
267 ObDereferenceObject(Port);
268 return(Status);
269 }
270 if (LpcRequestMessageSize > (sizeof(LPC_MESSAGE) + MAX_MESSAGE_DATA))
271 {
272 if (NULL != AttachedProcess)
273 {
274 KeAttachProcess(AttachedProcess);
275 }
276 ObDereferenceObject(Port);
277 return(STATUS_PORT_MESSAGE_TOO_LONG);
278 }
279 LpcRequest = ExAllocatePool(NonPagedPool, LpcRequestMessageSize);
280 if (LpcRequest == NULL)
281 {
282 if (NULL != AttachedProcess)
283 {
284 KeAttachProcess(AttachedProcess);
285 }
286 ObDereferenceObject(Port);
287 return(STATUS_NO_MEMORY);
288 }
289 Status = MmCopyFromCaller(LpcRequest, UnsafeLpcRequest,
290 LpcRequestMessageSize);
291 if (!NT_SUCCESS(Status))
292 {
293 ExFreePool(LpcRequest);
294 if (NULL != AttachedProcess)
295 {
296 KeAttachProcess(AttachedProcess);
297 }
298 ObDereferenceObject(Port);
299 return(Status);
300 }
301 LpcRequestMessageSize = LpcRequest->MessageSize;
302 if (LpcRequestMessageSize > (sizeof(LPC_MESSAGE) + MAX_MESSAGE_DATA))
303 {
304 ExFreePool(LpcRequest);
305 if (NULL != AttachedProcess)
306 {
307 KeAttachProcess(AttachedProcess);
308 }
309 ObDereferenceObject(Port);
310 return(STATUS_PORT_MESSAGE_TOO_LONG);
311 }
312 if (LpcRequest->DataSize != (LpcRequest->MessageSize - sizeof(LPC_MESSAGE)))
313 {
314 ExFreePool(LpcRequest);
315 if (NULL != AttachedProcess)
316 {
317 KeAttachProcess(AttachedProcess);
318 }
319 ObDereferenceObject(Port);
320 return(STATUS_PORT_MESSAGE_TOO_LONG);
321 }
322
323 Status = EiReplyOrRequestPort(Port->OtherPort,
324 LpcRequest,
325 LPC_REQUEST,
326 Port);
327 if (!NT_SUCCESS(Status))
328 {
329 DPRINT1("Enqueue failed\n");
330 ExFreePool(LpcRequest);
331 if (NULL != AttachedProcess)
332 {
333 KeAttachProcess(AttachedProcess);
334 }
335 ObDereferenceObject(Port);
336 return(Status);
337 }
338 ExFreePool(LpcRequest);
339 KeReleaseSemaphore (&Port->OtherPort->Semaphore, IO_NO_INCREMENT,
340 1, FALSE);
341
342 /*
343 * Wait for a reply
344 */
345 Status = KeWaitForSingleObject(&Port->Semaphore,
346 UserRequest,
347 UserMode,
348 FALSE,
349 NULL);
350 if (Status == STATUS_SUCCESS)
351 {
352
353 /*
354 * Dequeue the reply
355 */
356 KeAcquireSpinLock(&Port->Lock, &oldIrql);
357 Message = EiDequeueMessagePort(Port);
358 KeReleaseSpinLock(&Port->Lock, oldIrql);
359 if (Message)
360 {
361 DPRINT("Message->Message.MessageSize %d\n",
362 Message->Message.MessageSize);
363 Status = MmCopyToCaller(UnsafeLpcReply, &Message->Message,
364 Message->Message.MessageSize);
365 ExFreePool(Message);
366 }
367 else
368 Status = STATUS_UNSUCCESSFUL;
369 }
370 else
371 {
372 if (NT_SUCCESS(Status))
373 {
374 Status = STATUS_UNSUCCESSFUL;
375 }
376 }
377 if (NULL != AttachedProcess)
378 {
379 KeAttachProcess(AttachedProcess);
380 }
381 ObDereferenceObject(Port);
382
383 return(Status);
384 }
385
386
387 /**********************************************************************
388 * NAME
389 * NtWriteRequestData/6
390 *
391 * DESCRIPTION
392 *
393 * ARGUMENTS
394 *
395 * RETURN VALUE
396 *
397 * REVISIONS
398 */
399 NTSTATUS STDCALL NtWriteRequestData (HANDLE PortHandle,
400 PLPC_MESSAGE Message,
401 ULONG Index,
402 PVOID Buffer,
403 ULONG BufferLength,
404 PULONG ReturnLength)
405 {
406 UNIMPLEMENTED;
407 return(STATUS_NOT_IMPLEMENTED);
408 }
409
410
411 /* EOF */