Sync to trunk revision 63857.
[reactos.git] / ntoskrnl / lpc / create.c
1 /*
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)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* PRIVATE FUNCTIONS *********************************************************/
16
17 NTSTATUS
18 NTAPI
19 LpcpInitializePortQueue(IN PLPCP_PORT_OBJECT Port)
20 {
21 PLPCP_NONPAGED_PORT_QUEUE MessageQueue;
22 PAGED_CODE();
23
24 /* Allocate the queue */
25 MessageQueue = ExAllocatePoolWithTag(NonPagedPool,
26 sizeof(LPCP_NONPAGED_PORT_QUEUE),
27 'troP');
28 if (!MessageQueue) return STATUS_INSUFFICIENT_RESOURCES;
29
30 /* Set it up */
31 KeInitializeSemaphore(&MessageQueue->Semaphore, 0, MAXLONG);
32 MessageQueue->BackPointer = Port;
33
34 /* And link it with the Paged Pool part */
35 Port->MsgQueue.Semaphore = &MessageQueue->Semaphore;
36 InitializeListHead(&Port->MsgQueue.ReceiveHead);
37 return STATUS_SUCCESS;
38 }
39
40 NTSTATUS
41 NTAPI
42 LpcpCreatePort(OUT PHANDLE PortHandle,
43 IN POBJECT_ATTRIBUTES ObjectAttributes,
44 IN ULONG MaxConnectionInfoLength,
45 IN ULONG MaxMessageLength,
46 IN ULONG MaxPoolUsage,
47 IN BOOLEAN Waitable)
48 {
49 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
50 NTSTATUS Status;
51 PLPCP_PORT_OBJECT Port;
52 HANDLE Handle;
53 PUNICODE_STRING ObjectName;
54 BOOLEAN NoName;
55 PAGED_CODE();
56 LPCTRACE(LPC_CREATE_DEBUG, "Name: %wZ\n", ObjectAttributes->ObjectName);
57
58 /* Check if the call comes from user mode */
59 if (PreviousMode != KernelMode)
60 {
61 _SEH2_TRY
62 {
63 /* Probe the PortHandle */
64 ProbeForWriteHandle(PortHandle);
65
66 /* Probe the ObjectAttributes */
67 ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
68
69 /* Get the object name and probe the unicode string */
70 ObjectName = ObjectAttributes->ObjectName;
71 ProbeForRead(ObjectName, sizeof(UNICODE_STRING), 1);
72
73 /* Check if we have no name */
74 NoName = (ObjectName->Buffer == NULL) || (ObjectName->Length == 0);
75 }
76 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
77 {
78 /* Return the exception code */
79 _SEH2_YIELD(return _SEH2_GetExceptionCode());
80 }
81 _SEH2_END;
82 }
83 else
84 {
85 /* Check if we have no name */
86 NoName = (ObjectAttributes->ObjectName->Buffer == NULL) ||
87 (ObjectAttributes->ObjectName->Length == 0);
88 }
89
90 /* Create the Object */
91 Status = ObCreateObject(PreviousMode,
92 LpcPortObjectType,
93 ObjectAttributes,
94 PreviousMode,
95 NULL,
96 sizeof(LPCP_PORT_OBJECT),
97 0,
98 0,
99 (PVOID*)&Port);
100 if (!NT_SUCCESS(Status)) return Status;
101
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);
108
109 /* Check if we don't have a name */
110 if (NoName)
111 {
112 /* Set up for an unconnected port */
113 Port->Flags = LPCP_UNCONNECTED_PORT;
114 Port->ConnectedPort = Port;
115 Port->ServerProcess = NULL;
116 }
117 else
118 {
119 /* Set up for a named connection port */
120 Port->Flags = LPCP_CONNECTION_PORT;
121 Port->ServerProcess = PsGetCurrentProcess();
122
123 /* Don't let the process die on us */
124 ObReferenceObject(Port->ServerProcess);
125 }
126
127 /* Check if this is a waitable port */
128 if (Waitable) Port->Flags |= LPCP_WAITABLE_PORT;
129
130 /* Setup the port queue */
131 Status = LpcpInitializePortQueue(Port);
132 if (!NT_SUCCESS(Status))
133 {
134 /* Fail */
135 ObDereferenceObject(Port);
136 return Status;
137 }
138
139 /* Check if this is a waitable port */
140 if (Port->Flags & LPCP_WAITABLE_PORT)
141 {
142 /* Setup the wait event */
143 KeInitializeEvent(&Port->WaitEvent, NotificationEvent, FALSE);
144 }
145
146 /* Set the maximum message size allowed */
147 Port->MaxMessageLength = LpcpMaxMessageSize -
148 FIELD_OFFSET(LPCP_MESSAGE, Request);
149
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);
154
155 /* Validate the sizes */
156 if (Port->MaxConnectionInfoLength < MaxConnectionInfoLength)
157 {
158 /* Not enough space for your request */
159 ObDereferenceObject(Port);
160 return STATUS_INVALID_PARAMETER_3;
161 }
162 else if (Port->MaxMessageLength < MaxMessageLength)
163 {
164 /* Not enough space for your request */
165 ObDereferenceObject(Port);
166 return STATUS_INVALID_PARAMETER_4;
167 }
168
169 /* Now set the custom setting */
170 Port->MaxMessageLength = MaxMessageLength;
171
172 /* Insert it now */
173 Status = ObInsertObject((PVOID)Port,
174 NULL,
175 PORT_ALL_ACCESS,
176 0,
177 NULL,
178 &Handle);
179 if (NT_SUCCESS(Status))
180 {
181 _SEH2_TRY
182 {
183 /* Write back the handle, pointer was already probed */
184 *PortHandle = Handle;
185 }
186 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
187 {
188 ObCloseHandle(Handle, UserMode);
189 Status = _SEH2_GetExceptionCode();
190 }
191 _SEH2_END;
192 }
193
194 /* Return success or the error */
195 LPCTRACE(LPC_CREATE_DEBUG, "Port: %p. Handle: %p\n", Port, Handle);
196 return Status;
197 }
198
199 /* PUBLIC FUNCTIONS **********************************************************/
200
201 /*
202 * @implemented
203 */
204 NTSTATUS
205 NTAPI
206 NtCreatePort(OUT PHANDLE PortHandle,
207 IN POBJECT_ATTRIBUTES ObjectAttributes,
208 IN ULONG MaxConnectInfoLength,
209 IN ULONG MaxDataLength,
210 IN ULONG MaxPoolUsage)
211 {
212 PAGED_CODE();
213
214 /* Call the internal API */
215 return LpcpCreatePort(PortHandle,
216 ObjectAttributes,
217 MaxConnectInfoLength,
218 MaxDataLength,
219 MaxPoolUsage,
220 FALSE);
221 }
222
223 /*
224 * @implemented
225 */
226 NTSTATUS
227 NTAPI
228 NtCreateWaitablePort(OUT PHANDLE PortHandle,
229 IN POBJECT_ATTRIBUTES ObjectAttributes,
230 IN ULONG MaxConnectInfoLength,
231 IN ULONG MaxDataLength,
232 IN ULONG MaxPoolUsage)
233 {
234 PAGED_CODE();
235
236 /* Call the internal API */
237 return LpcpCreatePort(PortHandle,
238 ObjectAttributes,
239 MaxConnectInfoLength,
240 MaxDataLength,
241 MaxPoolUsage,
242 TRUE);
243 }
244
245 /* EOF */