Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

786 lines
22 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
AgntEvnt.c
Abstract:
This module implements the interface by which the csc driver reports
stuff to the agent.
Author:
Joe Linn [JoeLinn] 5-may-1997
Revision History:
Notes:
Additional synchronization surrounds net_start and net_stop. for netstop, we
have to wait for the agent to signal that he is finished before we can proceed.
we probably we should implement a mechanism by which he can refuse the
netstop. anyway this is done by recording the netstop context that is waiting
before signaling the event. the same sort of thing is true for netstart.
--*/
#include "precomp.h"
#pragma hdrstop
#pragma code_seg("PAGE")
extern DEBUG_TRACE_CONTROLPOINT RX_DEBUG_TRACE_MRXSMBCSC;
#define Dbg (DEBUG_TRACE_MRXSMBCSC)
// A global variable which indicates the current status of the net
// TRUE implies available. This is used in controlling the
// transitioning indication to the agent
LONG CscNetPresent = FALSE;
LONG CscAgentNotifiedOfNetStatusChange = CSC_AGENT_NOT_NOTIFIED;
LONG CscAgentNotifiedOfFullCache = CSC_AGENT_NOT_NOTIFIED;
PKEVENT MRxSmbAgentSynchronizationEvent = NULL;
ULONG MRxSmbAgentSynchronizationEventIdx = 0;
PKEVENT MRxSmbAgentFillEvent = NULL;
PRX_CONTEXT MRxSmbContextAwaitingAgent = NULL;
PRX_CONTEXT MRxSmbContextAwaitingFillAgent = NULL;
LONG vcntTransportsForCSC=0;
extern ULONG CscSessionIdCausingTransition;
//CODE.IMPROVEMENT.NTIFS had to just know to do this......
extern POBJECT_TYPE *ExEventObjectType;
//CODE.IMPROVEMENT.NTIFS just stole this from oak\in\zwapi.h
NTSYSAPI
NTSTATUS
NTAPI
ZwOpenEvent (
OUT PHANDLE EventHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
typedef struct _MRXSMBCSC_OPENEVENT_POSTCONTEXT {
KEVENT PostEvent;
RX_WORK_QUEUE_ITEM WorkQueueItem;
} MRXSMBCSC_OPENEVENT_POSTCONTEXT, *PMRXSMBCSC_OPENEVENT_POSTCONTEXT;
VOID
MRxSmbCscOpenAgentEvent (
BOOLEAN PostedCall);
VOID
MRxSmbCscOpenAgentFillEvent (
BOOLEAN PostedCall);
NTSTATUS
MRxSmbCscOpenAgentEventPostWrapper(
IN OUT PMRXSMBCSC_OPENEVENT_POSTCONTEXT OpenEventPostContext
)
{
RxDbgTrace( 0, Dbg, ("MRxSmbCscOpenAgentEventPostWrapper entry\n"));
MRxSmbCscOpenAgentEvent(TRUE);
RxDbgTrace( 0, Dbg, ("MRxSmbCscOpenAgentEventPostWrapper exit\n"));
KeSetEvent( &OpenEventPostContext->PostEvent, 0, FALSE );
return(STATUS_SUCCESS);
}
NTSTATUS
MRxSmbCscOpenAgentFillEventPostWrapper(
IN OUT PMRXSMBCSC_OPENEVENT_POSTCONTEXT OpenFillEventPostContext
)
{
RxDbgTrace( 0, Dbg, ("MRxSmbCscOpenAgentFillEventPostWrapper entry\n"));
MRxSmbCscOpenAgentFillEvent(TRUE);
RxDbgTrace( 0, Dbg, ("MRxSmbCscOpenAgentFillEventPostWrapper exit\n"));
KeSetEvent( &OpenFillEventPostContext->PostEvent, 0, FALSE );
return(STATUS_SUCCESS);
}
VOID
MRxSmbCscOpenAgentEvent (
BOOLEAN PostedCall
)
/*++
Routine Description:
This routine gets a pointer to the agent's event.
Arguments:
Return Value:
Notes:
The shadowcrit serialization mutex must have already been acquired before the call.
--*/
{
NTSTATUS Status;
HANDLE EventHandle;
UNICODE_STRING EventName;
OBJECT_ATTRIBUTES ObjectAttributes;
WCHAR SessEventName[100];
WCHAR IdBuffer[16];
UNICODE_STRING IdString;
ASSERT (MRxSmbAgentSynchronizationEvent == NULL);
// DbgPrint("MRxSmbCscOpenAgentEvent(%d) Caused by sess 0x%x\n",
// PostedCall,
// CscSessionIdCausingTransition);
if (PsGetCurrentProcess()!= RxGetRDBSSProcess()) {
//CODE.IMPROVEMENT we should capture the rdbss process
// and avoid this call (RxGetRDBSSProcess)
NTSTATUS PostStatus;
MRXSMBCSC_OPENEVENT_POSTCONTEXT PostContext;
ASSERT(!PostedCall);
KeInitializeEvent(&PostContext.PostEvent,
NotificationEvent,
FALSE );
IF_DEBUG {
//fill the workqueue structure with deadbeef....all the better to diagnose
//a failed post
ULONG i;
for (i=0;i+sizeof(ULONG)-1<sizeof(PostContext.WorkQueueItem);i+=sizeof(ULONG)) {
PBYTE BytePtr = ((PBYTE)&PostContext.WorkQueueItem)+i;
PULONG UlongPtr = (PULONG)BytePtr;
*UlongPtr = 0xdeadbeef;
}
}
PostStatus = RxPostToWorkerThread(
MRxSmbDeviceObject,
CriticalWorkQueue,
&PostContext.WorkQueueItem,
MRxSmbCscOpenAgentEventPostWrapper,
&PostContext);
ASSERT(PostStatus == STATUS_SUCCESS);
KeWaitForSingleObject( &PostContext.PostEvent,
Executive, KernelMode, FALSE, NULL );
return;
}
// Build an event name with the session id at the end
wcscpy(SessEventName, SESSION_EVENT_NAME_NT);
wcscat(SessEventName, L"_");
EventName.Buffer = SessEventName;
EventName.Length = wcslen(SessEventName) * sizeof(WCHAR);
EventName.MaximumLength = sizeof(SessEventName);
IdString.Buffer = IdBuffer;
IdString.Length = 0;
IdString.MaximumLength = sizeof(IdBuffer);
RtlIntegerToUnicodeString(CscSessionIdCausingTransition, 10, &IdString);
RtlAppendUnicodeStringToString(&EventName, &IdString);
// DbgPrint("MRxSmbCscOpenAgentEvent: SessEventName = %wZ\n", &EventName);
InitializeObjectAttributes( &ObjectAttributes,
&EventName,
0,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL );
Status = ZwOpenEvent( &EventHandle,
EVENT_ALL_ACCESS,
&ObjectAttributes
);
if (Status!=STATUS_SUCCESS) {
RxDbgTrace(0, Dbg, ("MRxSmbCscSignalAgent no event %08lx\n",Status));
return;
}
Status = ObReferenceObjectByHandle( EventHandle,
0,
*ExEventObjectType,
KernelMode,
(PVOID *) &MRxSmbAgentSynchronizationEvent,
NULL );
MRxSmbAgentSynchronizationEventIdx = CscSessionIdCausingTransition;
ZwClose(EventHandle);
if (Status!=STATUS_SUCCESS) {
RxDbgTrace(0, Dbg, ("MRxSmbCscSignalAgent couldn't reference %08lx\n", Status));
MRxSmbAgentSynchronizationEvent = NULL;
MRxSmbAgentSynchronizationEventIdx = 0;
return;
}
return;
}
NTSTATUS
MRxSmbCscSignalAgent (
PRX_CONTEXT RxContext OPTIONAL,
ULONG Controls
)
/*++
Routine Description:
This routine signals the csc usermode agent using the appropriate event.
Arguments:
RxContext - the RDBSS context. if this is provided then the context is
as the guy who is waiting.
Return Value:
NTSTATUS - The return status for the operation
Notes:
The shadowcrit serialization mutex must have already been acquired before the call.
We will drop it here.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN ShadowCritEntered = TRUE; //must be in critsect on
BOOLEAN PreventLeaveCrit = BooleanFlagOn(Controls,SIGNALAGENTFLAG_DONT_LEAVE_CRIT_SECT);
RxDbgTrace(+1, Dbg, ("MRxSmbCscSignalAgent entry...%08lx\n",RxContext));
DbgDoit(ASSERT(vfInShadowCrit));
ASSERT(MRxSmbIsCscEnabled);
if (!FlagOn(Controls,SIGNALAGENTFLAG_CONTINUE_FOR_NO_AGENT)) {
if (hthreadReint==0) {
//no agent and no force...just get out
RxDbgTrace(0, Dbg, ("MRxSmbCscSignalAgent no agent/noforce %08lx\n", RxContext));
goto FINALLY;
}
}
if (
MRxSmbAgentSynchronizationEvent != NULL
&&
MRxSmbAgentSynchronizationEventIdx != CscSessionIdCausingTransition
) {
ObDereferenceObject(MRxSmbAgentSynchronizationEvent);
MRxSmbAgentSynchronizationEvent = NULL;
MRxSmbAgentSynchronizationEventIdx = 0;
}
if (MRxSmbAgentSynchronizationEvent == NULL) {
MRxSmbCscOpenAgentEvent(FALSE); //FALSE==>not a posted call
if (MRxSmbAgentSynchronizationEvent == NULL) {
//still NULL...no agent.........
RxDbgTrace(0, Dbg, ("MRxSmbCscSignalAgent no event %08lx %08lx\n",
RxContext,Status));
Status = STATUS_SUCCESS;
goto FINALLY;
}
}
if (RxContext != NULL) {
MRxSmbContextAwaitingAgent = RxContext;
}
if (!PreventLeaveCrit) {
LeaveShadowCrit();
ShadowCritEntered = FALSE;
} else {
ASSERT(RxContext==NULL); //cant wait with critsect held
}
// reduce the window of MRxSmbAgentSynchronizationEvent getting nulled out
// by explictly checking before pulsing
if (MRxSmbAgentSynchronizationEvent)
{
KeSetEvent(MRxSmbAgentSynchronizationEvent,0,FALSE);
}
if (RxContext != NULL) {
RxDbgTrace(0, Dbg, ("MRxSmbCscSignalAgent waiting %08lx\n", RxContext));
RxWaitSync(RxContext);
RxDbgTrace(0, Dbg, ("MRxSmbCscSignalAgent end of wait %08lx\n", RxContext));
}
RxDbgTrace(0, Dbg, ("MRxSmbCscSignalAgent %08lx\n", RxContext));
FINALLY:
if (ShadowCritEntered && !PreventLeaveCrit) {
LeaveShadowCrit();
}
RxDbgTrace(-1, Dbg, ("MRxSmbCscSignalAgent... exit %08lx %08lx\n",
RxContext, Status));
return(Status);
}
VOID
MRxSmbCscSignalNetStatus(
BOOLEAN NetPresent,
BOOLEAN fFirstLast
)
{
if(!MRxSmbIsCscEnabled) {
return;
}
if (NetPresent)
{
InterlockedIncrement(&vcntTransportsForCSC);
}
else
{
if(vcntTransportsForCSC == 0)
{
DbgPrint("CSC:Mismatched transport departure messages from mini redir \n");
return;
}
InterlockedDecrement(&vcntTransportsForCSC);
}
if (!fFirstLast)
{
return;
}
InterlockedExchange(
&CscNetPresent,
NetPresent);
InterlockedExchange(
&CscAgentNotifiedOfNetStatusChange,
CSC_AGENT_NOT_NOTIFIED);
CscNotifyAgentOfNetStatusChangeIfRequired(FALSE);
}
VOID
CscNotifyAgentOfNetStatusChangeIfRequired(
BOOLEAN fInvokeAutoDial
)
{
LONG AgentNotificationState;
AgentNotificationState = InterlockedExchange(
&CscAgentNotifiedOfNetStatusChange,
CSC_AGENT_NOTIFIED);
if (AgentNotificationState == CSC_AGENT_NOT_NOTIFIED) {
EnterShadowCrit(); //this is dropped in the signalagent routine....
if (CscNetPresent) {
SetFlag(sGS.uFlagsEvents,FLAG_GLOBALSTATUS_GOT_NET);
} else {
SetFlag(sGS.uFlagsEvents,FLAG_GLOBALSTATUS_NO_NET);
if (fInvokeAutoDial)
{
SetFlag(sGS.uFlagsEvents,FLAG_GLOBALSTATUS_INVOKE_AUTODIAL);
}
}
MRxSmbCscSignalAgent(
NULL,
SIGNALAGENTFLAG_CONTINUE_FOR_NO_AGENT);
}
}
VOID
CscNotifyAgentOfFullCacheIfRequired(
VOID)
{
// DbgPrint("CscNotifyAgentOfFullCacheIfRequired()\n");
if (MRxSmbAgentSynchronizationEvent == NULL) {
MRxSmbCscOpenAgentEvent(FALSE); //FALSE==>not a posted call
if (MRxSmbAgentSynchronizationEvent == NULL) {
RxDbgTrace(0, Dbg, ("MRxSmbCscSignalAgent no event %08lx %08lx\n"));
// DbgPrint("CscNotifyAgentOfFullCacheIfRequired exit no event\n");
return;
}
}
SetFlag(sGS.uFlagsEvents, FLAG_GLOBALSTATUS_INVOKE_FREESPACE);
if (MRxSmbAgentSynchronizationEvent)
KeSetEvent(MRxSmbAgentSynchronizationEvent,0,FALSE);
// DbgPrint("CscNotifyAgentOfFullCacheIfRequired exit\n");
}
//CODE.IMPROVEMENT.ASHAMED...the next two routines are virtually identical; also there's
// a lot of very similar codein the third
VOID
MRxSmbCscAgentSynchronizationOnStart (
IN OUT PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine signals the csc usermode agent that a start is occurring.
By passing the context to the signal routine, we indicate that we want
to wait for an external guy (in this case ioctl_register_start) to signal us
tro proceed
Arguments:
RxContext - the RDBSS context.
Return Value:
Notes:
--*/
{
#if 0
NTSTATUS Status;
if(!MRxSmbIsCscEnabled) {
return;
}
RxDbgTrace(+1, Dbg, ("MRxSmbCscAgentSynchronizationOnStart entry...%08lx\n",RxContext));
EnterShadowCrit(); //this is dropped in the signalagent routine....
// check if an agent is already registered
// if he is then we don't need to do any of this stuff
if (!hthreadReint)
{
SetFlag(sGS.uFlagsEvents,FLAG_GLOBALSTATUS_START);
Status = MRxSmbCscSignalAgent(RxContext,
SIGNALAGENTFLAG_CONTINUE_FOR_NO_AGENT);
}
else
{
LeaveShadowCrit();
}
RxDbgTrace(-1, Dbg, ("MRxSmbCscAgentSynchronizationOnStart...%08lx %08lx\n",
RxContext, Status));
#endif
return;
}
VOID
MRxSmbCscAgentSynchronizationOnStop (
IN OUT PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine signals the csc usermode agent that a stop is occurring.
By passing the context to the signal routine, we indicate that we want
to wait for an external guy (in this case ioctl_register_stop) to signal us
tro proceed
Arguments:
RxContext - the RDBSS context.
Return Value:
Notes:
--*/
{
#if 0
NTSTATUS Status;
if(!MRxSmbIsCscEnabled) {
return;
}
RxDbgTrace(+1, Dbg, ("MRxSmbCscAgentSynchronizationOnStop entry...%08lx\n",RxContext));
EnterShadowCrit(); //this is dropped in the signalagent routine....
if (hthreadReint)
{
SetFlag(sGS.uFlagsEvents,FLAG_GLOBALSTATUS_STOP);
Status = MRxSmbCscSignalAgent(RxContext,0); //0 means no special operations
}
else
{
LeaveShadowCrit();
}
RxDbgTrace(-1, Dbg, ("MRxSmbCscAgentSynchronizationOnStop...%08lx %08lx\n",
RxContext, Status));
#endif
return;
}
VOID
MRxSmbCscReleaseRxContextFromAgentWait (
void
)
/*++
Routine Description:
This routine checks to see if there is a context waiting for the agent. If so,
it signals the context's syncevent. It also clears the specified flags.
Arguments:
RxContext - the RDBSS context.
Return Value:
Notes:
--*/
{
PRX_CONTEXT WaitingContext;
RxDbgTrace(+1, Dbg, ("MRxSmbCscReleaseRxContextFromAgentWait entry...%08lx\n"));
ASSERT(MRxSmbIsCscEnabled);
EnterShadowCrit();
WaitingContext = MRxSmbContextAwaitingAgent;
MRxSmbContextAwaitingAgent = NULL;
LeaveShadowCrit();
if (WaitingContext != NULL) {
RxSignalSynchronousWaiter(WaitingContext);
}
RxDbgTrace(-1, Dbg, ("MRxSmbCscReleaseRxContextFromAgentWait...%08lx\n"));
return;
}
//CODE.IMPROVEMENT get this in an include file
extern ULONG MRxSmbCscNumberOfShadowOpens;
extern ULONG MRxSmbCscActivityThreshold;
VOID
MRxSmbCscReportFileOpens (
void
)
/*++
Routine Description:
This routine checks to see if there has been enough activity to signal
the agent to recompute reference priorities.
Arguments:
Return Value:
Notes:
--*/
{
NTSTATUS Status;
RxDbgTrace(+1, Dbg, ("MRxSmbCscReportFileOpens entry...%08lx %08lx\n",
MRxSmbCscNumberOfShadowOpens,(ULONG)(sGS.cntFileOpen) ));
EnterShadowCrit(); //this is dropped in the signalagent routine....
MRxSmbCscNumberOfShadowOpens++;
if ((MRxSmbCscNumberOfShadowOpens > (ULONG)(sGS.cntFileOpen) ) // to guard against rollover
&& ((MRxSmbCscNumberOfShadowOpens - (ULONG)(sGS.cntFileOpen))
< MRxSmbCscActivityThreshold)) {
RxDbgTrace(-1, Dbg, ("MRxSmbCscReportFileOpens inactive...\n"));
LeaveShadowCrit();
return;
}
//SetFlag(sGS.uFlagsEvents,FLAG_GLOBALSTATUS_START);
sGS.cntFileOpen = MRxSmbCscNumberOfShadowOpens;
Status = MRxSmbCscSignalAgent(NULL,0); //this means don't wait for a repsonse
RxDbgTrace(-1, Dbg, ("MRxSmbCscReportFileOpens...activeexit\n"));
return;
}
NTSTATUS
MRxSmbCscSignalFillAgent(
PRX_CONTEXT RxContext OPTIONAL,
ULONG Controls)
{
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN ShadowCritEntered = TRUE; //must be in critsect on
BOOLEAN PreventLeaveCrit = BooleanFlagOn(Controls,SIGNALAGENTFLAG_DONT_LEAVE_CRIT_SECT);
RxDbgTrace(+1, Dbg, ("MRxSmbCscSignalFillAgent entry...%08lx\n",RxContext));
// DbgPrint("MRxSmbCscSignalFillAgent entry...%08lx\n",RxContext);
ASSERT(MRxSmbIsCscEnabled);
if (!FlagOn(Controls,SIGNALAGENTFLAG_CONTINUE_FOR_NO_AGENT)) {
if (hthreadReint==0) {
//no agent and no force...just get out
RxDbgTrace(0, Dbg, ("MRxSmbCscSignalFillAgent no agent/noforce %08lx\n", RxContext));
goto FINALLY;
}
}
if (MRxSmbAgentFillEvent == NULL) {
// DbgPrint("MRxSmbCscSignalFillAgent: gotta open the event...\n");
MRxSmbCscOpenAgentFillEvent(FALSE); //FALSE==>not a posted call
if (MRxSmbAgentFillEvent == NULL) {
//still NULL...no agent.........
RxDbgTrace(0, Dbg, ("MRxSmbCscSignalFillAgent no event %08lx %08lx\n",
RxContext,Status));
// DbgPrint("MRxSmbCscSignalFillAgent no event %08lx %08lx\n");
Status = STATUS_SUCCESS;
goto FINALLY;
}
}
if (RxContext != NULL) {
MRxSmbContextAwaitingFillAgent = RxContext;
}
// if (!PreventLeaveCrit) {
// LeaveShadowCrit();
// ShadowCritEntered = FALSE;
// } else {
// ASSERT(RxContext==NULL); //cant wait with critsect held
// }
// reduce the window of MRxSmbAgentFillEvent getting nulled out
// by explictly checking before pulsing
if (MRxSmbAgentFillEvent) {
KeSetEvent(MRxSmbAgentFillEvent,0,FALSE);
}
if (RxContext != NULL) {
RxDbgTrace(0, Dbg, ("MRxSmbCscSignalFillAgent waiting %08lx\n", RxContext));
RxWaitSync(RxContext);
RxDbgTrace(0, Dbg, ("MRxSmbCscSignalFillAgent end of wait %08lx\n", RxContext));
}
RxDbgTrace(0, Dbg, ("MRxSmbCscSignalFillAgent %08lx\n", RxContext));
FINALLY:
// if (ShadowCritEntered && !PreventLeaveCrit) {
// LeaveShadowCrit();
// }
RxDbgTrace(-1, Dbg, ("MRxSmbCscSignalFillAgent... exit %08lx %08lx\n",
RxContext, Status));
// DbgPrint("MRxSmbCscSignalFillAgent... exit %08lx %08lx\n", Status);
return(Status);
}
VOID
MRxSmbCscOpenAgentFillEvent (
BOOLEAN PostedCall)
{
NTSTATUS Status;
HANDLE EventHandle;
UNICODE_STRING EventName;
OBJECT_ATTRIBUTES ObjectAttributes;
if (PsGetCurrentProcess()!= RxGetRDBSSProcess()) {
//CODE.IMPROVEMENT we should capture the rdbss process
// and avoid this call (RxGetRDBSSProcess)
NTSTATUS PostStatus;
MRXSMBCSC_OPENEVENT_POSTCONTEXT PostContext;
ASSERT(!PostedCall);
// DbgPrint("MRxSmbCscOpenAgentFillEvent: posting...\n");
KeInitializeEvent(&PostContext.PostEvent,
NotificationEvent,
FALSE );
PostStatus = RxPostToWorkerThread(
MRxSmbDeviceObject,
CriticalWorkQueue,
&PostContext.WorkQueueItem,
MRxSmbCscOpenAgentFillEventPostWrapper,
&PostContext);
ASSERT(PostStatus == STATUS_SUCCESS);
KeWaitForSingleObject( &PostContext.PostEvent,
Executive, KernelMode, FALSE, NULL );
// DbgPrint("MRxSmbCscOpenAgentFillEvent: posting done...\n");
return;
}
RtlInitUnicodeString(&EventName,SHARED_FILL_EVENT_NAME_NT);
InitializeObjectAttributes( &ObjectAttributes,
&EventName,
0,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL );
Status = ZwOpenEvent( &EventHandle,
EVENT_ALL_ACCESS,
&ObjectAttributes);
if (Status!=STATUS_SUCCESS) {
RxDbgTrace(0, Dbg, ("MRxSmbCscSignalFillAgent no event %08lx\n",Status));
DbgPrint("MRxSmbCscSignalFillAgent no event %08lx\n",Status);
return;
}
Status = ObReferenceObjectByHandle( EventHandle,
0,
*ExEventObjectType,
KernelMode,
(PVOID *) &MRxSmbAgentFillEvent,
NULL );
ZwClose(EventHandle);
if (Status!=STATUS_SUCCESS) {
RxDbgTrace(0, Dbg, ("MRxSmbCscSignalFillAgent couldn't reference %08lx\n", Status));
DbgPrint("MRxSmbCscSignalFillAgent couldn't reference %08lx\n", Status);
MRxSmbAgentFillEvent = NULL;
return;
}
return;
}