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
;
24 /* Allocate the queue */
25 MessageQueue
= ExAllocatePoolWithTag(NonPagedPool
,
26 sizeof(LPCP_NONPAGED_PORT_QUEUE
),
28 if (!MessageQueue
) return STATUS_INSUFFICIENT_RESOURCES
;
31 KeInitializeSemaphore(&MessageQueue
->Semaphore
, 0, MAXLONG
);
32 MessageQueue
->BackPointer
= Port
;
34 /* And link it with the Paged Pool part */
35 Port
->MsgQueue
.Semaphore
= &MessageQueue
->Semaphore
;
36 InitializeListHead(&Port
->MsgQueue
.ReceiveHead
);
37 return STATUS_SUCCESS
;
42 LpcpCreatePort(OUT PHANDLE PortHandle
,
43 IN POBJECT_ATTRIBUTES ObjectAttributes
,
44 IN ULONG MaxConnectionInfoLength
,
45 IN ULONG MaxMessageLength
,
46 IN ULONG MaxPoolUsage
,
49 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
51 PLPCP_PORT_OBJECT Port
;
53 PUNICODE_STRING ObjectName
;
56 LPCTRACE(LPC_CREATE_DEBUG
, "Name: %wZ\n", ObjectAttributes
->ObjectName
);
58 /* Check if the call comes from user mode */
59 if (PreviousMode
!= KernelMode
)
63 /* Probe the PortHandle */
64 ProbeForWriteHandle(PortHandle
);
66 /* Probe the ObjectAttributes */
67 ProbeForRead(ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), sizeof(ULONG
));
69 /* Get the object name and probe the unicode string */
70 ObjectName
= ObjectAttributes
->ObjectName
;
71 ProbeForRead(ObjectName
, sizeof(UNICODE_STRING
), 1);
73 /* Check if we have no name */
74 NoName
= (ObjectName
->Buffer
== NULL
) || (ObjectName
->Length
== 0);
76 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
78 /* Return the exception code */
79 _SEH2_YIELD(return _SEH2_GetExceptionCode());
85 /* Check if we have no name */
86 NoName
= (ObjectAttributes
->ObjectName
->Buffer
== NULL
) ||
87 (ObjectAttributes
->ObjectName
->Length
== 0);
90 /* Create the Object */
91 Status
= ObCreateObject(PreviousMode
,
96 sizeof(LPCP_PORT_OBJECT
),
100 if (!NT_SUCCESS(Status
)) return Status
;
102 /* Set up the Object */
103 RtlZeroMemory(Port
, sizeof(LPCP_PORT_OBJECT
));
104 Port
->ConnectionPort
= Port
;
105 Port
->Creator
= PsGetCurrentThread()->Cid
;
106 InitializeListHead(&Port
->LpcDataInfoChainHead
);
107 InitializeListHead(&Port
->LpcReplyChainHead
);
109 /* Check if we don't have a name */
112 /* Set up for an unconnected port */
113 Port
->Flags
= LPCP_UNCONNECTED_PORT
;
114 Port
->ConnectedPort
= Port
;
115 Port
->ServerProcess
= NULL
;
119 /* Set up for a named connection port */
120 Port
->Flags
= LPCP_CONNECTION_PORT
;
121 Port
->ServerProcess
= PsGetCurrentProcess();
123 /* Don't let the process die on us */
124 ObReferenceObject(Port
->ServerProcess
);
127 /* Check if this is a waitable port */
128 if (Waitable
) Port
->Flags
|= LPCP_WAITABLE_PORT
;
130 /* Setup the port queue */
131 Status
= LpcpInitializePortQueue(Port
);
132 if (!NT_SUCCESS(Status
))
135 ObDereferenceObject(Port
);
139 /* Check if this is a waitable port */
140 if (Port
->Flags
& LPCP_WAITABLE_PORT
)
142 /* Setup the wait event */
143 KeInitializeEvent(&Port
->WaitEvent
, NotificationEvent
, FALSE
);
146 /* Set the maximum message size allowed */
147 Port
->MaxMessageLength
= LpcpMaxMessageSize
-
148 FIELD_OFFSET(LPCP_MESSAGE
, Request
);
150 /* Now subtract the actual message structures and get the data size */
151 Port
->MaxConnectionInfoLength
= Port
->MaxMessageLength
-
152 sizeof(PORT_MESSAGE
) -
153 sizeof(LPCP_CONNECTION_MESSAGE
);
155 /* Validate the sizes */
156 if (Port
->MaxConnectionInfoLength
< MaxConnectionInfoLength
)
158 /* Not enough space for your request */
159 ObDereferenceObject(Port
);
160 return STATUS_INVALID_PARAMETER_3
;
162 else if (Port
->MaxMessageLength
< MaxMessageLength
)
164 /* Not enough space for your request */
165 ObDereferenceObject(Port
);
166 return STATUS_INVALID_PARAMETER_4
;
169 /* Now set the custom setting */
170 Port
->MaxMessageLength
= MaxMessageLength
;
173 Status
= ObInsertObject((PVOID
)Port
,
179 if (NT_SUCCESS(Status
))
183 /* Write back the handle, pointer was already probed */
184 *PortHandle
= Handle
;
186 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
188 ObCloseHandle(Handle
, UserMode
);
189 Status
= _SEH2_GetExceptionCode();
194 /* Return success or the error */
195 LPCTRACE(LPC_CREATE_DEBUG
, "Port: %p. Handle: %p\n", Port
, Handle
);
199 /* PUBLIC FUNCTIONS **********************************************************/
206 NtCreatePort(OUT PHANDLE PortHandle
,
207 IN POBJECT_ATTRIBUTES ObjectAttributes
,
208 IN ULONG MaxConnectInfoLength
,
209 IN ULONG MaxDataLength
,
210 IN ULONG MaxPoolUsage
)
214 /* Call the internal API */
215 return LpcpCreatePort(PortHandle
,
217 MaxConnectInfoLength
,
228 NtCreateWaitablePort(OUT PHANDLE PortHandle
,
229 IN POBJECT_ATTRIBUTES ObjectAttributes
,
230 IN ULONG MaxConnectInfoLength
,
231 IN ULONG MaxDataLength
,
232 IN ULONG MaxPoolUsage
)
236 /* Call the internal API */
237 return LpcpCreatePort(PortHandle
,
239 MaxConnectInfoLength
,