[FLTMGR] Latest from my branch (#135)
[reactos.git] / drivers / filters / fltmgr / Messaging.c
1 /*
2 * PROJECT: Filesystem Filter Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/filters/fltmgr/Messaging.c
5 * PURPOSE: Contains the routines to handle the comms layer
6 * PROGRAMMERS: Ged Murphy (gedmurphy@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "fltmgr.h"
12 #include "fltmgrint.h"
13 #include <fltmgr_shared.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18
19 /* DATA *********************************************************************/
20
21 UNICODE_STRING CommsDeviceName = RTL_CONSTANT_STRING(L"\\FileSystem\\Filters\\FltMgrMsg");
22 PDEVICE_OBJECT CommsDeviceObject;
23
24 POBJECT_TYPE ServerPortObjectType;
25 POBJECT_TYPE ClientPortObjectType;
26
27 static
28 BOOLEAN
29 FltpDisconnectPort(
30 _In_ PFLT_PORT_OBJECT PortObject
31 );
32
33 static
34 NTSTATUS
35 CreateClientPort(
36 _In_ PFILE_OBJECT FileObject,
37 _Inout_ PIRP Irp
38 );
39
40 static
41 NTSTATUS
42 CloseClientPort(
43 _In_ PFILE_OBJECT FileObject,
44 _Inout_ PIRP Irp
45 );
46
47 static
48 NTSTATUS
49 InitializeMessageWaiterQueue(
50 _Inout_ PFLT_MESSAGE_WAITER_QUEUE MsgWaiterQueue
51 );
52
53 static
54 PPORT_CCB
55 CreatePortCCB(
56 _In_ PFLT_PORT_OBJECT PortObject
57 );
58
59
60
61 /* EXPORTED FUNCTIONS ******************************************************/
62
63 _Must_inspect_result_
64 _IRQL_requires_max_(PASSIVE_LEVEL)
65 NTSTATUS
66 FLTAPI
67 FltCreateCommunicationPort(_In_ PFLT_FILTER Filter,
68 _Outptr_ PFLT_PORT *ServerPort,
69 _In_ POBJECT_ATTRIBUTES ObjectAttributes,
70 _In_opt_ PVOID ServerPortCookie,
71 _In_ PFLT_CONNECT_NOTIFY ConnectNotifyCallback,
72 _In_ PFLT_DISCONNECT_NOTIFY DisconnectNotifyCallback,
73 _In_opt_ PFLT_MESSAGE_NOTIFY MessageNotifyCallback,
74 _In_ LONG MaxConnections)
75 {
76 PFLT_SERVER_PORT_OBJECT PortObject;
77 NTSTATUS Status;
78
79 /* The caller must allow at least one connection */
80 if (MaxConnections == 0)
81 {
82 return STATUS_INVALID_PARAMETER;
83 }
84
85 /* The request must be for a kernel handle */
86 if (!(ObjectAttributes->Attributes & OBJ_KERNEL_HANDLE))
87 {
88 return STATUS_INVALID_PARAMETER;
89 }
90
91 /*
92 * Get rundown protection on the target to stop the owner
93 * from unloading whilst this port object is open. It gets
94 * removed in the FltpServerPortClose callback
95 */
96 Status = FltObjectReference(Filter);
97 if (!NT_SUCCESS(Status))
98 {
99 return Status;
100 }
101
102 /* Create the server port object for this filter */
103 Status = ObCreateObject(KernelMode,
104 ServerPortObjectType,
105 ObjectAttributes,
106 KernelMode,
107 NULL,
108 sizeof(FLT_SERVER_PORT_OBJECT),
109 0,
110 0,
111 (PVOID *)&PortObject);
112 if (NT_SUCCESS(Status))
113 {
114 /* Zero out the struct */
115 RtlZeroMemory(PortObject, sizeof(FLT_SERVER_PORT_OBJECT));
116
117 /* Increment the ref count on the target filter */
118 FltpObjectPointerReference((PFLT_OBJECT)Filter);
119
120 /* Setup the filter port object */
121 PortObject->Filter = Filter;
122 PortObject->ConnectNotify = ConnectNotifyCallback;
123 PortObject->DisconnectNotify = DisconnectNotifyCallback;
124 PortObject->MessageNotify = MessageNotifyCallback;
125 PortObject->Cookie = ServerPortCookie;
126 PortObject->MaxConnections = MaxConnections;
127
128 /* Insert the object */
129 Status = ObInsertObject(PortObject,
130 NULL,
131 STANDARD_RIGHTS_ALL | FILE_READ_DATA,
132 0,
133 NULL,
134 (PHANDLE)ServerPort);
135 if (NT_SUCCESS(Status))
136 {
137 /* Lock the connection list */
138 ExAcquireFastMutex(&Filter->ConnectionList.mLock);
139
140 /* Add the new port object to the connection list and increment the count */
141 InsertTailList(&Filter->ConnectionList.mList, &PortObject->FilterLink);
142 Filter->ConnectionList.mCount++;
143
144 /* Unlock the connection list*/
145 ExReleaseFastMutex(&Filter->ConnectionList.mLock);
146 }
147 }
148
149 if (!NT_SUCCESS(Status))
150 {
151 /* Allow the filter to be cleaned up */
152 FltObjectDereference(Filter);
153 }
154
155 return Status;
156 }
157
158 _IRQL_requires_max_(PASSIVE_LEVEL)
159 VOID
160 FLTAPI
161 FltCloseCommunicationPort(_In_ PFLT_PORT ServerPort)
162 {
163 /* Just close the handle to initiate the cleanup callbacks */
164 ZwClose(ServerPort);
165 }
166
167 _IRQL_requires_max_(PASSIVE_LEVEL)
168 VOID
169 FLTAPI
170 FltCloseClientPort(_In_ PFLT_FILTER Filter,
171 _Inout_ PFLT_PORT *ClientPort)
172 {
173 PFLT_PORT Port;
174
175 /* Protect against the handle being used whilst we're closing it */
176 FltAcquirePushLockShared(&Filter->PortLock);
177
178 /* Store the port handle while we have the lock held */
179 Port = *ClientPort;
180
181 if (*ClientPort)
182 {
183 /* Set the hadle to null */
184 *ClientPort = NULL;
185 }
186
187 /* Unlock the port */
188 FltReleasePushLock(&Filter->PortLock);
189
190 if (Port)
191 {
192 /* Close the safe handle */
193 ZwClose(Port);
194 }
195 }
196
197 _Must_inspect_result_
198 _IRQL_requires_max_(APC_LEVEL)
199 NTSTATUS
200 FLTAPI
201 FltSendMessage(_In_ PFLT_FILTER Filter,
202 _In_ PFLT_PORT *ClientPort,
203 _In_reads_bytes_(SenderBufferLength) PVOID SenderBuffer,
204 _In_ ULONG SenderBufferLength,
205 _Out_writes_bytes_opt_(*ReplyLength) PVOID ReplyBuffer,
206 _Inout_opt_ PULONG ReplyLength,
207 _In_opt_ PLARGE_INTEGER Timeout)
208 {
209 UNREFERENCED_PARAMETER(Filter);
210 UNREFERENCED_PARAMETER(ClientPort);
211 UNREFERENCED_PARAMETER(SenderBuffer);
212 UNREFERENCED_PARAMETER(SenderBufferLength);
213 UNREFERENCED_PARAMETER(ReplyBuffer);
214 UNREFERENCED_PARAMETER(ReplyLength);
215 UNREFERENCED_PARAMETER(Timeout);
216 return STATUS_NOT_IMPLEMENTED;
217 }
218
219 /* INTERNAL FUNCTIONS ******************************************************/
220
221
222 NTSTATUS
223 FltpMsgCreate(_In_ PDEVICE_OBJECT DeviceObject,
224 _Inout_ PIRP Irp)
225 {
226 PIO_STACK_LOCATION StackPtr;
227 NTSTATUS Status;
228
229 /* Get the stack location */
230 StackPtr = IoGetCurrentIrpStackLocation(Irp);
231
232 FLT_ASSERT(StackPtr->MajorFunction == IRP_MJ_CREATE);
233
234 /* Check if this is a caller wanting to connect */
235 if (StackPtr->MajorFunction == IRP_MJ_CREATE)
236 {
237 /* Create the client port for this connection and exit */
238 Status = CreateClientPort(StackPtr->FileObject, Irp);
239 }
240 else
241 {
242 Status = STATUS_INVALID_PARAMETER;
243 }
244
245 if (Status != STATUS_PENDING)
246 {
247 Irp->IoStatus.Status = Status;
248 Irp->IoStatus.Information = 0;
249 IoCompleteRequest(Irp, 0);
250 }
251
252 return Status;
253 }
254
255 NTSTATUS
256 FltpMsgDispatch(_In_ PDEVICE_OBJECT DeviceObject,
257 _Inout_ PIRP Irp)
258 {
259 PIO_STACK_LOCATION StackPtr;
260 NTSTATUS Status;
261
262 /* Get the stack location */
263 StackPtr = IoGetCurrentIrpStackLocation(Irp);
264
265 /* Check if this is a caller wanting to connect */
266 if (StackPtr->MajorFunction == IRP_MJ_CLOSE)
267 {
268 /* Create the client port for this connection and exit */
269 Status = CloseClientPort(StackPtr->FileObject, Irp);
270 }
271 else
272 {
273 // We don't support anything else yet
274 Status = STATUS_NOT_IMPLEMENTED;
275 }
276
277 if (Status != STATUS_PENDING)
278 {
279 Irp->IoStatus.Status = Status;
280 Irp->IoStatus.Information = 0;
281 IoCompleteRequest(Irp, 0);
282 }
283
284 return Status;
285 }
286
287 VOID
288 NTAPI
289 FltpServerPortClose(_In_opt_ PEPROCESS Process,
290 _In_ PVOID Object,
291 _In_ ACCESS_MASK GrantedAccess,
292 _In_ ULONG ProcessHandleCount,
293 _In_ ULONG SystemHandleCount)
294 {
295 PFLT_SERVER_PORT_OBJECT PortObject;
296 PFAST_MUTEX Lock;
297
298 /* Cast the object to a server port object */
299 PortObject = (PFLT_SERVER_PORT_OBJECT)Object;
300
301 /* Lock the connection list */
302 Lock = &PortObject->Filter->ConnectionList.mLock;
303 ExAcquireFastMutex(Lock);
304
305 /* Remove the server port object from the list */
306 RemoveEntryList(&PortObject->FilterLink);
307
308 /* Unlock the connection list */
309 ExReleaseFastMutex(Lock);
310
311 /* Remove the rundown protection we added to stop the owner from tearing us down */
312 FltObjectDereference(PortObject->Filter);
313 }
314
315 VOID
316 NTAPI
317 FltpServerPortDelete(PVOID Object)
318 {
319 /* Decrement the filter count we added in the create routine */
320 PFLT_SERVER_PORT_OBJECT PortObject = (PFLT_SERVER_PORT_OBJECT)Object;
321 FltpObjectPointerDereference((PFLT_OBJECT)PortObject->Filter);
322
323 }
324
325 VOID
326 NTAPI
327 FltpClientPortClose(_In_opt_ PEPROCESS Process,
328 _In_ PVOID Object,
329 _In_ ACCESS_MASK GrantedAccess,
330 _In_ ULONG ProcessHandleCount,
331 _In_ ULONG SystemHandleCount)
332 {
333 PFLT_PORT_OBJECT PortObject = (PFLT_PORT_OBJECT)Object;
334
335 if (FltpDisconnectPort(PortObject))
336 {
337 InterlockedDecrement(&PortObject->ServerPort->NumberOfConnections);
338 }
339 }
340
341 BOOLEAN
342 FltpDisconnectPort(_In_ PFLT_PORT_OBJECT PortObject)
343 {
344 BOOLEAN Disconnected = FALSE;
345
346 /* Lock the port object while we disconnect it */
347 ExAcquireFastMutex(&PortObject->Lock);
348
349 /* Make sure we have a valid connection */
350 if (PortObject->Disconnected == FALSE)
351 {
352 /* Let any waiters know we're dusconnecing */
353 KeSetEvent(&PortObject->DisconnectEvent, 0, 0);
354
355 // cleanup everything in the message queue (PortObject->MsgQ.Csq)
356
357 /* Set the disconnected state to true */
358 PortObject->Disconnected = TRUE;
359 Disconnected = TRUE;
360 }
361
362 /* Unlock and exit*/
363 ExReleaseFastMutex(&PortObject->Lock);
364 return Disconnected;
365 }
366
367 VOID
368 NTAPI
369 FltpClientPortDelete(PVOID Object)
370 {
371 PFLT_PORT_OBJECT PortObject = (PFLT_PORT_OBJECT)Object;
372 ObfDereferenceObject(PortObject->ServerPort);
373 }
374
375
376 NTSTATUS
377 FltpSetupCommunicationObjects(_In_ PDRIVER_OBJECT DriverObject)
378 {
379 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
380 UNICODE_STRING SymLinkName;
381 UNICODE_STRING Name;
382 NTSTATUS Status;
383
384 GENERIC_MAPPING Mapping =
385 {
386 STANDARD_RIGHTS_READ,
387 STANDARD_RIGHTS_WRITE,
388 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
389 FLT_PORT_ALL_ACCESS
390 };
391
392 /* Create the server comms object type */
393 RtlZeroMemory(&ObjectTypeInitializer, sizeof(OBJECT_TYPE_INITIALIZER));
394 RtlInitUnicodeString(&Name, L"FilterConnectionPort");
395 ObjectTypeInitializer.Length = sizeof(OBJECT_TYPE_INITIALIZER);
396 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
397 ObjectTypeInitializer.GenericMapping = Mapping;
398 ObjectTypeInitializer.PoolType = NonPagedPool;
399 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(FLT_SERVER_PORT_OBJECT);
400 ObjectTypeInitializer.ValidAccessMask = GENERIC_ALL;
401 ObjectTypeInitializer.CloseProcedure = FltpServerPortClose;
402 ObjectTypeInitializer.DeleteProcedure = FltpServerPortDelete;
403 Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ServerPortObjectType);
404 if (!NT_SUCCESS(Status)) return Status;
405
406 /* Create the client comms object type */
407 RtlZeroMemory(&ObjectTypeInitializer, sizeof(OBJECT_TYPE_INITIALIZER));
408 RtlInitUnicodeString(&Name, L"FilterCommunicationPort");
409 ObjectTypeInitializer.Length = sizeof(OBJECT_TYPE_INITIALIZER);
410 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
411 ObjectTypeInitializer.GenericMapping = Mapping;
412 ObjectTypeInitializer.PoolType = NonPagedPool;
413 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(FLT_PORT_OBJECT);
414 ObjectTypeInitializer.ValidAccessMask = GENERIC_ALL;
415 ObjectTypeInitializer.CloseProcedure = FltpClientPortClose;
416 ObjectTypeInitializer.DeleteProcedure = FltpClientPortDelete;
417 Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ClientPortObjectType);
418 if (!NT_SUCCESS(Status))
419 {
420 goto Quit;
421 }
422
423 /* Create the device object */
424 Status = IoCreateDevice(DriverObject,
425 0,
426 &CommsDeviceName,
427 FILE_DEVICE_WPD,
428 0,
429 0,
430 &CommsDeviceObject);
431 if (NT_SUCCESS(Status))
432 {
433 /* Setup a symbolic link for the device */
434 RtlInitUnicodeString(&SymLinkName, L"\\DosDevices\\FltMgrMsg");
435 Status = IoCreateSymbolicLink(&SymLinkName, &CommsDeviceName);
436 }
437
438 Quit:
439 if (!NT_SUCCESS(Status))
440 {
441 /* Something went wrong, undo */
442 if (CommsDeviceObject)
443 {
444 IoDeleteDevice(CommsDeviceObject);
445 CommsDeviceObject = NULL;
446 }
447 if (ClientPortObjectType)
448 {
449 ObMakeTemporaryObject(ClientPortObjectType);
450 ObfDereferenceObject(ClientPortObjectType);
451 ClientPortObjectType = NULL;
452 }
453
454 if (ServerPortObjectType)
455 {
456 ObMakeTemporaryObject(ServerPortObjectType);
457 ObfDereferenceObject(ServerPortObjectType);
458 ServerPortObjectType = NULL;
459 }
460 }
461
462 return Status;
463 }
464
465 /* CSQ IRP CALLBACKS *******************************************************/
466
467
468 NTSTATUS
469 NTAPI
470 FltpAddMessageWaiter(_In_ PIO_CSQ Csq,
471 _In_ PIRP Irp,
472 _In_ PVOID InsertContext)
473 {
474 PFLT_MESSAGE_WAITER_QUEUE MessageWaiterQueue;
475
476 /* Get the start of the waiter queue struct */
477 MessageWaiterQueue = CONTAINING_RECORD(Csq,
478 FLT_MESSAGE_WAITER_QUEUE,
479 Csq);
480
481 /* Insert the IRP at the end of the queue */
482 InsertTailList(&MessageWaiterQueue->WaiterQ.mList,
483 &Irp->Tail.Overlay.ListEntry);
484
485 /* return success */
486 return STATUS_SUCCESS;
487 }
488
489 VOID
490 NTAPI
491 FltpRemoveMessageWaiter(_In_ PIO_CSQ Csq,
492 _In_ PIRP Irp)
493 {
494 /* Remove the IRP from the queue */
495 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
496 }
497
498 PIRP
499 NTAPI
500 FltpGetNextMessageWaiter(_In_ PIO_CSQ Csq,
501 _In_ PIRP Irp,
502 _In_ PVOID PeekContext)
503 {
504 PFLT_MESSAGE_WAITER_QUEUE MessageWaiterQueue;
505 PIRP NextIrp = NULL;
506 PLIST_ENTRY NextEntry;
507 PIO_STACK_LOCATION IrpStack;
508
509 /* Get the start of the waiter queue struct */
510 MessageWaiterQueue = CONTAINING_RECORD(Csq,
511 FLT_MESSAGE_WAITER_QUEUE,
512 Csq);
513
514 /* Is the IRP valid? */
515 if (Irp == NULL)
516 {
517 /* Start peeking from the listhead */
518 NextEntry = MessageWaiterQueue->WaiterQ.mList.Flink;
519 }
520 else
521 {
522 /* Start peeking from that IRP onwards */
523 NextEntry = Irp->Tail.Overlay.ListEntry.Flink;
524 }
525
526 /* Loop through the queue */
527 while (NextEntry != &MessageWaiterQueue->WaiterQ.mList)
528 {
529 /* Store the next IRP in the list */
530 NextIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
531
532 /* Did we supply a PeekContext on insert? */
533 if (!PeekContext)
534 {
535 /* We already have the next IRP */
536 break;
537 }
538 else
539 {
540 /* Get the stack of the next IRP */
541 IrpStack = IoGetCurrentIrpStackLocation(NextIrp);
542
543 /* Does the PeekContext match the object? */
544 if (IrpStack->FileObject == (PFILE_OBJECT)PeekContext)
545 {
546 /* We have a match */
547 break;
548 }
549
550 /* Move to the next IRP */
551 NextIrp = NULL;
552 NextEntry = NextEntry->Flink;
553 }
554 }
555
556 return NextIrp;
557 }
558
559 _Acquires_lock_(((PFLT_MESSAGE_WAITER_QUEUE)CONTAINING_RECORD(Csq, FLT_MESSAGE_WAITER_QUEUE, Csq))->WaiterQ.mLock)
560 _IRQL_saves_global_(Irql, ((PFLT_MESSAGE_WAITER_QUEUE)CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue))->WaiterQ.mLock)
561 _IRQL_raises_(DISPATCH_LEVEL)
562 VOID
563 NTAPI
564 FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq,
565 _Out_ PKIRQL Irql)
566 {
567 PFLT_MESSAGE_WAITER_QUEUE MessageWaiterQueue;
568
569 UNREFERENCED_PARAMETER(Irql);
570
571 /* Get the start of the waiter queue struct */
572 MessageWaiterQueue = CONTAINING_RECORD(Csq,
573 FLT_MESSAGE_WAITER_QUEUE,
574 Csq);
575
576 /* Acquire the IRP queue lock */
577 ExAcquireFastMutex(&MessageWaiterQueue->WaiterQ.mLock);
578 }
579
580 _Releases_lock_(((PFLT_MESSAGE_WAITER_QUEUE)CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue))->WaiterQ.mLock)
581 _IRQL_restores_global_(Irql, ((PFLT_MESSAGE_WAITER_QUEUE)CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue))->WaiterQ.mLock)
582 _IRQL_requires_(DISPATCH_LEVEL)
583 VOID
584 NTAPI
585 FltpReleaseMessageWaiterLock(_In_ PIO_CSQ Csq,
586 _In_ KIRQL Irql)
587 {
588 PFLT_MESSAGE_WAITER_QUEUE MessageWaiterQueue;
589
590 UNREFERENCED_PARAMETER(Irql);
591
592 /* Get the start of the waiter queue struct */
593 MessageWaiterQueue = CONTAINING_RECORD(Csq,
594 FLT_MESSAGE_WAITER_QUEUE,
595 Csq);
596
597 /* Release the IRP queue lock */
598 ExReleaseFastMutex(&MessageWaiterQueue->WaiterQ.mLock);
599 }
600
601 VOID
602 NTAPI
603 FltpCancelMessageWaiter(_In_ PIO_CSQ Csq,
604 _In_ PIRP Irp)
605 {
606 /* Cancel the IRP */
607 Irp->IoStatus.Status = STATUS_CANCELLED;
608 Irp->IoStatus.Information = 0;
609 IoCompleteRequest(Irp, IO_NO_INCREMENT);
610 }
611
612
613 /* PRIVATE FUNCTIONS ******************************************************/
614
615 static
616 NTSTATUS
617 CreateClientPort(_In_ PFILE_OBJECT FileObject,
618 _Inout_ PIRP Irp)
619 {
620 PFLT_SERVER_PORT_OBJECT ServerPortObject = NULL;
621 OBJECT_ATTRIBUTES ObjectAttributes;
622 PFILTER_PORT_DATA FilterPortData;
623 PFLT_PORT_OBJECT ClientPortObject = NULL;
624 PFLT_PORT PortHandle = NULL;
625 PPORT_CCB PortCCB = NULL;
626 //ULONG BufferLength;
627 LONG NumConns;
628 NTSTATUS Status;
629
630 /* We received the buffer via FilterConnectCommunicationPort, cast it back to its original form */
631 FilterPortData = Irp->AssociatedIrp.SystemBuffer;
632
633 /* Get a reference to the server port the filter created */
634 Status = ObReferenceObjectByName(&FilterPortData->PortName,
635 0,
636 0,
637 FLT_PORT_ALL_ACCESS,
638 ServerPortObjectType,
639 ExGetPreviousMode(),
640 0,
641 (PVOID *)&ServerPortObject);
642 if (!NT_SUCCESS(Status))
643 {
644 return Status;
645 }
646
647 /* Increment the number of connections on the server port */
648 NumConns = InterlockedIncrement(&ServerPortObject->NumberOfConnections);
649 if (NumConns > ServerPortObject->MaxConnections)
650 {
651 Status = STATUS_CONNECTION_COUNT_LIMIT;
652 goto Quit;
653 }
654
655 /* Initialize a basic kernel handle request */
656 InitializeObjectAttributes(&ObjectAttributes,
657 NULL,
658 OBJ_KERNEL_HANDLE,
659 NULL,
660 NULL);
661
662 /* Now create the new client port object */
663 Status = ObCreateObject(KernelMode,
664 ClientPortObjectType,
665 &ObjectAttributes,
666 KernelMode,
667 NULL,
668 sizeof(FLT_PORT_OBJECT),
669 0,
670 0,
671 (PVOID *)&ClientPortObject);
672 if (!NT_SUCCESS(Status))
673 {
674 goto Quit;
675 }
676
677 /* Clear out the buffer */
678 RtlZeroMemory(ClientPortObject, sizeof(FLT_PORT_OBJECT));
679
680 /* Initialize the locks */
681 ExInitializeRundownProtection(&ClientPortObject->MsgNotifRundownRef);
682 ExInitializeFastMutex(&ClientPortObject->Lock);
683
684 /* Set the server port object this belongs to */
685 ClientPortObject->ServerPort = ServerPortObject;
686
687 /* Setup the message queue */
688 Status = InitializeMessageWaiterQueue(&ClientPortObject->MsgQ);
689 if (!NT_SUCCESS(Status))
690 {
691 goto Quit;
692 }
693
694 /* Create the CCB which we'll attach to the file object */
695 PortCCB = CreatePortCCB(ClientPortObject);
696 if (PortCCB == NULL)
697 {
698 Status = STATUS_INSUFFICIENT_RESOURCES;
699 goto Quit;
700 }
701
702 /* Now insert the new client port into the object manager*/
703 Status = ObInsertObject(ClientPortObject, 0, FLT_PORT_ALL_ACCESS, 1, 0, (PHANDLE)&PortHandle);
704 if (!NT_SUCCESS(Status))
705 {
706 goto Quit;
707 }
708
709 /* Add a reference to the filter to keep it alive while we do some work with it */
710 Status = FltObjectReference(ServerPortObject->Filter);
711 if (NT_SUCCESS(Status))
712 {
713 /* Invoke the callback to let the filter know we have a connection */
714 Status = ServerPortObject->ConnectNotify(PortHandle,
715 ServerPortObject->Cookie,
716 NULL, //ConnectionContext
717 0, //SizeOfContext
718 &ClientPortObject->Cookie);
719 if (NT_SUCCESS(Status))
720 {
721 /* Add the client port CCB to the file object */
722 FileObject->FsContext2 = PortCCB;
723
724 /* Lock the port list on the filter and add this new port object to the list */
725 ExAcquireFastMutex(&ServerPortObject->Filter->PortList.mLock);
726 InsertTailList(&ServerPortObject->Filter->PortList.mList, &ClientPortObject->FilterLink);
727 ExReleaseFastMutex(&ServerPortObject->Filter->PortList.mLock);
728 }
729
730 /* We're done with the filter object, decremement the count */
731 FltObjectDereference(ServerPortObject->Filter);
732 }
733
734
735 Quit:
736 if (!NT_SUCCESS(Status))
737 {
738 if (ClientPortObject)
739 {
740 ObfDereferenceObject(ClientPortObject);
741 }
742
743 if (PortHandle)
744 {
745 ZwClose(PortHandle);
746 }
747 else if (ServerPortObject)
748 {
749 InterlockedDecrement(&ServerPortObject->NumberOfConnections);
750 ObfDereferenceObject(ServerPortObject);
751 }
752
753 if (PortCCB)
754 {
755 ExFreePoolWithTag(PortCCB, FM_TAG_CCB);
756 }
757 }
758
759 return Status;
760 }
761
762 static
763 NTSTATUS
764 CloseClientPort(_In_ PFILE_OBJECT FileObject,
765 _Inout_ PIRP Irp)
766 {
767 PFLT_CCB Ccb;
768
769 Ccb = (PFLT_CCB)FileObject->FsContext2;
770
771 /* Remove the reference on the filter we added when we opened the port */
772 ObDereferenceObject(Ccb->Data.Port.Port);
773
774 // FIXME: Free the CCB
775
776 return STATUS_SUCCESS;
777 }
778
779 static
780 NTSTATUS
781 InitializeMessageWaiterQueue(_Inout_ PFLT_MESSAGE_WAITER_QUEUE MsgWaiterQueue)
782 {
783 NTSTATUS Status;
784
785 /* Setup the IRP queue */
786 Status = IoCsqInitializeEx(&MsgWaiterQueue->Csq,
787 FltpAddMessageWaiter,
788 FltpRemoveMessageWaiter,
789 FltpGetNextMessageWaiter,
790 FltpAcquireMessageWaiterLock,
791 FltpReleaseMessageWaiterLock,
792 FltpCancelMessageWaiter);
793 if (!NT_SUCCESS(Status))
794 {
795 return Status;
796 }
797
798 /* Initialize the waiter queue */
799 ExInitializeFastMutex(&MsgWaiterQueue->WaiterQ.mLock);
800 InitializeListHead(&MsgWaiterQueue->WaiterQ.mList);
801 MsgWaiterQueue->WaiterQ.mCount = 0;
802
803 /* We don't have a minimum waiter length */
804 MsgWaiterQueue->MinimumWaiterLength = (ULONG)-1;
805
806 /* Init the semaphore and event used for counting and signaling available IRPs */
807 KeInitializeSemaphore(&MsgWaiterQueue->Semaphore, 0, MAXLONG);
808 KeInitializeEvent(&MsgWaiterQueue->Event, NotificationEvent, FALSE);
809
810 return STATUS_SUCCESS;
811 }
812
813 static
814 PPORT_CCB
815 CreatePortCCB(_In_ PFLT_PORT_OBJECT PortObject)
816 {
817 PPORT_CCB PortCCB;
818
819 /* Allocate a CCB struct to hold the client port object info */
820 PortCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(PPORT_CCB), FM_TAG_CCB);
821 if (PortCCB)
822 {
823 /* Initialize the structure */
824 PortCCB->Port = PortObject;
825 PortCCB->ReplyWaiterList.mCount = 0;
826 ExInitializeFastMutex(&PortCCB->ReplyWaiterList.mLock);
827 KeInitializeEvent(&PortCCB->ReplyWaiterList.mLock.Event, SynchronizationEvent, 0);
828 }
829
830 return PortCCB;
831 }