3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/lpc/connect.c
6 * PURPOSE: Communication mechanism
7 * PROGRAMMER: David Welch (welch@cwcom.net)
12 /* INCLUDES *****************************************************************/
14 #include <ddk/ntddk.h>
15 #include <internal/ob.h>
16 #include <internal/port.h>
17 #include <internal/dbg.h>
18 #include <internal/pool.h>
19 #include <internal/safe.h>
20 #include <internal/mm.h>
23 #include <internal/debug.h>
25 /* GLOBALS *******************************************************************/
27 #define TAG_LPC_CONNECT_MESSAGE TAG('L', 'P', 'C', 'C')
29 /* FUNCTIONS *****************************************************************/
32 EiConnectPort(IN PEPORT* ConnectedPort,
34 IN PSECTION_OBJECT Section,
35 IN LARGE_INTEGER SectionOffset,
37 OUT PVOID* ClientSendViewBase,
38 OUT PVOID* ServerSendViewBase,
39 OUT PULONG ReceiveViewSize,
40 OUT PVOID* ReceiveViewBase,
41 OUT PULONG MaximumMessageSize,
42 IN OUT PVOID ConnectData,
43 IN OUT PULONG ConnectDataLength)
45 PEPORT_CONNECT_REQUEST_MESSAGE RequestMessage;
46 ULONG RequestConnectDataLength;
49 PEPORT_CONNECT_REPLY_MESSAGE CReply;
53 if (ConnectDataLength == NULL)
55 RequestConnectDataLength = 0;
59 RequestConnectDataLength = *ConnectDataLength;
63 * Create a port to represent our side of the connection
65 Status = ObCreateObject (NULL,
70 if (!NT_SUCCESS(Status))
74 NiInitializePort(OurPort);
77 * Allocate a request message.
79 RequestMessage = ExAllocatePool(NonPagedPool,
80 sizeof(EPORT_CONNECT_REQUEST_MESSAGE) +
81 RequestConnectDataLength);
82 if (RequestMessage == NULL)
84 ObDereferenceObject(OurPort);
85 return(STATUS_NO_MEMORY);
89 * Initialize the request message.
91 RequestMessage->MessageHeader.DataSize =
92 sizeof(EPORT_CONNECT_REQUEST_MESSAGE) + RequestConnectDataLength -
93 sizeof(LPC_MESSAGE_HEADER);
94 RequestMessage->MessageHeader.MessageSize =
95 sizeof(EPORT_CONNECT_REQUEST_MESSAGE) + RequestConnectDataLength;
96 DPRINT("RequestMessageSize %d\n",
97 RequestMessage->MessageHeader.MessageSize);
98 RequestMessage->MessageHeader.SharedSectionSize = 0;
99 RequestMessage->ConnectingProcess = PsGetCurrentProcess();
100 ObReferenceObjectByPointer(RequestMessage->ConnectingProcess,
101 PROCESS_VM_OPERATION,
104 RequestMessage->SendSectionObject = (struct _SECTION_OBJECT*)Section;
105 RequestMessage->SendSectionOffset = SectionOffset;
106 RequestMessage->SendViewSize = ViewSize;
107 RequestMessage->ConnectDataLength = RequestConnectDataLength;
108 if (RequestConnectDataLength > 0)
110 memcpy(RequestMessage->ConnectData, ConnectData,
111 RequestConnectDataLength);
115 * Queue the message to the named port
117 EiReplyOrRequestPort(NamedPort,
118 &RequestMessage->MessageHeader,
119 LPC_CONNECTION_REQUEST,
121 KeReleaseSemaphore(&NamedPort->Semaphore, IO_NO_INCREMENT, 1, FALSE);
122 ExFreePool(RequestMessage);
125 * Wait for them to accept our connection
127 KeWaitForSingleObject(&OurPort->Semaphore,
134 * Dequeue the response
136 KeAcquireSpinLock (&OurPort->Lock, &oldIrql);
137 Reply = EiDequeueMessagePort (OurPort);
138 KeReleaseSpinLock (&OurPort->Lock, oldIrql);
139 CReply = (PEPORT_CONNECT_REPLY_MESSAGE)&Reply->Message;
142 * Do some initial cleanup.
144 ObDereferenceObject(PsGetCurrentProcess());
147 * Check for connection refusal.
149 if (CReply->MessageHeader.MessageType == LPC_CONNECTION_REFUSED)
151 ObDereferenceObject(OurPort);
154 * FIXME: Check what NT does here. Giving the user data back on
155 * connect failure sounds reasonable; it probably wouldn't break
158 if (ConnectDataLength != NULL)
160 *ConnectDataLength = CReply->ConnectDataLength;
161 memcpy(ConnectData, CReply->ConnectData, CReply->ConnectDataLength);
163 return(STATUS_PORT_CONNECTION_REFUSED);
167 * Otherwise we are connected. Copy data back to the client.
169 *ServerSendViewBase = CReply->SendServerViewBase;
170 *ReceiveViewSize = CReply->ReceiveClientViewSize;
171 *ReceiveViewBase = CReply->ReceiveClientViewBase;
172 *MaximumMessageSize = CReply->MaximumMessageSize;
173 if (ConnectDataLength != NULL)
175 *ConnectDataLength = CReply->ConnectDataLength;
176 memcpy(ConnectData, CReply->ConnectData, CReply->ConnectDataLength);
180 * Create our view of the send section object.
184 *ClientSendViewBase = 0;
185 Status = MmMapViewOfSection(Section,
186 PsGetCurrentProcess(),
193 0 /* MEM_TOP_DOWN? */,
195 if (!NT_SUCCESS(Status))
197 /* FIXME: Cleanup here. */
203 * Do the final initialization of our port.
205 OurPort->State = EPORT_CONNECTED_CLIENT;
211 *ConnectedPort = OurPort;
212 return(STATUS_SUCCESS);
215 /**********************************************************************
220 * Connect to a named port and wait for the other side to
221 * accept the connection.
231 * UserConnectInfoLength
237 NtConnectPort (PHANDLE UnsafeConnectedPortHandle,
238 PUNICODE_STRING PortName,
239 PSECURITY_QUALITY_OF_SERVICE Qos,
240 PLPC_SECTION_WRITE UnsafeWriteMap,
241 PLPC_SECTION_READ UnsafeReadMap,
242 PULONG UnsafeMaximumMessageSize,
243 PVOID UnsafeConnectData,
244 PULONG UnsafeConnectDataLength)
246 HANDLE ConnectedPortHandle;
247 LPC_SECTION_WRITE WriteMap;
248 LPC_SECTION_READ ReadMap;
249 ULONG MaximumMessageSize;
251 ULONG ConnectDataLength;
252 PSECTION_OBJECT SectionObject;
253 LARGE_INTEGER SectionOffset;
254 PEPORT ConnectedPort;
259 * Copy in write map and partially validate.
261 if (UnsafeWriteMap != NULL)
263 Status = MmCopyFromCaller(&WriteMap, UnsafeWriteMap,
264 sizeof(LPC_SECTION_WRITE));
265 if (!NT_SUCCESS(Status))
269 if (WriteMap.Length != sizeof(LPC_SECTION_WRITE))
271 return(STATUS_INVALID_PARAMETER_4);
273 SectionOffset.QuadPart = WriteMap.SectionOffset;
277 WriteMap.SectionHandle = INVALID_HANDLE_VALUE;
281 * Handle connection data.
283 if (UnsafeConnectData == NULL)
285 ConnectDataLength = 0;
290 if (ExGetPreviousMode() == KernelMode)
292 ConnectDataLength = *UnsafeConnectDataLength;
293 ConnectData = UnsafeConnectData;
297 Status = MmCopyFromCaller(&ConnectDataLength,
298 UnsafeConnectDataLength,
300 if (!NT_SUCCESS(Status))
304 ConnectData = ExAllocatePool(NonPagedPool, ConnectDataLength);
305 if (ConnectData == NULL && ConnectDataLength != 0)
307 return(STATUS_NO_MEMORY);
309 Status = MmCopyFromCaller(ConnectData,
312 if (!NT_SUCCESS(Status))
314 ExFreePool(ConnectData);
321 * Reference the named port.
323 Status = ObReferenceObjectByName (PortName,
326 PORT_ALL_ACCESS, /* DesiredAccess */
331 if (!NT_SUCCESS(Status))
333 if (KeGetPreviousMode() != KernelMode)
335 ExFreePool(ConnectData);
341 * Reference the send section object.
343 if (WriteMap.SectionHandle != INVALID_HANDLE_VALUE)
345 Status = ObReferenceObjectByHandle(WriteMap.SectionHandle,
346 SECTION_MAP_READ | SECTION_MAP_WRITE,
349 (PVOID*)&SectionObject,
351 if (!NT_SUCCESS(Status))
353 ObDereferenceObject(NamedPort);
354 if (KeGetPreviousMode() != KernelMode)
356 ExFreePool(ConnectData);
363 SectionObject = NULL;
367 * Do the connection establishment.
369 Status = EiConnectPort(&ConnectedPort,
375 &WriteMap.TargetViewBase,
381 if (!NT_SUCCESS(Status))
383 /* FIXME: Again, check what NT does here. */
384 if (UnsafeConnectDataLength != NULL)
386 if (ExGetPreviousMode() != KernelMode)
388 MmCopyToCaller(UnsafeConnectData, ConnectData,
390 ExFreePool(ConnectData);
392 MmCopyToCaller(UnsafeConnectDataLength, &ConnectDataLength,
399 * Do some initial cleanup.
401 if (SectionObject != NULL)
403 ObDereferenceObject(SectionObject);
404 SectionObject = NULL;
406 ObDereferenceObject(NamedPort);
410 * Copy the data back to the caller.
412 if (ExGetPreviousMode() != KernelMode)
414 if (UnsafeConnectDataLength != NULL)
416 if (ExGetPreviousMode() != KernelMode)
418 Status = MmCopyToCaller(UnsafeConnectData, ConnectData,
420 ExFreePool(ConnectData);
421 if (!NT_SUCCESS(Status))
426 Status = MmCopyToCaller(UnsafeConnectDataLength, &ConnectDataLength,
428 if (!NT_SUCCESS(Status))
434 Status = ObInsertObject(ConnectedPort,
439 &ConnectedPortHandle);
440 if (!NT_SUCCESS(Status))
444 Status = MmCopyToCaller(UnsafeConnectedPortHandle, &ConnectedPortHandle,
446 if (!NT_SUCCESS(Status))
450 if (UnsafeWriteMap != NULL)
452 Status = MmCopyToCaller(UnsafeWriteMap, &WriteMap,
453 sizeof(LPC_SECTION_WRITE));
454 if (!NT_SUCCESS(Status))
459 if (UnsafeReadMap != NULL)
461 Status = MmCopyToCaller(UnsafeReadMap, &ReadMap,
462 sizeof(LPC_SECTION_READ));
463 if (!NT_SUCCESS(Status))
468 if (UnsafeMaximumMessageSize != NULL)
470 Status = MmCopyToCaller(UnsafeMaximumMessageSize,
472 sizeof(LPC_SECTION_WRITE));
473 if (!NT_SUCCESS(Status))
482 ObDereferenceObject(ConnectedPort);
484 return(STATUS_SUCCESS);
488 /**********************************************************************
490 * NtAcceptConnectPort@24
505 EXPORTED NTSTATUS STDCALL
506 NtAcceptConnectPort (PHANDLE ServerPortHandle,
507 HANDLE NamedPortHandle,
508 PLPC_MESSAGE LpcMessage,
510 PLPC_SECTION_WRITE WriteMap,
511 PLPC_SECTION_READ ReadMap)
515 PEPORT OurPort = NULL;
516 PQUEUEDMESSAGE ConnectionRequest;
518 PEPORT_CONNECT_REQUEST_MESSAGE CRequest;
519 PEPORT_CONNECT_REPLY_MESSAGE CReply;
521 CReply = ExAllocatePool(NonPagedPool,
522 sizeof(EPORT_CONNECT_REPLY_MESSAGE) + LpcMessage->DataSize);
525 return(STATUS_NO_MEMORY);
528 Status = ObReferenceObjectByHandle(NamedPortHandle,
534 if (!NT_SUCCESS(Status))
541 * Create a port object for our side of the connection
545 Status = ObCreateObject(ServerPortHandle,
550 if (!NT_SUCCESS(Status))
552 ObDereferenceObject(NamedPort);
555 NiInitializePort(OurPort);
559 * Dequeue the connection request
561 KeAcquireSpinLock(&NamedPort->Lock, &oldIrql);
562 ConnectionRequest = EiDequeueConnectMessagePort (NamedPort);
563 KeReleaseSpinLock(&NamedPort->Lock, oldIrql);
564 CRequest = (PEPORT_CONNECT_REQUEST_MESSAGE)(&ConnectionRequest->Message);
569 if (LpcMessage != NULL)
571 memcpy(&CReply->MessageHeader, LpcMessage, sizeof(LPC_MESSAGE_HEADER));
572 memcpy(&CReply->ConnectData, (PVOID)(LpcMessage + 1),
573 LpcMessage->DataSize);
574 CReply->MessageHeader.MessageSize =
575 sizeof(EPORT_CONNECT_REPLY_MESSAGE) + LpcMessage->DataSize;
576 CReply->MessageHeader.DataSize = CReply->MessageHeader.MessageSize -
577 sizeof(LPC_MESSAGE_HEADER);
578 CReply->ConnectDataLength = LpcMessage->DataSize;
582 CReply->MessageHeader.MessageSize = sizeof(EPORT_CONNECT_REPLY_MESSAGE);
583 CReply->MessageHeader.DataSize = sizeof(EPORT_CONNECT_REPLY_MESSAGE) -
584 sizeof(LPC_MESSAGE_HEADER);
585 CReply->ConnectDataLength = 0;
589 EiReplyOrRequestPort(ConnectionRequest->Sender,
590 &CReply->MessageHeader,
591 LPC_CONNECTION_REFUSED,
593 KeReleaseSemaphore(&ConnectionRequest->Sender->Semaphore,
597 ObDereferenceObject(ConnectionRequest->Sender);
598 ExFreePool(ConnectionRequest);
600 ObDereferenceObject(NamedPort);
601 return (STATUS_SUCCESS);
605 * Prepare the connection.
607 if (WriteMap != NULL)
609 PSECTION_OBJECT SectionObject;
610 LARGE_INTEGER SectionOffset;
612 Status = ObReferenceObjectByHandle(WriteMap->SectionHandle,
613 SECTION_MAP_READ | SECTION_MAP_WRITE,
616 (PVOID*)&SectionObject,
618 if (!NT_SUCCESS(Status))
623 SectionOffset.QuadPart = WriteMap->SectionOffset;
624 WriteMap->TargetViewBase = 0;
625 CReply->ReceiveClientViewSize = WriteMap->ViewSize;
626 Status = MmMapViewOfSection(SectionObject,
627 CRequest->ConnectingProcess,
628 &WriteMap->TargetViewBase,
630 CReply->ReceiveClientViewSize,
632 &CReply->ReceiveClientViewSize,
634 0 /* MEM_TOP_DOWN? */,
636 if (!NT_SUCCESS(Status))
641 WriteMap->ViewBase = 0;
642 Status = MmMapViewOfSection(SectionObject,
643 PsGetCurrentProcess(),
650 0 /* MEM_TOP_DOWN? */,
652 if (!NT_SUCCESS(Status))
657 ObDereferenceObject(SectionObject);
659 if (ReadMap != NULL && CRequest->SendSectionObject != NULL)
661 LARGE_INTEGER SectionOffset;
663 SectionOffset = CRequest->SendSectionOffset;
664 ReadMap->ViewSize = CRequest->SendViewSize;
665 ReadMap->ViewBase = 0;
666 Status = MmMapViewOfSection(CRequest->SendSectionObject,
667 PsGetCurrentProcess(),
670 CRequest->SendViewSize,
672 &CRequest->SendViewSize,
674 0 /* MEM_TOP_DOWN? */,
676 if (!NT_SUCCESS(Status))
687 CReply->SendServerViewBase = ReadMap->ViewBase;
691 CReply->SendServerViewBase = 0;
693 if (WriteMap != NULL)
695 CReply->ReceiveClientViewBase = WriteMap->TargetViewBase;
697 CReply->MaximumMessageSize = 0x148;
701 * Connect the two ports
703 OurPort->OtherPort = ConnectionRequest->Sender;
704 OurPort->OtherPort->OtherPort = OurPort;
705 EiReplyOrRequestPort(ConnectionRequest->Sender,
706 (PLPC_MESSAGE)CReply,
709 ExFreePool(ConnectionRequest);
711 ObDereferenceObject(OurPort);
712 ObDereferenceObject(NamedPort);
714 return (STATUS_SUCCESS);
717 /**********************************************************************
719 * NtSecureConnectPort@36
722 * Connect to a named port and wait for the other side to
723 * accept the connection. Possibly verify that the server
724 * matches the ServerSid (trusted server).
736 * UserConnectInfoLength
742 NtSecureConnectPort (OUT PHANDLE ConnectedPort,
743 IN PUNICODE_STRING PortName,
744 IN PSECURITY_QUALITY_OF_SERVICE Qos,
745 IN OUT PLPC_SECTION_WRITE WriteMap OPTIONAL,
746 IN PSID ServerSid OPTIONAL,
747 IN OUT PLPC_SECTION_READ ReadMap OPTIONAL,
748 OUT PULONG MaxMessageSize OPTIONAL,
749 IN OUT PVOID ConnectInfo OPTIONAL,
750 IN OUT PULONG UserConnectInfoLength OPTIONAL)
752 return (STATUS_NOT_IMPLEMENTED);