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 -
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;
522 Size = sizeof(EPORT_CONNECT_REPLY_MESSAGE);
525 Size += LpcMessage->DataSize;
528 CReply = ExAllocatePool(NonPagedPool, Size);
531 return(STATUS_NO_MEMORY);
534 Status = ObReferenceObjectByHandle(NamedPortHandle,
540 if (!NT_SUCCESS(Status))
547 * Create a port object for our side of the connection
551 Status = ObCreateObject(ServerPortHandle,
556 if (!NT_SUCCESS(Status))
559 ObDereferenceObject(NamedPort);
562 NiInitializePort(OurPort);
566 * Dequeue the connection request
568 KeAcquireSpinLock(&NamedPort->Lock, &oldIrql);
569 ConnectionRequest = EiDequeueConnectMessagePort (NamedPort);
570 KeReleaseSpinLock(&NamedPort->Lock, oldIrql);
571 CRequest = (PEPORT_CONNECT_REQUEST_MESSAGE)(&ConnectionRequest->Message);
576 if (LpcMessage != NULL)
578 memcpy(&CReply->MessageHeader, LpcMessage, sizeof(LPC_MESSAGE));
579 memcpy(&CReply->ConnectData, (PVOID)(LpcMessage + 1),
580 LpcMessage->DataSize);
581 CReply->MessageHeader.MessageSize =
582 sizeof(EPORT_CONNECT_REPLY_MESSAGE) + LpcMessage->DataSize;
583 CReply->MessageHeader.DataSize = CReply->MessageHeader.MessageSize -
585 CReply->ConnectDataLength = LpcMessage->DataSize;
589 CReply->MessageHeader.MessageSize = sizeof(EPORT_CONNECT_REPLY_MESSAGE);
590 CReply->MessageHeader.DataSize = sizeof(EPORT_CONNECT_REPLY_MESSAGE) -
592 CReply->ConnectDataLength = 0;
596 EiReplyOrRequestPort(ConnectionRequest->Sender,
597 &CReply->MessageHeader,
598 LPC_CONNECTION_REFUSED,
600 KeReleaseSemaphore(&ConnectionRequest->Sender->Semaphore,
604 ObDereferenceObject(ConnectionRequest->Sender);
605 ExFreePool(ConnectionRequest);
607 ObDereferenceObject(NamedPort);
608 return (STATUS_SUCCESS);
612 * Prepare the connection.
614 if (WriteMap != NULL)
616 PSECTION_OBJECT SectionObject;
617 LARGE_INTEGER SectionOffset;
619 Status = ObReferenceObjectByHandle(WriteMap->SectionHandle,
620 SECTION_MAP_READ | SECTION_MAP_WRITE,
623 (PVOID*)&SectionObject,
625 if (!NT_SUCCESS(Status))
630 SectionOffset.QuadPart = WriteMap->SectionOffset;
631 WriteMap->TargetViewBase = 0;
632 CReply->ReceiveClientViewSize = WriteMap->ViewSize;
633 Status = MmMapViewOfSection(SectionObject,
634 CRequest->ConnectingProcess,
635 &WriteMap->TargetViewBase,
637 CReply->ReceiveClientViewSize,
639 &CReply->ReceiveClientViewSize,
641 0 /* MEM_TOP_DOWN? */,
643 if (!NT_SUCCESS(Status))
648 WriteMap->ViewBase = 0;
649 Status = MmMapViewOfSection(SectionObject,
650 PsGetCurrentProcess(),
657 0 /* MEM_TOP_DOWN? */,
659 if (!NT_SUCCESS(Status))
664 ObDereferenceObject(SectionObject);
666 if (ReadMap != NULL && CRequest->SendSectionObject != NULL)
668 LARGE_INTEGER SectionOffset;
670 SectionOffset = CRequest->SendSectionOffset;
671 ReadMap->ViewSize = CRequest->SendViewSize;
672 ReadMap->ViewBase = 0;
673 Status = MmMapViewOfSection(CRequest->SendSectionObject,
674 PsGetCurrentProcess(),
677 CRequest->SendViewSize,
679 &CRequest->SendViewSize,
681 0 /* MEM_TOP_DOWN? */,
683 if (!NT_SUCCESS(Status))
694 CReply->SendServerViewBase = ReadMap->ViewBase;
698 CReply->SendServerViewBase = 0;
700 if (WriteMap != NULL)
702 CReply->ReceiveClientViewBase = WriteMap->TargetViewBase;
704 CReply->MaximumMessageSize = 0x148;
708 * Connect the two ports
710 OurPort->OtherPort = ConnectionRequest->Sender;
711 OurPort->OtherPort->OtherPort = OurPort;
712 EiReplyOrRequestPort(ConnectionRequest->Sender,
713 (PLPC_MESSAGE)CReply,
716 ExFreePool(ConnectionRequest);
719 ObDereferenceObject(OurPort);
720 ObDereferenceObject(NamedPort);
722 return (STATUS_SUCCESS);
725 /**********************************************************************
727 * NtSecureConnectPort@36
730 * Connect to a named port and wait for the other side to
731 * accept the connection. Possibly verify that the server
732 * matches the ServerSid (trusted server).
744 * UserConnectInfoLength
750 NtSecureConnectPort (OUT PHANDLE ConnectedPort,
751 IN PUNICODE_STRING PortName,
752 IN PSECURITY_QUALITY_OF_SERVICE Qos,
753 IN OUT PLPC_SECTION_WRITE WriteMap OPTIONAL,
754 IN PSID ServerSid OPTIONAL,
755 IN OUT PLPC_SECTION_READ ReadMap OPTIONAL,
756 OUT PULONG MaxMessageSize OPTIONAL,
757 IN OUT PVOID ConnectInfo OPTIONAL,
758 IN OUT PULONG UserConnectInfoLength OPTIONAL)
760 return (STATUS_NOT_IMPLEMENTED);