Fix incorrect LPC Object export...we export pointers not the object itself! Also...
[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 * 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 LARGE_INTEGER 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 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 PLPC_MESSAGE UnsafeLpcRequest,
218 PLPC_MESSAGE UnsafeLpcReply)
219 {
220 PETHREAD CurrentThread;
221 struct _KPROCESS *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 LpcPortObjectType,
235 UserMode,
236 (PVOID*)&Port,
237 NULL);
238 if (!NT_SUCCESS(Status))
239 {
240 return(Status);
241 }
242
243 if (EPORT_DISCONNECTED == Port->State)
244 {
245 ObDereferenceObject(Port);
246 return STATUS_PORT_DISCONNECTED;
247 }
248
249 /* win32k sometimes needs to KeAttach() the CSRSS process in order to make
250 the PortHandle valid. Now that we've got the EPORT structure from the
251 handle we can undo this, so everything is normal again. Need to
252 re-KeAttach() before returning though */
253 CurrentThread = PsGetCurrentThread();
254 if (&CurrentThread->ThreadsProcess->Pcb == CurrentThread->Tcb.ApcState.Process)
255 {
256 AttachedProcess = NULL;
257 }
258 else
259 {
260 AttachedProcess = CurrentThread->Tcb.ApcState.Process;
261 KeDetachProcess();
262 }
263
264 Status = MmCopyFromCaller(&LpcRequestMessageSize,
265 &UnsafeLpcRequest->MessageSize,
266 sizeof(USHORT));
267 if (!NT_SUCCESS(Status))
268 {
269 if (NULL != AttachedProcess)
270 {
271 KeAttachProcess(AttachedProcess);
272 }
273 ObDereferenceObject(Port);
274 return(Status);
275 }
276 if (LpcRequestMessageSize > (sizeof(LPC_MESSAGE) + MAX_MESSAGE_DATA))
277 {
278 if (NULL != AttachedProcess)
279 {
280 KeAttachProcess(AttachedProcess);
281 }
282 ObDereferenceObject(Port);
283 return(STATUS_PORT_MESSAGE_TOO_LONG);
284 }
285 LpcRequest = ExAllocatePool(NonPagedPool, LpcRequestMessageSize);
286 if (LpcRequest == NULL)
287 {
288 if (NULL != AttachedProcess)
289 {
290 KeAttachProcess(AttachedProcess);
291 }
292 ObDereferenceObject(Port);
293 return(STATUS_NO_MEMORY);
294 }
295 Status = MmCopyFromCaller(LpcRequest, UnsafeLpcRequest,
296 LpcRequestMessageSize);
297 if (!NT_SUCCESS(Status))
298 {
299 ExFreePool(LpcRequest);
300 if (NULL != AttachedProcess)
301 {
302 KeAttachProcess(AttachedProcess);
303 }
304 ObDereferenceObject(Port);
305 return(Status);
306 }
307 LpcRequestMessageSize = LpcRequest->MessageSize;
308 if (LpcRequestMessageSize > (sizeof(LPC_MESSAGE) + MAX_MESSAGE_DATA))
309 {
310 ExFreePool(LpcRequest);
311 if (NULL != AttachedProcess)
312 {
313 KeAttachProcess(AttachedProcess);
314 }
315 ObDereferenceObject(Port);
316 return(STATUS_PORT_MESSAGE_TOO_LONG);
317 }
318 if (LpcRequest->DataSize != (LpcRequest->MessageSize - sizeof(LPC_MESSAGE)))
319 {
320 ExFreePool(LpcRequest);
321 if (NULL != AttachedProcess)
322 {
323 KeAttachProcess(AttachedProcess);
324 }
325 ObDereferenceObject(Port);
326 return(STATUS_PORT_MESSAGE_TOO_LONG);
327 }
328
329 Status = EiReplyOrRequestPort(Port->OtherPort,
330 LpcRequest,
331 LPC_REQUEST,
332 Port);
333 if (!NT_SUCCESS(Status))
334 {
335 DPRINT1("Enqueue failed\n");
336 ExFreePool(LpcRequest);
337 if (NULL != AttachedProcess)
338 {
339 KeAttachProcess(AttachedProcess);
340 }
341 ObDereferenceObject(Port);
342 return(Status);
343 }
344 ExFreePool(LpcRequest);
345 KeReleaseSemaphore (&Port->OtherPort->Semaphore, IO_NO_INCREMENT,
346 1, FALSE);
347
348 /*
349 * Wait for a reply
350 */
351 Status = KeWaitForSingleObject(&Port->Semaphore,
352 UserRequest,
353 UserMode,
354 FALSE,
355 NULL);
356 if (Status == STATUS_SUCCESS)
357 {
358
359 /*
360 * Dequeue the reply
361 */
362 KeAcquireSpinLock(&Port->Lock, &oldIrql);
363 Message = EiDequeueMessagePort(Port);
364 KeReleaseSpinLock(&Port->Lock, oldIrql);
365 if (Message)
366 {
367 DPRINT("Message->Message.MessageSize %d\n",
368 Message->Message.MessageSize);
369 Status = MmCopyToCaller(UnsafeLpcReply, &Message->Message,
370 Message->Message.MessageSize);
371 ExFreePool(Message);
372 }
373 else
374 Status = STATUS_UNSUCCESSFUL;
375 }
376 else
377 {
378 if (NT_SUCCESS(Status))
379 {
380 Status = STATUS_UNSUCCESSFUL;
381 }
382 }
383 if (NULL != AttachedProcess)
384 {
385 KeAttachProcess(AttachedProcess);
386 }
387 ObDereferenceObject(Port);
388
389 return(Status);
390 }
391
392
393 /**********************************************************************
394 * NAME
395 * NtWriteRequestData/6
396 *
397 * DESCRIPTION
398 *
399 * ARGUMENTS
400 *
401 * RETURN VALUE
402 *
403 * REVISIONS
404 */
405 NTSTATUS STDCALL NtWriteRequestData (HANDLE PortHandle,
406 PLPC_MESSAGE Message,
407 ULONG Index,
408 PVOID Buffer,
409 ULONG BufferLength,
410 PULONG ReturnLength)
411 {
412 UNIMPLEMENTED;
413 return(STATUS_NOT_IMPLEMENTED);
414 }
415
416
417 /* EOF */