1 /* $Id: connect.c,v 1.16 2003/06/07 12:23:14 chorns Exp $
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
.SharedSectionSize
= 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
238 NtConnectPort (PHANDLE UnsafeConnectedPortHandle
,
239 PUNICODE_STRING PortName
,
240 PSECURITY_QUALITY_OF_SERVICE Qos
,
241 PLPC_SECTION_WRITE UnsafeWriteMap
,
242 PLPC_SECTION_READ UnsafeReadMap
,
243 PULONG UnsafeMaximumMessageSize
,
244 PVOID UnsafeConnectData
,
245 PULONG UnsafeConnectDataLength
)
247 HANDLE ConnectedPortHandle
;
248 LPC_SECTION_WRITE WriteMap
;
249 LPC_SECTION_READ ReadMap
;
250 ULONG MaximumMessageSize
;
252 ULONG ConnectDataLength
;
253 PSECTION_OBJECT SectionObject
;
254 LARGE_INTEGER SectionOffset
;
255 PEPORT ConnectedPort
;
260 * Copy in write map and partially validate.
262 if (UnsafeWriteMap
!= NULL
)
264 Status
= MmCopyFromCaller(&WriteMap
, UnsafeWriteMap
,
265 sizeof(LPC_SECTION_WRITE
));
266 if (!NT_SUCCESS(Status
))
270 if (WriteMap
.Length
!= sizeof(LPC_SECTION_WRITE
))
272 return(STATUS_INVALID_PARAMETER_4
);
274 SectionOffset
.QuadPart
= WriteMap
.SectionOffset
;
278 WriteMap
.SectionHandle
= INVALID_HANDLE_VALUE
;
282 * Handle connection data.
284 if (UnsafeConnectData
== NULL
)
286 ConnectDataLength
= 0;
291 if (ExGetPreviousMode() == KernelMode
)
293 ConnectDataLength
= *UnsafeConnectDataLength
;
294 ConnectData
= UnsafeConnectData
;
298 Status
= MmCopyFromCaller(&ConnectDataLength
,
299 UnsafeConnectDataLength
,
301 if (!NT_SUCCESS(Status
))
305 ConnectData
= ExAllocatePool(NonPagedPool
, ConnectDataLength
);
306 if (ConnectData
== NULL
&& ConnectDataLength
!= 0)
308 return(STATUS_NO_MEMORY
);
310 Status
= MmCopyFromCaller(ConnectData
,
313 if (!NT_SUCCESS(Status
))
315 ExFreePool(ConnectData
);
322 * Reference the named port.
324 Status
= ObReferenceObjectByName (PortName
,
327 PORT_ALL_ACCESS
, /* DesiredAccess */
332 if (!NT_SUCCESS(Status
))
334 if (KeGetPreviousMode() != KernelMode
)
336 ExFreePool(ConnectData
);
342 * Reference the send section object.
344 if (WriteMap
.SectionHandle
!= INVALID_HANDLE_VALUE
)
346 Status
= ObReferenceObjectByHandle(WriteMap
.SectionHandle
,
347 SECTION_MAP_READ
| SECTION_MAP_WRITE
,
350 (PVOID
*)&SectionObject
,
352 if (!NT_SUCCESS(Status
))
354 ObDereferenceObject(NamedPort
);
355 if (KeGetPreviousMode() != KernelMode
)
357 ExFreePool(ConnectData
);
364 SectionObject
= NULL
;
368 * Do the connection establishment.
370 Status
= EiConnectPort(&ConnectedPort
,
376 &WriteMap
.TargetViewBase
,
382 if (!NT_SUCCESS(Status
))
384 /* FIXME: Again, check what NT does here. */
385 if (UnsafeConnectDataLength
!= NULL
)
387 if (ExGetPreviousMode() != KernelMode
)
389 MmCopyToCaller(UnsafeConnectData
, ConnectData
,
391 ExFreePool(ConnectData
);
393 MmCopyToCaller(UnsafeConnectDataLength
, &ConnectDataLength
,
400 * Do some initial cleanup.
402 if (SectionObject
!= NULL
)
404 ObDereferenceObject(SectionObject
);
405 SectionObject
= NULL
;
407 ObDereferenceObject(NamedPort
);
411 * Copy the data back to the caller.
413 if (ExGetPreviousMode() != KernelMode
)
415 if (UnsafeConnectDataLength
!= NULL
)
417 if (ExGetPreviousMode() != KernelMode
)
419 Status
= MmCopyToCaller(UnsafeConnectData
, ConnectData
,
421 ExFreePool(ConnectData
);
422 if (!NT_SUCCESS(Status
))
427 Status
= MmCopyToCaller(UnsafeConnectDataLength
, &ConnectDataLength
,
429 if (!NT_SUCCESS(Status
))
435 Status
= ObInsertObject(ConnectedPort
,
440 &ConnectedPortHandle
);
441 if (!NT_SUCCESS(Status
))
445 Status
= MmCopyToCaller(UnsafeConnectedPortHandle
, &ConnectedPortHandle
,
447 if (!NT_SUCCESS(Status
))
451 if (UnsafeWriteMap
!= NULL
)
453 Status
= MmCopyToCaller(UnsafeWriteMap
, &WriteMap
,
454 sizeof(LPC_SECTION_WRITE
));
455 if (!NT_SUCCESS(Status
))
460 if (UnsafeReadMap
!= NULL
)
462 Status
= MmCopyToCaller(UnsafeReadMap
, &ReadMap
,
463 sizeof(LPC_SECTION_READ
));
464 if (!NT_SUCCESS(Status
))
469 if (UnsafeMaximumMessageSize
!= NULL
)
471 Status
= MmCopyToCaller(UnsafeMaximumMessageSize
,
473 sizeof(LPC_SECTION_WRITE
));
474 if (!NT_SUCCESS(Status
))
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
= 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
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
);