/*++ Copyright (c) 1989 Microsoft Corporation Module Name: RxConnct.c Abstract: This module implements the nt version of the high level routines dealing with connections including both the routines for establishing connections and the winnet connection apis. Author: Joe Linn [JoeLinn] 1-mar-95 Revision History: Balan Sethu Raman [SethuR] -- --*/ #include "precomp.h" #pragma hdrstop #include "prefix.h" #include "secext.h" #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, RxExtractServerName) #pragma alloc_text(PAGE, RxFindOrCreateConnections) #pragma alloc_text(PAGE, RxCreateNetRootCallBack) #pragma alloc_text(PAGE, RxConstructSrvCall) #pragma alloc_text(PAGE, RxConstructNetRoot) #pragma alloc_text(PAGE, RxConstructVirtualNetRoot) #pragma alloc_text(PAGE, RxFindOrConstructVirtualNetRoot) #endif // // The local trace mask for this part of the module // #define Dbg (DEBUG_TRACE_CONNECT) // Internal helper functions for establishing connections through mini redirectors VOID RxCreateNetRootCallBack ( IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext ); VOID RxCreateSrvCallCallBack ( IN PMRX_SRVCALL_CALLBACK_CONTEXT Context ); VOID RxExtractServerName( IN PUNICODE_STRING FilePathName, OUT PUNICODE_STRING SrvCallName, OUT PUNICODE_STRING RestOfName ) /*++ Routine Description: This routine parses the input name into srv, netroot, and the rest. any of the output can be null Arguments: FilePathName -- the given file name xSrvCallName -- the srv call name xNetRootName -- the net root name RestOfName -- the remaining portion of the name --*/ { ULONG length = FilePathName->Length; PWCH w = FilePathName->Buffer; PWCH wlimit = (PWCH)(((PCHAR)w)+length); PWCH wlow; UNICODE_STRING xRestOfName; PAGED_CODE(); ASSERT(SrvCallName); SrvCallName->Buffer = wlow = w; for (;;) { if (w>=wlimit) break; if ( (*w == OBJ_NAME_PATH_SEPARATOR) && (w!=wlow) ) break; w++; } SrvCallName->Length = SrvCallName->MaximumLength = (USHORT)((PCHAR)w - (PCHAR)wlow); if (!RestOfName) RestOfName = &xRestOfName; RestOfName->Buffer = w; RestOfName->Length = RestOfName->MaximumLength = (USHORT)((PCHAR)wlimit - (PCHAR)w); RxDbgTrace( 0,Dbg,(" RxExtractServerName FilePath=%wZ\n",FilePathName)); RxDbgTrace(0,Dbg,(" Srv=%wZ,Rest=%wZ\n", SrvCallName,RestOfName)); return; } NTSTATUS RxFindOrCreateConnections ( IN PRX_CONTEXT RxContext, IN PUNICODE_STRING CanonicalName, IN NET_ROOT_TYPE NetRootType, OUT PUNICODE_STRING LocalNetRootName, OUT PUNICODE_STRING FilePathName, IN OUT LOCK_HOLDING_STATE *pLockHoldingState, IN PRX_CONNECTION_ID RxConnectionId ) /*++ Routine Description: This routine handles the call down from the MUP to claim a name or from the create path. If we don't find the name in the netname table, we pass the name down to the minirdrs to be connected. in the few places where it matters, we use the majorcode to distinguish between in MUP and create cases. there are a million cases depending on what we find on the initial lookup. these are the cases: found nothing (1) found intransition srvcall (2) found stable/nongood srvcall (3) found good srvcall (4&0) found good netroot on good srvcall (0) found intransition netroot on good srvcall (5) found bad netroot on good srvcall (6) found good netroot on bad srvcall (3) found intransition netroot on bad srvcall (3) found bad netroot on bad srvcall (3) found good netroot on intransition srvcall (2) found intransition netroot on intransition srvcall (2) found bad netroot on intransition srvcall (2) (x) means that the code to handle that case has a marker like "case (x)". could be a comment....could be a debugout. Arguments: IN PRX_CONTEXT RxContext, IN PUNICODE_STRING CanonicalName, IN NET_ROOT_TYPE NetRootType, OUT PUNICODE_STRING LocalNetRootName, OUT PUNICODE_STRING FilePathName, IN OUT PLOCK_HOLDING_STATE LockHoldingState Return Value: RXSTATUS --*/ { NTSTATUS Status = STATUS_UNSUCCESSFUL; RxCaptureRequestPacket; RxCaptureParamBlock; UNICODE_STRING UnmatchedName; PVOID Container = NULL; PSRV_CALL SrvCall = NULL; PNET_ROOT NetRoot = NULL; PV_NET_ROOT VNetRoot = NULL; PRX_PREFIX_TABLE pRxNetNameTable = RxContext->RxDeviceObject->pRxNetNameTable; PAGED_CODE(); RxDbgTrace(0, Dbg, ("RxFindOrCreateConnections -> %08lx\n", RxContext)); // Parse the canonical name into the local net root name and file path name *FilePathName = *CanonicalName; LocalNetRootName->Length = 0; LocalNetRootName->MaximumLength = 0; LocalNetRootName->Buffer = CanonicalName->Buffer; if (FilePathName->Buffer[1] == L';') { PWCHAR pFilePathName = &FilePathName->Buffer[2]; BOOLEAN SeparatorFound = FALSE; ULONG PathLength = 0; if (FilePathName->Length > sizeof(WCHAR) * 2) { PathLength = FilePathName->Length - sizeof(WCHAR) * 2; } while (PathLength > 0) { if (*pFilePathName == L'\\') { SeparatorFound = TRUE; break; } PathLength -= sizeof(WCHAR); pFilePathName++; } if (!SeparatorFound) { return STATUS_OBJECT_NAME_INVALID; } FilePathName->Buffer = pFilePathName; LocalNetRootName->Length = (USHORT)((PCHAR)pFilePathName - (PCHAR)CanonicalName->Buffer); LocalNetRootName->MaximumLength = LocalNetRootName->Length; FilePathName->Length -= LocalNetRootName->Length; } RxDbgTrace( 0, Dbg, ("RxFindOrCreateConnections Path = %wZ\n", FilePathName)); try { UNICODE_STRING SrvCallName,NetRootName; RETRY_LOOKUP: ASSERT(*pLockHoldingState != LHS_LockNotHeld); if (Container != NULL) { // This is the subsequent pass of a lookup after waiting for the transition // to the stable state of a previous lookup. // Dereference the result of the earlier lookup. switch (NodeType(Container)) { case RDBSS_NTC_V_NETROOT: RxDereferenceVNetRoot((PV_NET_ROOT)Container,*pLockHoldingState); break; case RDBSS_NTC_SRVCALL: RxDereferenceSrvCall((PSRV_CALL)Container,*pLockHoldingState); break; case RDBSS_NTC_NETROOT: RxDereferenceNetRoot((PNET_ROOT)Container,*pLockHoldingState); break; default: DbgPrint("RxFindOrCreateConnections -- Invalid Container Type\n"); break; } } Container = RxPrefixTableLookupName( pRxNetNameTable, FilePathName, &UnmatchedName, RxConnectionId ); RxLog(("FOrCC1 %x %x %wZ \n",RxContext,Container,FilePathName)); RxWmiLog(LOG, RxFindOrCreateConnections_1, LOGPTR(RxContext) LOGPTR(Container) LOGUSTR(*FilePathName)); RETRY_AFTER_LOOKUP: NetRoot = NULL; SrvCall = NULL; VNetRoot = NULL; RxContext->Create.pVNetRoot = NULL; RxContext->Create.pNetRoot = NULL; RxContext->Create.pSrvCall = NULL; RxContext->Create.Type = NetRootType; if ( Container ) { if (NodeType(Container) == RDBSS_NTC_V_NETROOT) { VNetRoot = (PV_NET_ROOT)Container; NetRoot = (PNET_ROOT)VNetRoot->NetRoot; SrvCall = (PSRV_CALL)NetRoot->SrvCall; if (NetRoot->Condition == Condition_InTransition) { RxReleasePrefixTableLock(pRxNetNameTable); RxWaitForStableNetRoot(NetRoot,RxContext); RxAcquirePrefixTableLockExclusive(pRxNetNameTable,TRUE); *pLockHoldingState = LHS_ExclusiveLockHeld; // // Since we had to drop the table lock and reacquire it, // our NetRoot pointer may be stale. Look it up again before // using it. // // NOTE: The NetRoot is still referenced, so it is safe to // look at its condition. // if (NetRoot->Condition == Condition_Good) { goto RETRY_LOOKUP; } } if ((NetRoot->Condition == Condition_Good) && (SrvCall->Condition == Condition_Good) && (SrvCall->RxDeviceObject == RxContext->RxDeviceObject) ) { //case (0)...the good case...see comments below RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot; RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot; RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall; try_return ( Status = (STATUS_CONNECTION_ACTIVE) ); } else { Status = VNetRoot->ConstructionStatus==STATUS_SUCCESS ? STATUS_BAD_NETWORK_PATH: VNetRoot->ConstructionStatus; RxDereferenceVNetRoot(VNetRoot,*pLockHoldingState); try_return ( Status ); } } else { ASSERT ( NodeType(Container) == RDBSS_NTC_SRVCALL); SrvCall = (PSRV_CALL)Container; #if 0 if ((NetRootType != NET_ROOT_MAILSLOT) && (SrvCall->Flags & SRVCALL_FLAG_MAILSLOT_SERVER)) { RxDereferenceSrvCall(SrvCall,*pLockHoldingState); try_return(Status = (STATUS_BAD_DEVICE_TYPE)); } #endif // The associated SRV_CALL is in the process of construction. // await the result. if (SrvCall->Condition == Condition_InTransition) { RxDbgTrace(0, Dbg, (" Case(3)\n", 0)); RxReleasePrefixTableLock(pRxNetNameTable); RxWaitForStableSrvCall(SrvCall,RxContext); RxAcquirePrefixTableLockExclusive(pRxNetNameTable,TRUE); *pLockHoldingState = LHS_ExclusiveLockHeld; if (SrvCall->Condition == Condition_Good) { goto RETRY_LOOKUP; } } if (SrvCall->Condition != Condition_Good) { Status = SrvCall->Status == STATUS_SUCCESS ? STATUS_BAD_NETWORK_PATH: SrvCall->Status; //in changing this...remember precious servers....... RxDereferenceSrvCall(SrvCall,*pLockHoldingState); try_return(Status); } } } if ( (SrvCall != NULL) && (SrvCall->Condition == Condition_Good) && (SrvCall->RxDeviceObject != RxContext->RxDeviceObject) ) { RxDereferenceSrvCall(SrvCall,*pLockHoldingState); try_return(Status = (STATUS_BAD_NETWORK_NAME)); } if (*pLockHoldingState == LHS_SharedLockHeld) { // Upgrade the lock to an exclusive lock if (!RxAcquirePrefixTableLockExclusive(pRxNetNameTable, FALSE) ) { RxReleasePrefixTableLock(pRxNetNameTable); RxAcquirePrefixTableLockExclusive(pRxNetNameTable,TRUE); *pLockHoldingState = LHS_ExclusiveLockHeld; goto RETRY_LOOKUP; } else { *pLockHoldingState = LHS_ExclusiveLockHeld; } } ASSERT(*pLockHoldingState == LHS_ExclusiveLockHeld); // A prefix table entry was found. Further construction is required // if either a SRV_CALL was found or a SRV_CALL/NET_ROOT/V_NET_ROOT // in a bad state was found. if (Container) { RxDbgTrace(0, Dbg, (" SrvCall=%08lx\n", SrvCall)); ASSERT((NodeType(SrvCall) == RDBSS_NTC_SRVCALL) && (SrvCall->Condition == Condition_Good)); ASSERT((NetRoot == NULL) && VNetRoot == NULL); RxDbgTrace(0, Dbg, (" Case(4)\n", 0)); ASSERT (SrvCall->RxDeviceObject == RxContext->RxDeviceObject); SrvCall->RxDeviceObject->Dispatch->MRxExtractNetRootName( FilePathName, (PMRX_SRV_CALL)SrvCall, &NetRootName, NULL); NetRoot = RxCreateNetRoot( SrvCall, &NetRootName, 0, RxConnectionId); if (NetRoot == NULL) { Status = (STATUS_INSUFFICIENT_RESOURCES); try_return(Status); } NetRoot->Type = NetRootType; // Decrement the reference created by lookup. Since the newly created // netroot holds onto a reference it is safe to do so. RxDereferenceSrvCall(SrvCall,*pLockHoldingState); // Also create the associated default virtual net root VNetRoot = RxCreateVNetRoot( RxContext, NetRoot, CanonicalName, LocalNetRootName, FilePathName, RxConnectionId); if (VNetRoot == NULL) { RxFinalizeNetRoot(NetRoot,TRUE,TRUE); Status = (STATUS_INSUFFICIENT_RESOURCES); try_return(Status); } // Reference the VNetRoot RxReferenceVNetRoot(VNetRoot); NetRoot->Condition = Condition_InTransition; RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall; RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot; RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot; Status = RxConstructNetRoot( RxContext, SrvCall, NetRoot, VNetRoot, pLockHoldingState); if (Status == (STATUS_SUCCESS)) { ASSERT(*pLockHoldingState == LHS_ExclusiveLockHeld); if (!(capPARAMS->Parameters.Create.Options & FILE_CREATE_TREE_CONNECTION)) { // do not release the lock acquired by the callback routine .... RxExclusivePrefixTableLockToShared(pRxNetNameTable); *pLockHoldingState = LHS_SharedLockHeld; } } else { // Dereference the Virtual net root RxTransitionVNetRoot(VNetRoot, Condition_Bad); RxLog(("FOrCC %x %x Failed %x VNRc %d \n", RxContext, VNetRoot, Status, VNetRoot->Condition)); RxWmiLog(LOG, RxFindOrCreateConnections_2, LOGPTR(RxContext) LOGPTR(VNetRoot) LOGULONG(Status) LOGULONG(VNetRoot->Condition)); RxDereferenceVNetRoot(VNetRoot,*pLockHoldingState); RxContext->Create.pNetRoot = NULL; RxContext->Create.pVNetRoot = NULL; } try_return (Status); } // No prefix table entry was found. A new SRV_CALL instance needs to be // constructed. ASSERT(Container == NULL); RxExtractServerName(FilePathName,&SrvCallName,NULL); SrvCall = RxCreateSrvCall(RxContext,&SrvCallName,NULL,RxConnectionId); if (SrvCall == NULL) { Status = (STATUS_INSUFFICIENT_RESOURCES); try_return(Status); } RxReferenceSrvCall(SrvCall); RxContext->Create.Type = NetRootType; RxContext->Create.pSrvCall = NULL; RxContext->Create.pNetRoot = NULL; RxContext->Create.pVNetRoot = NULL; Status = RxConstructSrvCall( RxContext, SrvCall, pLockHoldingState); ASSERT(!(Status==(STATUS_SUCCESS)) || RxIsPrefixTableLockAcquired(pRxNetNameTable)); if (Status != STATUS_SUCCESS) { if (SrvCall != NULL) { RxAcquirePrefixTableLockExclusive( pRxNetNameTable, TRUE); RxDereferenceSrvCall(SrvCall,LHS_ExclusiveLockHeld); RxReleasePrefixTableLock( pRxNetNameTable ); } try_return(Status); } else { Container = SrvCall; goto RETRY_AFTER_LOOKUP; } try_exit: NOTHING; } finally { if ((Status != (STATUS_SUCCESS)) && (Status != (STATUS_CONNECTION_ACTIVE))) { if (*pLockHoldingState != LHS_LockNotHeld) { RxReleasePrefixTableLock( pRxNetNameTable ); *pLockHoldingState = LHS_LockNotHeld; } } } ASSERT(!(Status==(STATUS_SUCCESS)) || RxIsPrefixTableLockAcquired(pRxNetNameTable)); return Status; } VOID RxCreateNetRootCallBack ( IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext ) /*++ Routine Description: This routine gets called when the minirdr has finished processing on a CreateNetRoot calldown. It's exact function depends on whether the context describes IRP_MJ_CREATE or an IRP_MJ_IOCTL. Arguments: NetRoot - describes the Net_Root. --*/ { PAGED_CODE(); RxDbgTrace(0, Dbg, ("RxCreateNetRootCallBack pCreateNetRootContext = %08lx\n", pCreateNetRootContext)); KeSetEvent(&pCreateNetRootContext->FinishEvent, IO_NETWORK_INCREMENT, FALSE ); } NTSTATUS RxFinishSrvCallConstruction( IN OUT PMRX_SRVCALLDOWN_STRUCTURE pSrvCalldownStructure) /*++ Routine Description: This routine completes the construction of the srv call instance on an asyhcnronous manner Arguments: SCCBC -- Call back structure --*/ { PRX_CONTEXT RxContext; RX_BLOCK_CONDITION SrvCallCondition; NTSTATUS Status; PSRV_CALL pSrvCall; PRX_PREFIX_TABLE pRxNetNameTable; RxContext = pSrvCalldownStructure->RxContext; pRxNetNameTable = RxContext->RxDeviceObject->pRxNetNameTable; pSrvCall = (PSRV_CALL)pSrvCalldownStructure->SrvCall; if ( pSrvCalldownStructure->BestFinisher == NULL) { SrvCallCondition = Condition_Bad; Status = pSrvCalldownStructure->CallbackContexts[0].Status; } else { PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext; // Notify the Winner CallbackContext = &(pSrvCalldownStructure->CallbackContexts[pSrvCalldownStructure->BestFinisherOrdinal]); RxLog(("WINNER %x %wZ\n",CallbackContext,&pSrvCalldownStructure->BestFinisher->DeviceName)); RxWmiLog(LOG, RxFinishSrvCallConstruction, LOGPTR(CallbackContext) LOGUSTR(pSrvCalldownStructure->BestFinisher->DeviceName)); ASSERT(pSrvCall->RxDeviceObject == pSrvCalldownStructure->BestFinisher); MINIRDR_CALL_THROUGH( Status, pSrvCalldownStructure->BestFinisher->Dispatch, MRxSrvCallWinnerNotify, ( (PMRX_SRV_CALL)pSrvCall, TRUE, CallbackContext->RecommunicateContext )); if (STATUS_SUCCESS != Status) { SrvCallCondition = Condition_Bad; } else { SrvCallCondition = Condition_Good; } } // Transition the SrvCall instance ... RxAcquirePrefixTableLockExclusive(pRxNetNameTable, TRUE); RxTransitionSrvCall(pSrvCall,SrvCallCondition); RxFreePool(pSrvCalldownStructure); if (FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION)) { RxReleasePrefixTableLock( pRxNetNameTable ); // Resume the request that triggered the construction of the SrvCall ... if (BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_CANCELLED)) { Status = STATUS_CANCELLED; } if (RxContext->MajorFunction == IRP_MJ_CREATE) { RxpPrepareCreateContextForReuse(RxContext); } if (Status == STATUS_SUCCESS) { Status = RxContext->ResumeRoutine(RxContext); if (Status != STATUS_PENDING) { RxCompleteRequest(RxContext,Status); } } else { RxCaptureRequestPacket; RxCaptureParamBlock; RxContext->MajorFunction = capPARAMS->MajorFunction; if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL) { if (RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL) { RxFreePool(RxContext->PrefixClaim.SuppliedPathName.Buffer); RxContext->PrefixClaim.SuppliedPathName.Buffer = NULL; } } capReqPacket->IoStatus.Status = Status; capReqPacket->IoStatus.Information = 0; RxCompleteRequest(RxContext,Status); } } RxDereferenceSrvCall(pSrvCall,LHS_LockNotHeld); return Status; } BOOLEAN RxSrvCallConstructionDispatcherActive = FALSE; VOID RxFinishSrvCallConstructionDispatcher( PVOID Context) /*++ Routine Description: This routine provides us with a throttling mechanism for controlling the number of threads that can be consumed by srv call construction in the thread pool. Currently this limit is set at 1. gets called when a minirdr has finished processing on --*/ { KIRQL SavedIrql; BOOLEAN RemainingRequestsForProcessing; BOOLEAN ResumeRequestsOnDispatchError; ResumeRequestsOnDispatchError = (Context == NULL); for (;;) { PLIST_ENTRY pSrvCalldownListEntry; PMRX_SRVCALLDOWN_STRUCTURE pSrvCalldownStructure; KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql ); pSrvCalldownListEntry = RemoveHeadList( &RxSrvCalldownList); if (pSrvCalldownListEntry != &RxSrvCalldownList) { RemainingRequestsForProcessing = TRUE; } else { RemainingRequestsForProcessing = FALSE; RxSrvCallConstructionDispatcherActive = FALSE; } KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql ); if (!RemainingRequestsForProcessing) { break; } pSrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE) CONTAINING_RECORD( pSrvCalldownListEntry, MRX_SRVCALLDOWN_STRUCTURE, SrvCalldownList); if (ResumeRequestsOnDispatchError) { pSrvCalldownStructure->BestFinisher = NULL; } RxFinishSrvCallConstruction(pSrvCalldownStructure); } } VOID RxCreateSrvCallCallBack ( IN PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC ) /*++ Routine Description: This routine gets called when a minirdr has finished processing on a CreateSrvCall calldown. The minirdr will have set the status in the passed context to indicate success or failure. what we have to do is 1) decrease the number of outstanding requests and set the event if this is the last one. 2) determine whether this guy is the winner of the call. the minirdr must get the strucsupspinlock in order to call this routine; this routine must NOT be called if the minirdr's call was successfully canceled. Arguments: SCCBC -- Call back structure --*/ { KIRQL SavedIrql; PMRX_SRVCALLDOWN_STRUCTURE pSrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE)(SCCBC->SrvCalldownStructure); PSRV_CALL pSrvCall = (PSRV_CALL)pSrvCalldownStructure->SrvCall; ULONG MiniRedirectorsRemaining; BOOLEAN Cancelled; KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql ); RxDbgTrace(0, Dbg, (" RxCreateSrvCallCallBack SrvCall = %08lx\n", pSrvCall)); if (SCCBC->Status == (STATUS_SUCCESS)) { pSrvCalldownStructure->BestFinisher = SCCBC->RxDeviceObject; pSrvCalldownStructure->BestFinisherOrdinal = SCCBC->CallbackContextOrdinal; } pSrvCalldownStructure->NumberRemaining -= 1; MiniRedirectorsRemaining = pSrvCalldownStructure->NumberRemaining; pSrvCall->Status = SCCBC->Status; KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql ); if (MiniRedirectorsRemaining == 0) { if (!FlagOn( pSrvCalldownStructure->RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION)) { KeSetEvent( &pSrvCalldownStructure->FinishEvent, IO_NETWORK_INCREMENT, FALSE ); } else if (FlagOn( pSrvCalldownStructure->RxContext->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT)) { RxFinishSrvCallConstruction(pSrvCalldownStructure); } else { KIRQL SavedIrql; BOOLEAN DispatchRequest; KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql ); InsertTailList( &RxSrvCalldownList, &pSrvCalldownStructure->SrvCalldownList); DispatchRequest = !RxSrvCallConstructionDispatcherActive; if (!RxSrvCallConstructionDispatcherActive) { RxSrvCallConstructionDispatcherActive = TRUE; } KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql ); if (DispatchRequest) { NTSTATUS DispatchStatus; DispatchStatus = RxDispatchToWorkerThread( RxFileSystemDeviceObject, CriticalWorkQueue, RxFinishSrvCallConstructionDispatcher, &RxSrvCalldownList); if (DispatchStatus != STATUS_SUCCESS) { RxFinishSrvCallConstructionDispatcher(NULL); } } } } } NTSTATUS RxConstructSrvCall( PRX_CONTEXT RxContext, PSRV_CALL pSrvCall, LOCK_HOLDING_STATE *pLockHoldingState) /*++ Routine Description: This routine constructs a srv call by invoking the registered mini redirectors Arguments: pSrvCall -- the server call whose construction is to be completed pLockHoldingState -- the prefix table lock holding status Return Value: the appropriate status value --*/ { RxCaptureRequestPacket; NTSTATUS Status,WaitStatus; PMRX_SRVCALLDOWN_STRUCTURE pSrvCalldownStructure; RX_BLOCK_CONDITION SrvCallCondition; BOOLEAN SynchronousOperation; PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC; PRDBSS_DEVICE_OBJECT RxDeviceObject = RxContext->RxDeviceObject; PRX_PREFIX_TABLE pRxNetNameTable = RxDeviceObject->pRxNetNameTable; PAGED_CODE(); ASSERT(*pLockHoldingState == LHS_ExclusiveLockHeld); SynchronousOperation = (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION)); pSrvCalldownStructure = RxAllocatePoolWithTag( NonPagedPool, sizeof(MRX_SRVCALLDOWN_STRUCTURE) + (sizeof(MRX_SRVCALL_CALLBACK_CONTEXT) * 1), //one minirdr in this call 'CSxR' ); if (pSrvCalldownStructure == NULL) { pSrvCall->Condition = Condition_Bad; pSrvCall->Context = NULL; RxReleasePrefixTableLock( pRxNetNameTable ); *pLockHoldingState = LHS_LockNotHeld; return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(pSrvCalldownStructure, sizeof(MRX_SRVCALLDOWN_STRUCTURE) + sizeof(MRX_SRVCALL_CALLBACK_CONTEXT) * 1); pSrvCall->Condition = Condition_InTransition; pSrvCall->Context = NULL; // Drop the prefix table lock before calling the mini redirectors. RxReleasePrefixTableLock( pRxNetNameTable ); *pLockHoldingState = LHS_LockNotHeld; SCCBC = &(pSrvCalldownStructure->CallbackContexts[0]); //use the first and only context RxLog(("Calldwn %lx %wZ",SCCBC,&RxDeviceObject->DeviceName)); RxWmiLog(LOG, RxConstructSrvCall, LOGPTR(SCCBC) LOGUSTR(RxDeviceObject->DeviceName)); SCCBC->SrvCalldownStructure = pSrvCalldownStructure; SCCBC->CallbackContextOrdinal = 0; SCCBC->RxDeviceObject = RxDeviceObject; // This reference is taken away by the RxFinishSrvCallConstruction routine. // This reference enables us to deal with synchronous/asynchronous processing // of srv call construction requests in an identical manner. RxReferenceSrvCall(pSrvCall); if (FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) { RxPrePostIrp(RxContext,capReqPacket); } else { KeInitializeEvent( &pSrvCalldownStructure->FinishEvent, SynchronizationEvent, FALSE ); } pSrvCalldownStructure->NumberToWait = 1; pSrvCalldownStructure->NumberRemaining = pSrvCalldownStructure->NumberToWait; pSrvCalldownStructure->SrvCall = (PMRX_SRV_CALL)pSrvCall; pSrvCalldownStructure->CallBack = RxCreateSrvCallCallBack; pSrvCalldownStructure->BestFinisher = NULL; pSrvCalldownStructure->RxContext = RxContext; SCCBC->Status = STATUS_BAD_NETWORK_PATH; InitializeListHead(&pSrvCalldownStructure->SrvCalldownList); MINIRDR_CALL_THROUGH( Status, RxDeviceObject->Dispatch, MRxCreateSrvCall, ((PMRX_SRV_CALL)pSrvCall,SCCBC), ); ASSERT(Status == STATUS_PENDING); if (SynchronousOperation) { WaitStatus = KeWaitForSingleObject( &pSrvCalldownStructure->FinishEvent, Executive, KernelMode, FALSE, NULL); Status = RxFinishSrvCallConstruction(pSrvCalldownStructure); if (Status != STATUS_SUCCESS) { RxReleasePrefixTableLock( pRxNetNameTable ); *pLockHoldingState = LHS_LockNotHeld; } else { ASSERT(RxIsPrefixTableLockAcquired(pRxNetNameTable)); *pLockHoldingState = LHS_ExclusiveLockHeld; } } else { Status = STATUS_PENDING; } return Status; } NTSTATUS RxConstructNetRoot( PRX_CONTEXT RxContext, PSRV_CALL pSrvCall, PNET_ROOT pNetRoot, PV_NET_ROOT pVNetRoot, LOCK_HOLDING_STATE *pLockHoldingState ) /*++ Routine Description: This routine constructs a net root by invoking the registered mini redirectors Arguments: RxContext -- the RDBSS context pSrvCall -- the server call associated with the net root pNetRoot -- the net root instance to be constructed pVirtualNetRoot -- the virtual net root instance to be constructed pLockHoldingState -- the prefix table lock holding status Return Value: the appropriate status value --*/ { NTSTATUS Status; PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext; RX_BLOCK_CONDITION NetRootCondition = Condition_Bad; RX_BLOCK_CONDITION VNetRootCondition = Condition_Bad; PRX_PREFIX_TABLE pRxNetNameTable = RxContext->RxDeviceObject->pRxNetNameTable; PAGED_CODE(); ASSERT(*pLockHoldingState == LHS_ExclusiveLockHeld); pCreateNetRootContext = (PMRX_CREATENETROOT_CONTEXT) RxAllocatePoolWithTag( NonPagedPool, sizeof(MRX_CREATENETROOT_CONTEXT), 'CSxR' ); if (pCreateNetRootContext == NULL) { return (STATUS_INSUFFICIENT_RESOURCES); } RxReleasePrefixTableLock( pRxNetNameTable ); *pLockHoldingState = LHS_LockNotHeld; RtlZeroMemory(pCreateNetRootContext,sizeof(MRX_CREATENETROOT_CONTEXT)); KeInitializeEvent( &pCreateNetRootContext->FinishEvent, SynchronizationEvent, FALSE ); pCreateNetRootContext->Callback = RxCreateNetRootCallBack; pCreateNetRootContext->RxContext = RxContext; pCreateNetRootContext->pVNetRoot = pVNetRoot; MINIRDR_CALL_THROUGH( Status, pSrvCall->RxDeviceObject->Dispatch, MRxCreateVNetRoot,(pCreateNetRootContext) ); ASSERT (Status == STATUS_PENDING); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&pCreateNetRootContext->FinishEvent, Executive, KernelMode, FALSE, NULL); if ((pCreateNetRootContext->NetRootStatus == (STATUS_SUCCESS)) && (pCreateNetRootContext->VirtualNetRootStatus == (STATUS_SUCCESS))) { RxDbgTrace(0, Dbg, ("Return to open, good netroot...%wZ\n", &pNetRoot->PrefixEntry.Prefix)); NetRootCondition = Condition_Good; VNetRootCondition = Condition_Good; Status = (STATUS_SUCCESS); } else { if (pCreateNetRootContext->NetRootStatus == (STATUS_SUCCESS)) { NetRootCondition = Condition_Good; } RxDbgTrace(0, Dbg, ("Return to open, bad netroot...%wZ\n", &pNetRoot->PrefixEntry.Prefix)); if (pCreateNetRootContext->VirtualNetRootStatus != (STATUS_SUCCESS)) { Status = pCreateNetRootContext->VirtualNetRootStatus; } else { Status = pCreateNetRootContext->NetRootStatus; } } } RxAcquirePrefixTableLockExclusive(pRxNetNameTable, TRUE); RxTransitionNetRoot(pNetRoot, NetRootCondition); RxTransitionVNetRoot(pVNetRoot,VNetRootCondition); *pLockHoldingState = LHS_ExclusiveLockHeld; if (pCreateNetRootContext->WorkQueueItem.List.Flink != NULL) { //DbgBreakPoint(); } RxFreePool(pCreateNetRootContext); return Status; } NTSTATUS RxConstructVirtualNetRoot( PRX_CONTEXT RxContext, PUNICODE_STRING CanonicalName, NET_ROOT_TYPE NetRootType, PV_NET_ROOT *pVirtualNetRootPointer, LOCK_HOLDING_STATE *pLockHoldingState, PRX_CONNECTION_ID RxConnectionId) /*++ Routine Description: This routine constructs a VNetRoot (View of a net root) by invoking the registered mini redirectors Arguments: RxContext -- the RDBSS context CanonicalName -- the canonical name associated with the VNetRoot NetRootType -- the type of the virtual net root pVirtualNetRoot -- placeholder for the virtual net root instance to be constructed pLockHoldingState -- the prefix table lock holding status RxConnectionId -- The ID used for multiplex control Return Value: the appropriate status value --*/ { NTSTATUS Status; RX_BLOCK_CONDITION VNetRootCondition = Condition_Bad; UNICODE_STRING FilePath; UNICODE_STRING LocalNetRootName; PV_NET_ROOT pVirtualNetRoot = NULL; PAGED_CODE(); RxDbgTrace(0, Dbg, ("RxConstructVirtualNetRoot -- Entry\n")); ASSERT(*pLockHoldingState != LHS_LockNotHeld); Status = RxFindOrCreateConnections( RxContext, CanonicalName, NetRootType, &LocalNetRootName, &FilePath, pLockHoldingState, RxConnectionId); if (Status == (STATUS_CONNECTION_ACTIVE)) { PV_NET_ROOT pActiveVNetRoot = (PV_NET_ROOT)(RxContext->Create.pVNetRoot); PNET_ROOT pNetRoot = (PNET_ROOT)pActiveVNetRoot->NetRoot; RxDbgTrace(0, Dbg, (" RxConstructVirtualNetRoot -- Creating new VNetRoot\n")); RxDbgTrace(0, Dbg, ("RxCreateTreeConnect netroot=%wZ\n", &pNetRoot->PrefixEntry.Prefix)); // The NetRoot has been previously constructed. A subsequent VNetRoot // construction is required since the existing VNetRoot's do not satisfy // the given criterion ( currently smae Logon Id's). pVirtualNetRoot = RxCreateVNetRoot( RxContext, pNetRoot, CanonicalName, &LocalNetRootName, &FilePath, RxConnectionId); // The skeleton VNetRoot has been constructed. ( As part of this construction // the underlying NetRoot and SrvCall has been referenced). if (pVirtualNetRoot != NULL) { RxReferenceVNetRoot(pVirtualNetRoot); } // Dereference the VNetRoot returned as part of the lookup. RxDereferenceVNetRoot(pActiveVNetRoot,LHS_LockNotHeld); RxContext->Create.pVNetRoot = NULL; RxContext->Create.pNetRoot = NULL; RxContext->Create.pSrvCall = NULL; if (pVirtualNetRoot != NULL) { Status = RxConstructNetRoot( RxContext, (PSRV_CALL)pVirtualNetRoot->NetRoot->SrvCall, (PNET_ROOT)pVirtualNetRoot->NetRoot, pVirtualNetRoot, pLockHoldingState); VNetRootCondition = (Status == (STATUS_SUCCESS)) ? Condition_Good : Condition_Bad; } else { Status = STATUS_INSUFFICIENT_RESOURCES; } } else if (Status == (STATUS_SUCCESS)) { *pLockHoldingState = LHS_ExclusiveLockHeld; VNetRootCondition = Condition_Good; pVirtualNetRoot = (PV_NET_ROOT)(RxContext->Create.pVNetRoot); } else { RxDbgTrace(0, Dbg, ("RxConstructVirtualNetRoot -- RxFindOrCreateConnections Status %lx\n",Status)); } if ((pVirtualNetRoot != NULL) && !StableCondition(pVirtualNetRoot->Condition)) { RxTransitionVNetRoot(pVirtualNetRoot,VNetRootCondition); } if (Status != (STATUS_SUCCESS)) { if (pVirtualNetRoot != NULL) { ASSERT(*pLockHoldingState != LHS_LockNotHeld); RxDereferenceVNetRoot(pVirtualNetRoot,*pLockHoldingState); pVirtualNetRoot = NULL; } if (*pLockHoldingState != LHS_LockNotHeld) { RxReleasePrefixTableLock( RxContext->RxDeviceObject->pRxNetNameTable); *pLockHoldingState = LHS_LockNotHeld; } } *pVirtualNetRootPointer = pVirtualNetRoot; RxDbgTrace(0, Dbg, ("RxConstructVirtualNetRoot -- Exit Status %lx\n",Status)); return Status; } NTSTATUS RxCheckVNetRootCredentials( PRX_CONTEXT RxContext, PV_NET_ROOT pVNetRoot, LUID *pLogonId, PUNICODE_STRING pUserName, PUNICODE_STRING pUserDomainName, PUNICODE_STRING pPassword, ULONG Flags ) { NTSTATUS Status; BOOLEAN UNCName; BOOLEAN TreeConnectFlagSpecified; PSecurityUserData pSecurityData = NULL; RxCaptureParamBlock; PAGED_CODE(); Status = (STATUS_MORE_PROCESSING_REQUIRED); UNCName = BooleanFlagOn(RxContext->Create.Flags,RX_CONTEXT_CREATE_FLAG_UNC_NAME); TreeConnectFlagSpecified = BooleanFlagOn(capPARAMS->Parameters.Create.Options,FILE_CREATE_TREE_CONNECTION); // only for UNC names do we do the logic below if(RxContext->Create.Flags & RX_CONTEXT_CREATE_FLAG_UNC_NAME) { if ((pVNetRoot->Flags & VNETROOT_FLAG_CSCAGENT_INSTANCE) != (Flags & VNETROOT_FLAG_CSCAGENT_INSTANCE)) { // mismatched csc agent flags, not collapsing //DbgPrint("RxCheckVNetRootCredentials Not collapsing VNR %x \n", pVNetRoot); return Status; } } // The for loop is a scoping construct to join together the // multitiude of failure cases in comparing the EA parameters // with the original parameters supplied in the create request. for (;;) { if (RtlCompareMemory(&pVNetRoot->LogonId,pLogonId,sizeof(LUID)) == sizeof(LUID)) { PUNICODE_STRING TempUserName,TempUserDomainName; // If no EA parameters are specified by the user, the existing // V_NET_ROOT instance as used. This is the common case when // the user specifies the credentials for establishing a // persistent connection across processes and reuses them. if ((pUserName == NULL) && (pUserDomainName == NULL) && (pPassword == NULL)) { Status = STATUS_SUCCESS; break; } TempUserName = pVNetRoot->pUserName; TempUserDomainName = pVNetRoot->pUserDomainName; if (TempUserName == NULL || TempUserDomainName == NULL) { Status = GetSecurityUserInfo( pLogonId, UNDERSTANDS_LONG_NAMES, &pSecurityData); if (NT_SUCCESS(Status)) { if (TempUserName == NULL) { TempUserName = &(pSecurityData->UserName); } if (TempUserDomainName == NULL) { TempUserDomainName = &(pSecurityData->LogonDomainName); } } else { break; } } // The logon ids match. The user has supplied EA parameters // which can either match with the existing credentials or // result in a conflict with the existing credentials. In all // such cases the outcome will either be a reuse of the // existing V_NET_ROOT instance or a refusal of the new connection // attempt. // The only exception to the above rule is in the case of // regular opens (FILE_CREATE_TREE_CONNECTION is not // specified for UNC names. In such cases the construction of a // new V_NET_ROOT is initiated which will be torn down // when the associated file is closed if (UNCName && !TreeConnectFlagSpecified) { Status = STATUS_MORE_PROCESSING_REQUIRED; } else { Status = STATUS_NETWORK_CREDENTIAL_CONFLICT; } if (pUserName != NULL && TempUserName != NULL && !RtlEqualUnicodeString(TempUserName,pUserName,TRUE)) { break; } if (pUserDomainName != NULL && !RtlEqualUnicodeString(TempUserDomainName,pUserDomainName,TRUE)) { break; } if ((pVNetRoot->pPassword != NULL) && (pPassword != NULL)) { if (!RtlEqualUnicodeString( pVNetRoot->pPassword, pPassword, FALSE)) { break; } } // We use existing session if either the stored or new password is NULL. // Later, a new security API will be created for verify the password based // on the logon ID. Status = STATUS_SUCCESS; break; } else { break; } } //ASSERT(Status != STATUS_NETWORK_CREDENTIAL_CONFLICT); if (pSecurityData != NULL) { LsaFreeReturnBuffer(pSecurityData); } return Status; } NTSTATUS RxFindOrConstructVirtualNetRoot( PRX_CONTEXT RxContext, PUNICODE_STRING CanonicalName, NET_ROOT_TYPE NetRootType, PUNICODE_STRING RemainingName) /*++ Routine Description: This routine finds or constructs a VNetRoot (View of a net root) Arguments: RxContext -- the RDBSS context CanonicalName -- the canonical name associated with the VNetRoot NetRootType -- the type of the virtual net root RemainingName -- the portion of the name that was not found in the prefix table Return Value: the appropriate status value --*/ { NTSTATUS Status; LOCK_HOLDING_STATE LockHoldingState; BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT); BOOLEAN InFSD = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP); BOOLEAN UNCName; BOOLEAN TreeConnectFlagSpecified; PVOID Container; PV_NET_ROOT pVNetRoot; PNET_ROOT pNetRoot; PSRV_CALL pSrvCall; PRX_PREFIX_TABLE pRxNetNameTable = RxContext->RxDeviceObject->pRxNetNameTable; ULONG Flags = 0; RX_CONNECTION_ID sRxConnectionId; PRDBSS_DEVICE_OBJECT RxDeviceObject = RxContext->RxDeviceObject; RxCaptureParamBlock; PAGED_CODE(); MINIRDR_CALL_THROUGH( Status, RxDeviceObject->Dispatch, MRxGetConnectionId, (RxContext,&sRxConnectionId) ); if( Status == STATUS_NOT_IMPLEMENTED ) { RtlZeroMemory( &sRxConnectionId, sizeof(RX_CONNECTION_ID) ); } else if( !NT_SUCCESS(Status) ) { DbgPrint( "MRXSMB: Failed to initialize Connection ID\n" ); ASSERT(FALSE); RtlZeroMemory( &sRxConnectionId, sizeof(RX_CONNECTION_ID) ); } Status = (STATUS_MORE_PROCESSING_REQUIRED); UNCName = BooleanFlagOn(RxContext->Create.Flags,RX_CONTEXT_CREATE_FLAG_UNC_NAME); TreeConnectFlagSpecified = BooleanFlagOn(capPARAMS->Parameters.Create.Options,FILE_CREATE_TREE_CONNECTION); //deleterxcontext stuff will deref wherever this points....... RxContext->Create.NetNamePrefixEntry = NULL; RxAcquirePrefixTableLockShared(pRxNetNameTable, TRUE); LockHoldingState = LHS_SharedLockHeld; for(;;) { // This for loop actually serves as a simple scoping construct for executing // the same piece of code twice, once with a shared lock and once with an // exclusive lock. In the interests of maximal concurrency a shared lock is // accquired for the first pass and subsequently upgraded. If the search // succeeds with a shared lock the second pass is skipped. Container = RxPrefixTableLookupName( pRxNetNameTable, CanonicalName, RemainingName, &sRxConnectionId ); if (Container != NULL ) { if (NodeType(Container) == RDBSS_NTC_V_NETROOT) { PV_NET_ROOT pTempVNetRoot; ULONG SessionId; pVNetRoot = (PV_NET_ROOT)Container; pNetRoot = (PNET_ROOT)pVNetRoot->NetRoot; // Determine if a virtual net root with the same logon id. already exists. // If not a new virtual net root has to be constructed. // traverse the list of virtual net roots associated with a net root. // Note that the list of virtual net roots associated with a net root cannot be empty // since the construction of the default virtual net root coincides with the creation // of the net root. if (((pNetRoot->Condition == Condition_Good) || (pNetRoot->Condition == Condition_InTransition)) && (pNetRoot->pSrvCall->RxDeviceObject == RxContext->RxDeviceObject)) { LUID LogonId; PUNICODE_STRING pUserName,pUserDomainName,pPassword; // Extract the VNetRoot parameters from the IRP to map one of // the existing VNetRoots if possible. The algorithm for // determining this mapping is very simplistic. If no Ea // parameters are specified a VNetRoot with a matching Logon // id. is choosen. if Ea parameters are specified then a // VNetRoot with identical parameters is choosen. The idea // behind this simplistic algorithm is to let the mini redirectors // determine the mapping policy and not prefer one mini // redirectors policy over another. Status = RxInitializeVNetRootParameters( RxContext, &LogonId, &SessionId, &pUserName, &pUserDomainName, &pPassword, &Flags ); #if 0 if (Flags & VNETROOT_FLAG_CSCAGENT_INSTANCE) { DbgPrint("RxFindOrConstructVirtualNetRoot AgentOpen %wZ\n", CanonicalName); } #endif if (Status == STATUS_SUCCESS) { pTempVNetRoot = pVNetRoot; Status = RxCheckVNetRootCredentials( RxContext, pTempVNetRoot, &LogonId, pUserName, pUserDomainName, pPassword, Flags ); if (Status == STATUS_MORE_PROCESSING_REQUIRED) { // The for loop iterates over the existing VNetRoots to locate // an instance whose parameters match the supplied parameters. // On exit from this loop pTempVNetRoot will either point to a // valid instance or have a NULL value. pTempVNetRoot = (PV_NET_ROOT)CONTAINING_RECORD( pNetRoot->VirtualNetRoots.Flink, V_NET_ROOT, NetRootListEntry); for (;;) { Status = RxCheckVNetRootCredentials( RxContext, pTempVNetRoot, &LogonId, pUserName, pUserDomainName, pPassword, Flags ); if (Status == STATUS_MORE_PROCESSING_REQUIRED) { if (pTempVNetRoot->NetRootListEntry.Flink == &pNetRoot->VirtualNetRoots) { pTempVNetRoot = NULL; break; } else { pTempVNetRoot = (PV_NET_ROOT)CONTAINING_RECORD( pTempVNetRoot->NetRootListEntry.Flink, V_NET_ROOT, NetRootListEntry); } } else { break; } } } if (Status != STATUS_SUCCESS) { pTempVNetRoot = NULL; } RxUninitializeVNetRootParameters(pUserName,pUserDomainName,pPassword,&Flags); } } else { Status = (STATUS_BAD_NETWORK_PATH); pTempVNetRoot = NULL; } if ((Status == STATUS_MORE_PROCESSING_REQUIRED) || (Status == STATUS_SUCCESS)) { if (pTempVNetRoot != pVNetRoot) { RxDereferenceVNetRoot(pVNetRoot,LockHoldingState); pVNetRoot = pTempVNetRoot; if (pVNetRoot != NULL) { RxReferenceVNetRoot(pVNetRoot); } } } else { if (pTempVNetRoot == NULL) { RxDereferenceVNetRoot(pVNetRoot,LockHoldingState); } } } else { ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL); RxDereferenceSrvCall((PSRV_CALL)Container,LockHoldingState); } } if ((Status == (STATUS_MORE_PROCESSING_REQUIRED)) && (LockHoldingState == LHS_SharedLockHeld)) { // Release the shared lock and acquire it in an exclusive mode. // Upgrade the lock to an exclusive lock if (!RxAcquirePrefixTableLockExclusive(pRxNetNameTable, FALSE) ) { RxReleasePrefixTableLock(pRxNetNameTable); RxAcquirePrefixTableLockExclusive(pRxNetNameTable,TRUE); LockHoldingState = LHS_ExclusiveLockHeld; } else { // The lock was upgraded from a shared mode to an exclusive mode without // losing it. Therefore there is no need to search the table again. The // construction of the new V_NET_ROOT can proceed. LockHoldingState = LHS_ExclusiveLockHeld; break; } } else { break; } } // At this point either the lookup was successful ( with a shared/exclusive lock ) // or exclusive lock has been obtained. // No virtual net root was found in the prefix table or the net root that was found is bad. // The construction of a new virtual netroot needs to be undertaken. if (Status == (STATUS_MORE_PROCESSING_REQUIRED)) { ASSERT(LockHoldingState == LHS_ExclusiveLockHeld); Status = RxConstructVirtualNetRoot( RxContext, CanonicalName, NetRootType, &pVNetRoot, &LockHoldingState, &sRxConnectionId); ASSERT((Status != (STATUS_SUCCESS)) || (LockHoldingState != LHS_LockNotHeld)); if (Status == (STATUS_SUCCESS)) { ASSERT(CanonicalName->Length >= pVNetRoot->PrefixEntry.Prefix.Length); RemainingName->Buffer = (PWCH)((PCHAR)CanonicalName->Buffer + pVNetRoot->PrefixEntry.Prefix.Length); RemainingName->Length = CanonicalName->Length - pVNetRoot->PrefixEntry.Prefix.Length; RemainingName->MaximumLength = RemainingName->Length; if (FlagOn(Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE)) { RxLog(("FOrCVNR CSC instance %x\n", pVNetRoot)); RxWmiLog(LOG, RxFindOrConstructVirtualNetRoot, LOGPTR(pVNetRoot)); // DbgPrint("FOrCVNR CSC instance %wZ\n", CanonicalName); } pVNetRoot->Flags |= Flags; } } if (LockHoldingState != LHS_LockNotHeld) { RxReleasePrefixTableLock(pRxNetNameTable); } if (Status == (STATUS_SUCCESS)) { RxWaitForStableVNetRoot(pVNetRoot,RxContext); if (pVNetRoot->Condition == Condition_Good) { pNetRoot = (PNET_ROOT)pVNetRoot->NetRoot; pSrvCall = (PSRV_CALL)pNetRoot->SrvCall; RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)pVNetRoot; RxContext->Create.pNetRoot = (PMRX_NET_ROOT)pNetRoot; RxContext->Create.pSrvCall = (PMRX_SRV_CALL)pSrvCall; } else { RxDereferenceVNetRoot(pVNetRoot,LHS_LockNotHeld); RxContext->Create.pVNetRoot = NULL; Status = (STATUS_BAD_NETWORK_PATH); } } return Status; }