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 #define NTOS_MODE_KERNEL
16 #include <internal/ob.h>
17 #include <internal/port.h>
18 #include <internal/dbg.h>
19 #include <internal/pool.h>
20 #include <internal/safe.h>
21 #include <internal/mm.h>
24 #include <internal/debug.h>
26 /* GLOBALS *******************************************************************/
28 #define TAG_LPC_CONNECT_MESSAGE TAG('L', 'P', 'C', 'C')
30 /* FUNCTIONS *****************************************************************/
33 EiConnectPort(IN PEPORT* ConnectedPort,
35 IN PSECTION_OBJECT Section,
36 IN LARGE_INTEGER SectionOffset,
38 OUT PVOID* ClientSendViewBase,
39 OUT PVOID* ServerSendViewBase,
40 OUT PULONG ReceiveViewSize,
41 OUT PVOID* ReceiveViewBase,
42 OUT PULONG MaximumMessageSize,
43 IN OUT PVOID ConnectData,
44 IN OUT PULONG ConnectDataLength)
46 PEPORT_CONNECT_REQUEST_MESSAGE RequestMessage;
47 ULONG RequestConnectDataLength;
50 PEPORT_CONNECT_REPLY_MESSAGE CReply;
54 if (ConnectDataLength == NULL)
56 RequestConnectDataLength = 0;
60 RequestConnectDataLength = *ConnectDataLength;
64 * Create a port to represent our side of the connection
66 Status = ObRosCreateObject (NULL,
71 if (!NT_SUCCESS(Status))
75 NiInitializePort(OurPort);
78 * Allocate a request message.
80 RequestMessage = ExAllocatePool(NonPagedPool,
81 sizeof(EPORT_CONNECT_REQUEST_MESSAGE) +
82 RequestConnectDataLength);
83 if (RequestMessage == NULL)
85 ObDereferenceObject(OurPort);
86 return(STATUS_NO_MEMORY);
90 * Initialize the request message.
92 RequestMessage->MessageHeader.DataSize =
93 sizeof(EPORT_CONNECT_REQUEST_MESSAGE) + RequestConnectDataLength -
95 RequestMessage->MessageHeader.MessageSize =
96 sizeof(EPORT_CONNECT_REQUEST_MESSAGE) + RequestConnectDataLength;
97 DPRINT("RequestMessageSize %d\n",
98 RequestMessage->MessageHeader.MessageSize);
99 RequestMessage->MessageHeader.SectionSize = 0;
100 RequestMessage->ConnectingProcess = PsGetCurrentProcess();
101 ObReferenceObjectByPointer(RequestMessage->ConnectingProcess,
102 PROCESS_VM_OPERATION,
105 RequestMessage->SendSectionObject = (struct _SECTION_OBJECT*)Section;
106 RequestMessage->SendSectionOffset = SectionOffset;
107 RequestMessage->SendViewSize = ViewSize;
108 RequestMessage->ConnectDataLength = RequestConnectDataLength;
109 if (RequestConnectDataLength > 0)
111 memcpy(RequestMessage->ConnectData, ConnectData,
112 RequestConnectDataLength);
116 * Queue the message to the named port
118 EiReplyOrRequestPort(NamedPort,
119 &RequestMessage->MessageHeader,
120 LPC_CONNECTION_REQUEST,
122 KeReleaseSemaphore(&NamedPort->Semaphore, IO_NO_INCREMENT, 1, FALSE);
123 ExFreePool(RequestMessage);
126 * Wait for them to accept our connection
128 KeWaitForSingleObject(&OurPort->Semaphore,
135 * Dequeue the response
137 KeAcquireSpinLock (&OurPort->Lock, &oldIrql);
138 Reply = EiDequeueMessagePort (OurPort);
139 KeReleaseSpinLock (&OurPort->Lock, oldIrql);
140 CReply = (PEPORT_CONNECT_REPLY_MESSAGE)&Reply->Message;
143 * Do some initial cleanup.
145 ObDereferenceObject(PsGetCurrentProcess());
148 * Check for connection refusal.
150 if (CReply->MessageHeader.MessageType == LPC_CONNECTION_REFUSED)
152 ObDereferenceObject(OurPort);
155 * FIXME: Check what NT does here. Giving the user data back on
156 * connect failure sounds reasonable; it probably wouldn't break
159 if (ConnectDataLength != NULL)
161 *ConnectDataLength = CReply->ConnectDataLength;
162 memcpy(ConnectData, CReply->ConnectData, CReply->ConnectDataLength);
164 return(STATUS_PORT_CONNECTION_REFUSED);
168 * Otherwise we are connected. Copy data back to the client.
170 *ServerSendViewBase = CReply->SendServerViewBase;
171 *ReceiveViewSize = CReply->ReceiveClientViewSize;
172 *ReceiveViewBase = CReply->ReceiveClientViewBase;
173 *MaximumMessageSize = CReply->MaximumMessageSize;
174 if (ConnectDataLength != NULL)
176 *ConnectDataLength = CReply->ConnectDataLength;
177 memcpy(ConnectData, CReply->ConnectData, CReply->ConnectDataLength);
181 * Create our view of the send section object.
185 *ClientSendViewBase = 0;
186 Status = MmMapViewOfSection(Section,
187 PsGetCurrentProcess(),
194 0 /* MEM_TOP_DOWN? */,
196 if (!NT_SUCCESS(Status))
198 /* FIXME: Cleanup here. */
204 * Do the final initialization of our port.
206 OurPort->State = EPORT_CONNECTED_CLIENT;
212 *ConnectedPort = OurPort;
213 return(STATUS_SUCCESS);
216 /**********************************************************************
221 * Connect to a named port and wait for the other side to
222 * accept the connection.
232 * UserConnectInfoLength
239 NtConnectPort (PHANDLE UnsafeConnectedPortHandle,
240 PUNICODE_STRING PortName,
241 PSECURITY_QUALITY_OF_SERVICE Qos,
242 PLPC_SECTION_WRITE UnsafeWriteMap,
243 PLPC_SECTION_READ UnsafeReadMap,
244 PULONG UnsafeMaximumMessageSize,
245 PVOID UnsafeConnectData,
246 PULONG UnsafeConnectDataLength)
248 HANDLE ConnectedPortHandle;
249 LPC_SECTION_WRITE WriteMap;
250 LPC_SECTION_READ ReadMap;
251 ULONG MaximumMessageSize;
253 ULONG ConnectDataLength;
254 PSECTION_OBJECT SectionObject;
255 LARGE_INTEGER SectionOffset;
256 PEPORT ConnectedPort;
261 * Copy in write map and partially validate.
263 if (UnsafeWriteMap != NULL)
265 Status = MmCopyFromCaller(&WriteMap, UnsafeWriteMap,
266 sizeof(LPC_SECTION_WRITE));
267 if (!NT_SUCCESS(Status))
271 if (WriteMap.Length != sizeof(LPC_SECTION_WRITE))
273 return(STATUS_INVALID_PARAMETER_4);
275 SectionOffset.QuadPart = WriteMap.SectionOffset;
279 WriteMap.SectionHandle = INVALID_HANDLE_VALUE;
283 * Handle connection data.
285 if (UnsafeConnectData == NULL)
287 ConnectDataLength = 0;
292 if (ExGetPreviousMode() == KernelMode)
294 ConnectDataLength = *UnsafeConnectDataLength;
295 ConnectData = UnsafeConnectData;
299 Status = MmCopyFromCaller(&ConnectDataLength,
300 UnsafeConnectDataLength,
302 if (!NT_SUCCESS(Status))
306 ConnectData = ExAllocatePool(NonPagedPool, ConnectDataLength);
307 if (ConnectData == NULL && ConnectDataLength != 0)
309 return(STATUS_NO_MEMORY);
311 Status = MmCopyFromCaller(ConnectData,
314 if (!NT_SUCCESS(Status))
316 ExFreePool(ConnectData);
323 * Reference the named port.
325 Status = ObReferenceObjectByName (PortName,
328 PORT_ALL_ACCESS, /* DesiredAccess */
333 if (!NT_SUCCESS(Status))
335 if (KeGetPreviousMode() != KernelMode)
337 ExFreePool(ConnectData);
343 * Reference the send section object.
345 if (WriteMap.SectionHandle != INVALID_HANDLE_VALUE)
347 Status = ObReferenceObjectByHandle(WriteMap.SectionHandle,
348 SECTION_MAP_READ | SECTION_MAP_WRITE,
351 (PVOID*)&SectionObject,
353 if (!NT_SUCCESS(Status))
355 ObDereferenceObject(NamedPort);
356 if (KeGetPreviousMode() != KernelMode)
358 ExFreePool(ConnectData);
365 SectionObject = NULL;
369 * Do the connection establishment.
371 Status = EiConnectPort(&ConnectedPort,
377 &WriteMap.TargetViewBase,
383 if (!NT_SUCCESS(Status))
385 /* FIXME: Again, check what NT does here. */
386 if (UnsafeConnectDataLength != NULL)
388 if (ExGetPreviousMode() != KernelMode)
390 MmCopyToCaller(UnsafeConnectData, ConnectData,
392 ExFreePool(ConnectData);
394 MmCopyToCaller(UnsafeConnectDataLength, &ConnectDataLength,
401 * Do some initial cleanup.
403 if (SectionObject != NULL)
405 ObDereferenceObject(SectionObject);
406 SectionObject = NULL;
408 ObDereferenceObject(NamedPort);
412 * Copy the data back to the caller.
414 if (ExGetPreviousMode() != KernelMode)
416 if (UnsafeConnectDataLength != NULL)
418 if (ExGetPreviousMode() != KernelMode)
420 Status = MmCopyToCaller(UnsafeConnectData, ConnectData,
422 ExFreePool(ConnectData);
423 if (!NT_SUCCESS(Status))
428 Status = MmCopyToCaller(UnsafeConnectDataLength, &ConnectDataLength,
430 if (!NT_SUCCESS(Status))
436 Status = ObInsertObject(ConnectedPort,
441 &ConnectedPortHandle);
442 if (!NT_SUCCESS(Status))
446 Status = MmCopyToCaller(UnsafeConnectedPortHandle, &ConnectedPortHandle,
448 if (!NT_SUCCESS(Status))
452 if (UnsafeWriteMap != NULL)
454 Status = MmCopyToCaller(UnsafeWriteMap, &WriteMap,
455 sizeof(LPC_SECTION_WRITE));
456 if (!NT_SUCCESS(Status))
461 if (UnsafeReadMap != NULL)
463 Status = MmCopyToCaller(UnsafeReadMap, &ReadMap,
464 sizeof(LPC_SECTION_READ));
465 if (!NT_SUCCESS(Status))
470 if (UnsafeMaximumMessageSize != NULL)
472 Status = MmCopyToCaller(UnsafeMaximumMessageSize,
474 sizeof(LPC_SECTION_WRITE));
475 if (!NT_SUCCESS(Status))
485 return(STATUS_SUCCESS);
489 /**********************************************************************
491 * 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 = ObRosCreateObject(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
749 NtSecureConnectPort (OUT PHANDLE ConnectedPort,
750 IN PUNICODE_STRING PortName,
751 IN PSECURITY_QUALITY_OF_SERVICE Qos,
752 IN OUT PLPC_SECTION_WRITE WriteMap OPTIONAL,
753 IN PSID ServerSid OPTIONAL,
754 IN OUT PLPC_SECTION_READ ReadMap OPTIONAL,
755 OUT PULONG MaxMessageSize OPTIONAL,
756 IN OUT PVOID ConnectInfo OPTIONAL,
757 IN OUT PULONG UserConnectInfoLength OPTIONAL)
759 return (STATUS_NOT_IMPLEMENTED);