331 lines
7.6 KiB
C
331 lines
7.6 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1996-1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
clstate.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
state machine for gpc client vcs
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Yoram Bernet (yoramb) 28-Dec-1997
|
||
|
Rajesh Sundaram (rajeshsu) 01-Aug-1998
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
Kernel Mode
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Rajesh Sundaram (rajeshsu) 04-Apr-1998 - reworked completly as another state
|
||
|
(CL_INTERNAL_CALL_COMPLETE) added.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "psched.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
/* External */
|
||
|
|
||
|
/* Static */
|
||
|
|
||
|
/* Forward */
|
||
|
|
||
|
/* End Forward */
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Initiate a close call on this VC and notify the GPC. Always called with the VC lock held.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
VOID
|
||
|
InternalCloseCall(
|
||
|
PGPC_CLIENT_VC Vc
|
||
|
)
|
||
|
{
|
||
|
PADAPTER Adapter = Vc->Adapter;
|
||
|
|
||
|
PsDbgOut(DBG_INFO,
|
||
|
DBG_STATE,
|
||
|
("[InternalCloseCall]: Adapter %08X, ClVcState is %s on VC %x\n",
|
||
|
Vc->Adapter, GpcVcState[Vc->ClVcState], Vc));
|
||
|
|
||
|
switch(Vc->ClVcState){
|
||
|
|
||
|
case CL_INTERNAL_CLOSE_PENDING:
|
||
|
|
||
|
//
|
||
|
// We could get here if we get an unbind at our wan instance with a
|
||
|
// NDIS_STATUS_WAN_LINE_DOWN. We could be trying to do an InternalClose
|
||
|
// from both places.
|
||
|
//
|
||
|
|
||
|
PsAssert(Vc->Flags & INTERNAL_CLOSE_REQUESTED);
|
||
|
|
||
|
PS_UNLOCK_DPC(&Vc->Lock);
|
||
|
|
||
|
PS_UNLOCK(&Adapter->Lock);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case CL_CALL_PENDING:
|
||
|
case CL_MODIFY_PENDING:
|
||
|
|
||
|
//
|
||
|
// We've been asked to close before the call
|
||
|
// has completed.
|
||
|
//
|
||
|
// Set a flag so that we'll close it when the
|
||
|
// call completes.
|
||
|
//
|
||
|
|
||
|
PsAssert(!(Vc->Flags & GPC_CLOSE_REQUESTED));
|
||
|
|
||
|
Vc->Flags |= INTERNAL_CLOSE_REQUESTED;
|
||
|
|
||
|
PS_UNLOCK_DPC(&Vc->Lock);
|
||
|
|
||
|
PS_UNLOCK(&Adapter->Lock);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case CL_INTERNAL_CALL_COMPLETE:
|
||
|
|
||
|
//
|
||
|
// The call has been completed, but we may or may not
|
||
|
// have told the GPC. Wait till we tell the GPC. We will
|
||
|
// complete this when we transistion to CL_CALL_COMPLETE
|
||
|
//
|
||
|
|
||
|
PsAssert(!IsBestEffortVc(Vc));
|
||
|
|
||
|
Vc->Flags |= INTERNAL_CLOSE_REQUESTED;
|
||
|
|
||
|
PS_UNLOCK_DPC(&Vc->Lock);
|
||
|
|
||
|
PS_UNLOCK(&Adapter->Lock);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case CL_CALL_COMPLETE:
|
||
|
|
||
|
//
|
||
|
// Transition to CL_INTERNAL_CLOSE_PENDING and
|
||
|
// ask the GPC to close.
|
||
|
//
|
||
|
|
||
|
Vc->ClVcState = CL_INTERNAL_CLOSE_PENDING;
|
||
|
|
||
|
Vc->Flags |= INTERNAL_CLOSE_REQUESTED;
|
||
|
|
||
|
PS_UNLOCK_DPC(&Vc->Lock);
|
||
|
|
||
|
PS_UNLOCK(&Adapter->Lock);
|
||
|
|
||
|
CmCloseCall(Vc);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case CL_GPC_CLOSE_PENDING:
|
||
|
|
||
|
//
|
||
|
// The GPC has already asked us to close. Now,
|
||
|
// we are also closing down - We need not do
|
||
|
// anything here - Need not even inform the GPC.
|
||
|
// we can just pretend as the InternalClose never
|
||
|
// happened
|
||
|
|
||
|
Vc->Flags &= ~INTERNAL_CLOSE_REQUESTED;
|
||
|
|
||
|
PS_UNLOCK_DPC(&Vc->Lock);
|
||
|
|
||
|
PS_UNLOCK(&Adapter->Lock);
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
|
||
|
PS_UNLOCK_DPC(&Vc->Lock);
|
||
|
|
||
|
PS_UNLOCK(&Adapter->Lock);
|
||
|
|
||
|
PsDbgOut(DBG_FAILURE,
|
||
|
DBG_STATE,
|
||
|
("[InternalCloseCall]: invalid state %s on VC %x\n",
|
||
|
GpcVcState[Vc->ClVcState], Vc));
|
||
|
|
||
|
PsAssert(0);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CallSucceededStateTransition(
|
||
|
PGPC_CLIENT_VC Vc
|
||
|
)
|
||
|
{
|
||
|
|
||
|
PsDbgOut(DBG_INFO,
|
||
|
DBG_STATE,
|
||
|
("[CallSucceededStateTransition]: Adapter %08X, ClVcState is %s on VC %x\n",
|
||
|
Vc->Adapter, GpcVcState[Vc->ClVcState], Vc));
|
||
|
|
||
|
PS_LOCK(&Vc->Lock);
|
||
|
|
||
|
switch(Vc->ClVcState){
|
||
|
|
||
|
case CL_GPC_CLOSE_PENDING:
|
||
|
|
||
|
PS_UNLOCK(&Vc->Lock);
|
||
|
|
||
|
PsDbgOut(DBG_FAILURE,
|
||
|
DBG_STATE,
|
||
|
("[CallSucceededStateTransition]: bad state %s on VC %x\n",
|
||
|
GpcVcState[Vc->ClVcState], Vc));
|
||
|
|
||
|
PsAssert(0);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case CL_INTERNAL_CALL_COMPLETE:
|
||
|
|
||
|
PsAssert(!IsBestEffortVc(Vc));
|
||
|
|
||
|
#if DBG
|
||
|
if(Vc->Flags & GPC_MODIFY_REQUESTED) {
|
||
|
PsAssert(! (Vc->Flags & GPC_CLOSE_REQUESTED));
|
||
|
}
|
||
|
|
||
|
if(Vc->Flags & GPC_CLOSE_REQUESTED) {
|
||
|
PsAssert(! (Vc->Flags & GPC_MODIFY_REQUESTED));
|
||
|
}
|
||
|
#endif
|
||
|
//
|
||
|
// Note that if both a modify & a internal remove is requested,
|
||
|
// we just satisfy the modify. When the modify goes into internal
|
||
|
// call complete, we will satify the remove
|
||
|
//
|
||
|
if(Vc->Flags & GPC_MODIFY_REQUESTED) {
|
||
|
|
||
|
NDIS_STATUS Status;
|
||
|
|
||
|
Vc->ClVcState = CL_MODIFY_PENDING;
|
||
|
Vc->Flags &= ~GPC_MODIFY_REQUESTED;
|
||
|
|
||
|
PS_UNLOCK(&Vc->Lock);
|
||
|
|
||
|
Status = CmModifyCall(Vc);
|
||
|
|
||
|
if(Status != NDIS_STATUS_PENDING) {
|
||
|
|
||
|
CmModifyCallComplete(Status, Vc, Vc->ModifyCallParameters);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
if(Vc->Flags & GPC_CLOSE_REQUESTED) {
|
||
|
|
||
|
//
|
||
|
// The GPC has asked us to close after it
|
||
|
// was notified of the call completion but
|
||
|
// before we managed to transition to the
|
||
|
// CL_CALL_COMPLETE state.
|
||
|
//
|
||
|
|
||
|
Vc->ClVcState = CL_GPC_CLOSE_PENDING;
|
||
|
|
||
|
PS_UNLOCK(&Vc->Lock);
|
||
|
|
||
|
CmCloseCall(Vc);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(Vc->Flags & INTERNAL_CLOSE_REQUESTED){
|
||
|
|
||
|
//
|
||
|
// We had an internal close request while
|
||
|
// the call was pending. The GPC has already
|
||
|
// been notified, so - we need to ask it to
|
||
|
// close.
|
||
|
//
|
||
|
|
||
|
Vc->ClVcState = CL_INTERNAL_CLOSE_PENDING;
|
||
|
|
||
|
PS_UNLOCK(&Vc->Lock);
|
||
|
|
||
|
CmCloseCall(Vc);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Vc->ClVcState = CL_CALL_COMPLETE;
|
||
|
|
||
|
PS_UNLOCK(&Vc->Lock);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case CL_MODIFY_PENDING:
|
||
|
//
|
||
|
// Typically, just transition to CL_CALL_COMPLETE
|
||
|
//
|
||
|
PsAssert(!(Vc->Flags & GPC_CLOSE_REQUESTED));
|
||
|
PsAssert(!(Vc->Flags & GPC_MODIFY_REQUESTED));
|
||
|
PsAssert(!IsBestEffortVc(Vc));
|
||
|
|
||
|
Vc->ClVcState = CL_INTERNAL_CALL_COMPLETE;
|
||
|
|
||
|
PS_UNLOCK(&Vc->Lock);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case CL_CALL_PENDING:
|
||
|
//
|
||
|
// Typically, just transition to CL_INTERNAL_CALL_COMPLETE.
|
||
|
//
|
||
|
PsAssert(!(Vc->Flags & GPC_CLOSE_REQUESTED));
|
||
|
PsAssert(!(Vc->Flags & GPC_MODIFY_REQUESTED));
|
||
|
|
||
|
//
|
||
|
// Call succeeded. Leave it up.
|
||
|
//
|
||
|
if(IsBestEffortVc(Vc))
|
||
|
{
|
||
|
Vc->ClVcState = CL_CALL_COMPLETE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Vc->ClVcState = CL_INTERNAL_CALL_COMPLETE;
|
||
|
}
|
||
|
PS_UNLOCK(&Vc->Lock);
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
|
||
|
PS_UNLOCK(&Vc->Lock);
|
||
|
|
||
|
PsDbgOut(DBG_FAILURE,
|
||
|
DBG_STATE,
|
||
|
("[CallSucceededStateTransition]: invalid state %s on VC %x\n",
|
||
|
GpcVcState[Vc->ClVcState], Vc));
|
||
|
|
||
|
PsAssert(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* end clstate.c */
|