2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/lpc/create.c
5 * PURPOSE: Local Procedure Call: Port/Queue/Message Creation
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* PRIVATE FUNCTIONS *********************************************************/
19 LpcpInitializePortQueue(IN PLPCP_PORT_OBJECT Port
)
21 PLPCP_NONPAGED_PORT_QUEUE MessageQueue
;
25 /* Allocate the queue */
26 MessageQueue
= ExAllocatePoolWithTag(NonPagedPool
,
27 sizeof(*MessageQueue
),
29 if (!MessageQueue
) return STATUS_INSUFFICIENT_RESOURCES
;
32 KeInitializeSemaphore(&MessageQueue
->Semaphore
, 0, MAXLONG
);
33 MessageQueue
->BackPointer
= Port
;
35 /* And link it with the Paged Pool part */
36 Port
->MsgQueue
.Semaphore
= &MessageQueue
->Semaphore
;
37 InitializeListHead(&Port
->MsgQueue
.ReceiveHead
);
38 return STATUS_SUCCESS
;
43 LpcpCreatePort(OUT PHANDLE PortHandle
,
44 IN POBJECT_ATTRIBUTES ObjectAttributes
,
45 IN ULONG MaxConnectionInfoLength
,
46 IN ULONG MaxMessageLength
,
47 IN ULONG MaxPoolUsage
,
51 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
52 UNICODE_STRING CapturedObjectName
, *ObjectName
;
53 PLPCP_PORT_OBJECT Port
;
57 LPCTRACE(LPC_CREATE_DEBUG
, "Name: %wZ\n", ObjectAttributes
->ObjectName
);
59 RtlInitEmptyUnicodeString(&CapturedObjectName
, NULL
, 0);
61 /* Check if the call comes from user mode */
62 if (PreviousMode
!= KernelMode
)
66 /* Probe the PortHandle */
67 ProbeForWriteHandle(PortHandle
);
69 /* Probe the ObjectAttributes and its object name (not the buffer) */
70 ProbeForRead(ObjectAttributes
, sizeof(*ObjectAttributes
), sizeof(ULONG
));
71 ObjectName
= ((volatile OBJECT_ATTRIBUTES
*)ObjectAttributes
)->ObjectName
;
74 ProbeForRead(ObjectName
, sizeof(*ObjectName
), 1);
75 CapturedObjectName
= *(volatile UNICODE_STRING
*)ObjectName
;
78 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
80 /* Return the exception code */
81 _SEH2_YIELD(return _SEH2_GetExceptionCode());
87 if (ObjectAttributes
->ObjectName
)
88 CapturedObjectName
= *(ObjectAttributes
->ObjectName
);
91 /* Normalize the buffer pointer in case we don't have a name */
92 if (CapturedObjectName
.Length
== 0)
93 CapturedObjectName
.Buffer
= NULL
;
95 /* Create the Object */
96 Status
= ObCreateObject(PreviousMode
,
101 sizeof(LPCP_PORT_OBJECT
),
105 if (!NT_SUCCESS(Status
)) return Status
;
107 /* Set up the Object */
108 RtlZeroMemory(Port
, sizeof(LPCP_PORT_OBJECT
));
109 Port
->ConnectionPort
= Port
;
110 Port
->Creator
= PsGetCurrentThread()->Cid
;
111 InitializeListHead(&Port
->LpcDataInfoChainHead
);
112 InitializeListHead(&Port
->LpcReplyChainHead
);
114 /* Check if we don't have a name */
115 if (CapturedObjectName
.Buffer
== NULL
)
117 /* Set up for an unconnected port */
118 Port
->Flags
= LPCP_UNCONNECTED_PORT
;
119 Port
->ConnectedPort
= Port
;
120 Port
->ServerProcess
= NULL
;
124 /* Set up for a named connection port */
125 Port
->Flags
= LPCP_CONNECTION_PORT
;
126 Port
->ServerProcess
= PsGetCurrentProcess();
128 /* Don't let the process die on us */
129 ObReferenceObject(Port
->ServerProcess
);
132 /* Check if this is a waitable port */
133 if (Waitable
) Port
->Flags
|= LPCP_WAITABLE_PORT
;
135 /* Setup the port queue */
136 Status
= LpcpInitializePortQueue(Port
);
137 if (!NT_SUCCESS(Status
))
140 ObDereferenceObject(Port
);
144 /* Check if this is a waitable port */
145 if (Port
->Flags
& LPCP_WAITABLE_PORT
)
147 /* Setup the wait event */
148 KeInitializeEvent(&Port
->WaitEvent
, NotificationEvent
, FALSE
);
151 /* Set the maximum message size allowed */
152 Port
->MaxMessageLength
= LpcpMaxMessageSize
-
153 FIELD_OFFSET(LPCP_MESSAGE
, Request
);
155 /* Now subtract the actual message structures and get the data size */
156 Port
->MaxConnectionInfoLength
= Port
->MaxMessageLength
-
157 sizeof(PORT_MESSAGE
) -
158 sizeof(LPCP_CONNECTION_MESSAGE
);
160 /* Validate the sizes */
161 if (Port
->MaxConnectionInfoLength
< MaxConnectionInfoLength
)
163 /* Not enough space for your request */
164 ObDereferenceObject(Port
);
165 return STATUS_INVALID_PARAMETER_3
;
167 else if (Port
->MaxMessageLength
< MaxMessageLength
)
169 /* Not enough space for your request */
170 ObDereferenceObject(Port
);
171 return STATUS_INVALID_PARAMETER_4
;
174 /* Now set the custom setting */
175 Port
->MaxMessageLength
= MaxMessageLength
;
178 Status
= ObInsertObject(Port
,
184 if (NT_SUCCESS(Status
))
188 /* Write back the handle, pointer was already probed */
189 *PortHandle
= Handle
;
191 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
193 /* An exception happened, close the opened handle */
194 ObCloseHandle(Handle
, PreviousMode
);
195 Status
= _SEH2_GetExceptionCode();
200 /* Return success or the error */
201 LPCTRACE(LPC_CREATE_DEBUG
, "Port: %p. Handle: %p\n", Port
, Handle
);
205 /* PUBLIC FUNCTIONS **********************************************************/
212 NtCreatePort(OUT PHANDLE PortHandle
,
213 IN POBJECT_ATTRIBUTES ObjectAttributes
,
214 IN ULONG MaxConnectInfoLength
,
215 IN ULONG MaxDataLength
,
216 IN ULONG MaxPoolUsage
)
220 /* Call the internal API */
221 return LpcpCreatePort(PortHandle
,
223 MaxConnectInfoLength
,
234 NtCreateWaitablePort(OUT PHANDLE PortHandle
,
235 IN POBJECT_ATTRIBUTES ObjectAttributes
,
236 IN ULONG MaxConnectInfoLength
,
237 IN ULONG MaxDataLength
,
238 IN ULONG MaxPoolUsage
)
242 /* Call the internal API */
243 return LpcpCreatePort(PortHandle
,
245 MaxConnectInfoLength
,