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 ObDereferenceObject(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 ObDereferenceObject(ClientPortObjectType); 451 ClientPortObjectType = NULL; 452 } 453 454 if (ServerPortObjectType) 455 { 456 ObMakeTemporaryObject(ServerPortObjectType); 457 ObDereferenceObject(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 ObDereferenceObject(ClientPortObject); 741 } 742 743 if (PortHandle) 744 { 745 ZwClose(PortHandle); 746 } 747 else if (ServerPortObject) 748 { 749 InterlockedDecrement(&ServerPortObject->NumberOfConnections); 750 ObDereferenceObject(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(PORT_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 } 832