- Implement the rest of Hard Error support.
[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 * NAME
20 * LpcRequestPort/2
21 *
22 * DESCRIPTION
23 *
24 * ARGUMENTS
25 *
26 * RETURN VALUE
27 *
28 * REVISIONS
29 * 2002-03-01 EA
30 * I investigated this function a bit more in depth.
31 * It looks like the legal values for the MessageType field in the
32 * message to send are in the range LPC_NEW_MESSAGE .. LPC_CLIENT_DIED,
33 * but LPC_DATAGRAM is explicitly forbidden.
34 *
35 * @implemented
36 */
37 NTSTATUS STDCALL LpcRequestPort (IN PVOID PortObject,
38 IN PPORT_MESSAGE LpcMessage)
39 {
40 NTSTATUS Status;
41 PEPORT Port = (PEPORT)PortObject;
42
43 DPRINT("LpcRequestPort(PortHandle %08x, LpcMessage %08x)\n", Port, LpcMessage);
44
45 #ifdef __USE_NT_LPC__
46 /* Check the message's type */
47 if (LPC_NEW_MESSAGE == LpcMessage->u2.s2.Type)
48 {
49 LpcMessage->u2.s2.Type = LPC_DATAGRAM;
50 }
51 else if (LPC_DATAGRAM == LpcMessage->u2.s2.Type)
52 {
53 return STATUS_INVALID_PARAMETER;
54 }
55 else if (LpcMessage->u2.s2.Type > LPC_CLIENT_DIED)
56 {
57 return STATUS_INVALID_PARAMETER;
58 }
59 /* Check the range offset */
60 if (0 != LpcMessage->VirtualRangesOffset)
61 {
62 return STATUS_INVALID_PARAMETER;
63 }
64 #endif
65
66 Status = EiReplyOrRequestPort(Port,
67 LpcMessage,
68 LPC_DATAGRAM,
69 Port);
70 KeReleaseSemaphore( &Port->Semaphore, IO_NO_INCREMENT, 1, FALSE );
71
72 return(Status);
73 }
74
75
76 /**********************************************************************
77 * NAME
78 * NtRequestPort/2
79 *
80 * DESCRIPTION
81 *
82 * ARGUMENTS
83 *
84 * RETURN VALUE
85 *
86 * REVISIONS
87 *
88 * @implemented
89 */
90 NTSTATUS STDCALL NtRequestPort (IN HANDLE PortHandle,
91 IN PPORT_MESSAGE LpcMessage)
92 {
93 NTSTATUS Status;
94 PEPORT Port;
95
96 DPRINT("NtRequestPort(PortHandle %x LpcMessage %x)\n", PortHandle,
97 LpcMessage);
98
99 Status = ObReferenceObjectByHandle(PortHandle,
100 PORT_ALL_ACCESS,
101 LpcPortObjectType,
102 UserMode,
103 (PVOID*)&Port,
104 NULL);
105 if (!NT_SUCCESS(Status))
106 {
107 DPRINT("NtRequestPort() = %x\n", Status);
108 return(Status);
109 }
110
111 Status = LpcRequestPort(Port->OtherPort,
112 LpcMessage);
113
114 ObDereferenceObject(Port);
115 return(Status);
116 }
117
118
119 /**********************************************************************
120 * NAME
121 * NtRequestWaitReplyPort/3
122 *
123 * DESCRIPTION
124 *
125 * ARGUMENTS
126 *
127 * RETURN VALUE
128 *
129 * REVISIONS
130 *
131 * @implemented
132 */
133 NTSTATUS STDCALL
134 NtRequestWaitReplyPort (IN HANDLE PortHandle,
135 PPORT_MESSAGE UnsafeLpcRequest,
136 PPORT_MESSAGE UnsafeLpcReply)
137 {
138 PETHREAD CurrentThread;
139 struct _KPROCESS *AttachedProcess;
140 PEPORT Port;
141 PQUEUEDMESSAGE Message;
142 KIRQL oldIrql;
143 PPORT_MESSAGE LpcRequest;
144 USHORT LpcRequestMessageSize = 0, LpcRequestDataSize = 0;
145 KPROCESSOR_MODE PreviousMode;
146 NTSTATUS Status = STATUS_SUCCESS;
147
148 PreviousMode = ExGetPreviousMode();
149
150 if (PreviousMode != KernelMode)
151 {
152 _SEH_TRY
153 {
154 ProbeForRead(UnsafeLpcRequest,
155 sizeof(PORT_MESSAGE),
156 1);
157 ProbeForWrite(UnsafeLpcReply,
158 sizeof(PORT_MESSAGE),
159 1);
160 LpcRequestMessageSize = UnsafeLpcRequest->u1.s1.TotalLength;
161 }
162 _SEH_HANDLE
163 {
164 Status = _SEH_GetExceptionCode();
165 }
166 _SEH_END;
167
168 if (!NT_SUCCESS(Status))
169 {
170 return Status;
171 }
172 }
173 else
174 {
175 LpcRequestMessageSize = UnsafeLpcRequest->u1.s1.TotalLength;
176 }
177
178 DPRINT("NtRequestWaitReplyPort(PortHandle %x, LpcRequest %x, "
179 "LpcReply %x)\n", PortHandle, UnsafeLpcRequest, UnsafeLpcReply);
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 return(Status);
190 }
191
192 if (EPORT_DISCONNECTED == Port->State)
193 {
194 ObDereferenceObject(Port);
195 return STATUS_PORT_DISCONNECTED;
196 }
197
198 /* win32k sometimes needs to KeAttach() the CSRSS process in order to make
199 the PortHandle valid. Now that we've got the EPORT structure from the
200 handle we can undo this, so everything is normal again. Need to
201 re-KeAttach() before returning though */
202 CurrentThread = PsGetCurrentThread();
203 if (&CurrentThread->ThreadsProcess->Pcb == CurrentThread->Tcb.ApcState.Process)
204 {
205 AttachedProcess = NULL;
206 }
207 else
208 {
209 AttachedProcess = CurrentThread->Tcb.ApcState.Process;
210 KeDetachProcess();
211 }
212
213 if (LpcRequestMessageSize > LPC_MAX_MESSAGE_LENGTH)
214 {
215 if (NULL != AttachedProcess)
216 {
217 KeAttachProcess(AttachedProcess);
218 }
219 ObDereferenceObject(Port);
220 return(STATUS_PORT_MESSAGE_TOO_LONG);
221 }
222 LpcRequest = ExAllocatePool(NonPagedPool, LpcRequestMessageSize);
223 if (LpcRequest == NULL)
224 {
225 if (NULL != AttachedProcess)
226 {
227 KeAttachProcess(AttachedProcess);
228 }
229 ObDereferenceObject(Port);
230 return(STATUS_NO_MEMORY);
231 }
232 if (PreviousMode != KernelMode)
233 {
234 _SEH_TRY
235 {
236 RtlCopyMemory(LpcRequest,
237 UnsafeLpcRequest,
238 LpcRequestMessageSize);
239 LpcRequestMessageSize = LpcRequest->u1.s1.TotalLength;
240 LpcRequestDataSize = LpcRequest->u1.s1.DataLength;
241 }
242 _SEH_HANDLE
243 {
244 Status = _SEH_GetExceptionCode();
245 }
246 _SEH_END;
247
248 if (!NT_SUCCESS(Status))
249 {
250 ExFreePool(LpcRequest);
251 if (NULL != AttachedProcess)
252 {
253 KeAttachProcess(AttachedProcess);
254 }
255 ObDereferenceObject(Port);
256 return(Status);
257 }
258 }
259 else
260 {
261 RtlCopyMemory(LpcRequest,
262 UnsafeLpcRequest,
263 LpcRequestMessageSize);
264 LpcRequestMessageSize = LpcRequest->u1.s1.TotalLength;
265 LpcRequestDataSize = LpcRequest->u1.s1.DataLength;
266 }
267
268 if (LpcRequestMessageSize > LPC_MAX_MESSAGE_LENGTH)
269 {
270 ExFreePool(LpcRequest);
271 if (NULL != AttachedProcess)
272 {
273 KeAttachProcess(AttachedProcess);
274 }
275 ObDereferenceObject(Port);
276 return(STATUS_PORT_MESSAGE_TOO_LONG);
277 }
278 if (LpcRequestDataSize > LPC_MAX_DATA_LENGTH)
279 {
280 ExFreePool(LpcRequest);
281 if (NULL != AttachedProcess)
282 {
283 KeAttachProcess(AttachedProcess);
284 }
285 ObDereferenceObject(Port);
286 return(STATUS_PORT_MESSAGE_TOO_LONG);
287 }
288
289 Status = EiReplyOrRequestPort(Port->OtherPort,
290 LpcRequest,
291 LpcRequest->u2.s2.Type == LPC_ERROR_EVENT ? LPC_ERROR_EVENT : LPC_REQUEST,
292 Port);
293 if (!NT_SUCCESS(Status))
294 {
295 DPRINT1("Enqueue failed\n");
296 ExFreePool(LpcRequest);
297 if (NULL != AttachedProcess)
298 {
299 KeAttachProcess(AttachedProcess);
300 }
301 ObDereferenceObject(Port);
302 return(Status);
303 }
304 ExFreePool(LpcRequest);
305 KeReleaseSemaphore (&Port->OtherPort->Semaphore, IO_NO_INCREMENT,
306 1, FALSE);
307
308 /*
309 * Wait for a reply
310 */
311 Status = KeWaitForSingleObject(&Port->Semaphore,
312 UserRequest,
313 UserMode,
314 FALSE,
315 NULL);
316 if (Status == STATUS_SUCCESS)
317 {
318
319 /*
320 * Dequeue the reply
321 */
322 KeAcquireSpinLock(&Port->Lock, &oldIrql);
323 Message = EiDequeueMessagePort(Port);
324 KeReleaseSpinLock(&Port->Lock, oldIrql);
325 if (Message)
326 {
327 DPRINT("Message->Message.u1.s1.TotalLength %d\n",
328 Message->Message.u1.s1.TotalLength);
329 if (PreviousMode != KernelMode)
330 {
331 _SEH_TRY
332 {
333 RtlCopyMemory(UnsafeLpcReply,
334 &Message->Message,
335 Message->Message.u1.s1.TotalLength);
336 }
337 _SEH_HANDLE
338 {
339 Status = _SEH_GetExceptionCode();
340 }
341 _SEH_END;
342 }
343 else
344 {
345 RtlCopyMemory(UnsafeLpcReply,
346 &Message->Message,
347 Message->Message.u1.s1.TotalLength);
348 }
349 ExFreePool(Message);
350 }
351 else
352 Status = STATUS_UNSUCCESSFUL;
353 }
354 else
355 {
356 if (NT_SUCCESS(Status))
357 {
358 Status = STATUS_UNSUCCESSFUL;
359 }
360 }
361 if (NULL != AttachedProcess)
362 {
363 KeAttachProcess(AttachedProcess);
364 }
365 ObDereferenceObject(Port);
366
367 return(Status);
368 }
369
370
371 /**********************************************************************
372 * NAME
373 * NtWriteRequestData/6
374 *
375 * DESCRIPTION
376 *
377 * ARGUMENTS
378 *
379 * RETURN VALUE
380 *
381 * REVISIONS
382 */
383 NTSTATUS STDCALL NtWriteRequestData (HANDLE PortHandle,
384 PPORT_MESSAGE Message,
385 ULONG Index,
386 PVOID Buffer,
387 ULONG BufferLength,
388 PULONG ReturnLength)
389 {
390 UNIMPLEMENTED;
391 return(STATUS_NOT_IMPLEMENTED);
392 }
393
394
395 /* EOF */