diff -r e9b924a62a66 -r 99439b07e980 bluetooth/btstack/linkmgr/roleswitchhelper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetooth/btstack/linkmgr/roleswitchhelper.cpp Tue Sep 14 23:28:24 2010 +0300 @@ -0,0 +1,518 @@ +// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Symbian Foundation License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + + +#include +#include "roleswitchhelper.h" +#include "physicallinksmanager.h" +#include "AclDataQController.h" +#include "ProxySAP.h" +#include "linkmgr.h" + +#ifdef __FLOG_ACTIVE +_LIT8(KLogComponent, LOG_COMPONENT_LINKMGR); +#endif + +CRoleSwitcher::CRoleSwitcher(CPhysicalLinksManager& aLinkMgr, CPhysicalLink& aLink, TBTBasebandRole aRole) + : CPhysicalLinkHelper(aLinkMgr, aLink) + , iRole(aRole) + , iIsEncryptionDisabledForRoleSwitch(EFalse) + { + LOG_FUNC + iState = &iLinkMgr.RoleSwitcherStateFactory().GetState(CRoleSwitcherStateFactory::EIdle); + } + +CRoleSwitcher* CRoleSwitcher::NewL(CPhysicalLinksManager& aLinkMgr, CPhysicalLink& aLink, TBTBasebandRole aRole) + { + LOG_STATIC_FUNC + CRoleSwitcher* self = new(ELeave) CRoleSwitcher(aLinkMgr, aLink, aRole); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CRoleSwitcher::ConstructL() + { + LOG_FUNC + + BaseConstructL(); + + // add ourselves to the list in LinkMgr, LinkMgr will kick off the role change state machine + iLinkMgr.AddRoleSwitcher(*this); + iAddedToLinkMgr = ETrue; + } + +CRoleSwitcher::~CRoleSwitcher() + { + LOG_FUNC + if (iAddedToLinkMgr) + { + iLinkMgr.RemoveRoleSwitcher(*this); + } + } + +void CRoleSwitcher::TimerExpired() + { + LOG_FUNC + + iState->TimerExpired(*this); + } + +void CRoleSwitcher::HandleError( TInt aError) + { + LOG_FUNC + + iState->Error(*this, aError); + } + +void CRoleSwitcher::DisableEncryption() + { + LOG_FUNC + // data traffic suspended + iLinkMgr.LinkManagerProtocol().ACLController().SetParked(iLink.Handle(), ETrue); + NotifyBasebandEvent(ENotifyEncryptionChangeOff); + iLinkMgr.Encrypt(EFalse, iLink); + + // set flag here, it's too late when we receive the event as AccessReqester + // might receive the baseband notification earlier then the flag is set! + iIsEncryptionDisabledForRoleSwitch = ETrue; + } + +void CRoleSwitcher::EnableEncryption() + { + LOG_FUNC + NotifyBasebandEvent(ENotifyEncryptionChangeOn); + iLinkMgr.Encrypt(ETrue, iLink); + // data traffic is enabled in IoctlComplete + } + +void CRoleSwitcher::ChangeRole() + { + LOG_FUNC + NotifyBasebandEvent(ENotifyAnyRole); + iLinkMgr.ChangeRole(iRole, iLink); + } + +void CRoleSwitcher::StartHelper() + { + LOG_FUNC + iState->Start(*this); + } + +void CRoleSwitcher::SaveEncryption() + { + LOG_FUNC + iIsEncrypted = iLink.Encrypted(); + } + +void CRoleSwitcher::LogRoleSwitchSuccessful(TBTBasebandEventNotification& aEvent) const + { + LOG_FUNC + TInt eventType; + eventType = (iRole == EMaster ? ENotifyMaster :ENotifySlave); + + if (aEvent.EventType()==eventType && aEvent.ErrorCode()==KErrNone) + { + LOG(_L("CRoleSwitcher RoleSwitch OK")); + } + else + { + LOG(_L("CRoleSwitcher RoleSwitch failed")); + } + } + +void CRoleSwitcher::EventReceived(TBTBasebandEventNotification& aEvent) + { + LOG_FUNC + iState->EventReceived(*this, aEvent); + } + + +//---------------------------------------------------------------------------------- +// STATE FACTORY +//---------------------------------------------------------------------------------- + +CRoleSwitcherStateFactory* CRoleSwitcherStateFactory::NewL() + { + LOG_STATIC_FUNC + CRoleSwitcherStateFactory* ret=new (ELeave) CRoleSwitcherStateFactory(); + CleanupStack::PushL(ret); + ret->ConstructL(); + CleanupStack::Pop(ret); + return ret; + } + +void CRoleSwitcherStateFactory::ConstructL() + { + LOG_FUNC + iStates[EIdle] =new (ELeave) TRSStateIdle(*this); + iStates[EDisablingLPM] =new (ELeave) TRSStateDisablingLPM(*this); + iStates[EDisablingEncryption] =new (ELeave) TRSStateDisablingEncryption(*this); + iStates[EChangingRole] =new (ELeave) TRSStateChangingRole(*this); + iStates[EChangingRoleWithEPR] =new (ELeave) TRSStateChangingRoleWithEPR(*this); + iStates[EEnablingEncryption] =new (ELeave) TRSStateEnablingEncryption(*this); + } + +CRoleSwitcherStateFactory::CRoleSwitcherStateFactory() + { + LOG_FUNC + iStates.DeleteAll(); + } + +TRoleSwitcherState& CRoleSwitcherStateFactory::GetState(CRoleSwitcherStateFactory::TRoleSwitcherStates aState) + { + LOG_FUNC + __ASSERT_DEBUG(iStates[aState], Panic(ERoleSwitcherInvalidState)); + return *iStates[aState]; + } + +TInt CRoleSwitcherStateFactory::StateIndex(const TRoleSwitcherState* aState) const + { + LOG_FUNC + TInt state; + for (state = 0; state < ERoleSwitcherMaxState; state++) + { + if (iStates[state] == aState) + { + return state; + } + } + + return KUnknownState; + } + + +//---------------------------------------------------------------------------------- +// STATES +//---------------------------------------------------------------------------------- + +TRoleSwitcherState::TRoleSwitcherState(CRoleSwitcherStateFactory& aFactory) +: iFactory(aFactory) + { + LOG_FUNC + } + +void TRoleSwitcherState::PanicInState(TLinkPanic aPanic) const + { + LOG_FUNC + Panic(aPanic, iFactory.StateIndex(this)); + } + +void TRoleSwitcherState::ChangeState(CRoleSwitcher& aContext, CRoleSwitcherStateFactory::TRoleSwitcherStates aState) const + { + LOG_FUNC + + aContext.iState->Exit(aContext); + +#ifdef __FLOG_ACTIVE + TRoleSwitcherState* state=&iFactory.GetState(aState); + LOG2(_L("RoleSwitcher: State %S -> %S"), &aContext.iState->iName, &state->iName); +#endif //__FLOG_ACTIVE + aContext.iState=&iFactory.GetState(aState); + + aContext.iState->Enter(aContext); + } + +void TRoleSwitcherState::Enter(CRoleSwitcher& /*aContext*/) const + { + LOG_FUNC + // do nothing + } + +void TRoleSwitcherState::Exit(CRoleSwitcher& /*aContext*/) const + { + LOG_FUNC + // do nothing + } + +void TRoleSwitcherState::Start(CRoleSwitcher& /*aContext*/) const + { + LOG_FUNC + PanicInState(ERoleSwitcherStateMachineInvalidEvent); + } + +void TRoleSwitcherState::Error(CRoleSwitcher& aContext, TInt /*aErr*/) const + { + LOG_FUNC + aContext.CancelNotify(); + aContext.RemoveTimer(); + ChangeState(aContext, CRoleSwitcherStateFactory::EIdle); + } + +void TRoleSwitcherState::EventReceived(CRoleSwitcher& /*aContext*/, TBTBasebandEventNotification& /*aEvent*/) const + { + LOG_FUNC + // do nothing + } + +void TRoleSwitcherState::TimerExpired(CRoleSwitcher& aContext) const + { + LOG_FUNC + ChangeState(aContext, CRoleSwitcherStateFactory::EIdle); + } + +//---------------------------------------------------------------------------------- + +TRSStateIdle::TRSStateIdle(CRoleSwitcherStateFactory& aFactory) +: TRoleSwitcherState(aFactory) + { + LOG_FUNC + STATENAME("TRSStateIdle"); + } + +void TRSStateIdle::Start(CRoleSwitcher& aContext) const + { + LOG_FUNC + aContext.QueueTimer(KTimeoutRoleSwitch); // watchdog timer + ChangeState(aContext, CRoleSwitcherStateFactory::EDisablingLPM); + } + +void TRSStateIdle::Enter(CRoleSwitcher& aContext) const + { + LOG_FUNC + // async call to delete the helper + aContext.iLink.AsyncDeleteRoleSwitcher(); + } + +//---------------------------------------------------------------------------------- + +TRSStateDisablingLPM::TRSStateDisablingLPM(CRoleSwitcherStateFactory& aFactory) +: TRoleSwitcherState(aFactory) + { + LOG_FUNC + STATENAME("TRSStateDisablingLPM"); + } + +void TRSStateDisablingLPM::Enter(CRoleSwitcher& aContext) const + { + LOG_FUNC + // DisableLPM even if link is active to prevent possible LPM requests during encryption disabling + + if (aContext.iLink.LinkMode() == EActiveMode) + { + aContext.DisableLPM(); + if (aContext.IsEPRSupported()) + { + ChangeState(aContext, CRoleSwitcherStateFactory::EChangingRoleWithEPR); + } + else + { + ChangeState(aContext, CRoleSwitcherStateFactory::EDisablingEncryption); + } + // don't wait for notification + } + else + { + aContext.NotifyBasebandEvent(ENotifyActiveMode); + aContext.DisableLPM(); + } + } + +void TRSStateDisablingLPM::EventReceived(CRoleSwitcher& aContext, TBTBasebandEventNotification& aEvent) const + { + LOG_FUNC + if (aEvent.EventType()==ENotifyActiveMode && aEvent.ErrorCode()==KErrNone) + { + if (aContext.IsEPRSupported()) + { + ChangeState(aContext, CRoleSwitcherStateFactory::EChangingRoleWithEPR); + } + else + { + ChangeState(aContext, CRoleSwitcherStateFactory::EDisablingEncryption); + } + } + else + { + LOG(_L("CRoleSwitcher RoleSwitch failed in DisableLPM")); + // we can quit SM, don't need to rewind + ChangeState(aContext, CRoleSwitcherStateFactory::EIdle); + } + } + +//---------------------------------------------------------------------------------- +TRSStateDisablingEncryption::TRSStateDisablingEncryption(CRoleSwitcherStateFactory& aFactory) +: TRoleSwitcherState(aFactory) + { + LOG_FUNC + STATENAME("TRSStateDisablingEncryption"); + } + +void TRSStateDisablingEncryption::Enter(CRoleSwitcher& aContext) const + { + LOG_FUNC + aContext.SaveEncryption(); + if (aContext.iIsEncrypted) + { + aContext.DisableEncryption(); + } + else + { + ChangeState(aContext, CRoleSwitcherStateFactory::EChangingRole); + } + } + +void TRSStateDisablingEncryption::EventReceived(CRoleSwitcher& aContext, TBTBasebandEventNotification& aEvent) const + { + LOG_FUNC + if (aEvent.EventType()==ENotifyEncryptionChangeOff && aEvent.ErrorCode()==KErrNone) + { + ChangeState(aContext, CRoleSwitcherStateFactory::EChangingRole); + } + else + { + LOG(_L("CRoleSwitcher RoleSwitch failed in DisableEncryption")); + // before quiting SM , try to enable LPM + ChangeState(aContext, CRoleSwitcherStateFactory::EIdle); + } + } + +void TRSStateDisablingEncryption::TimerExpired(CRoleSwitcher& aContext) const + { + LOG_FUNC + aContext.CancelNotify(); + ChangeState(aContext, CRoleSwitcherStateFactory::EEnablingEncryption); + } + +//---------------------------------------------------------------------------------- +TRSStateChangingRole::TRSStateChangingRole(CRoleSwitcherStateFactory& aFactory) +: TRoleSwitcherState(aFactory) + { + LOG_FUNC + STATENAME("TRSStateChangingRole"); + } + +void TRSStateChangingRole::Enter(CRoleSwitcher& aContext) const + { + LOG_FUNC + aContext.ChangeRole(); + } + +void TRSStateChangingRole::EventReceived(CRoleSwitcher& aContext, TBTBasebandEventNotification& __DEBUG_ONLY(aEvent)) const + { + LOG_FUNC + aContext.RemoveTimer(); // cancel watchdog timer + + FTRACE(aContext.LogRoleSwitchSuccessful(aEvent)); + + + ChangeState(aContext, CRoleSwitcherStateFactory::EEnablingEncryption); + } + +void TRSStateChangingRole::TimerExpired(CRoleSwitcher& aContext) const + { + LOG_FUNC + aContext.CancelNotify(); + ChangeState(aContext, CRoleSwitcherStateFactory::EEnablingEncryption); + } + +//---------------------------------------------------------------------------------- +TRSStateChangingRoleWithEPR::TRSStateChangingRoleWithEPR(CRoleSwitcherStateFactory& aFactory) +: TRoleSwitcherState(aFactory) + { + LOG_FUNC + STATENAME("TRSStateChangingRoleWithEPR"); + } + +void TRSStateChangingRoleWithEPR::Enter(CRoleSwitcher& aContext) const + { + LOG_FUNC + aContext.ChangeRole(); + } + +void TRSStateChangingRoleWithEPR::EventReceived(CRoleSwitcher& aContext, TBTBasebandEventNotification& __DEBUG_ONLY(aEvent)) const + { + LOG_FUNC + aContext.RemoveTimer(); // cancel watchdog timer + + FTRACE(aContext.LogRoleSwitchSuccessful(aEvent)); + + ChangeState(aContext, CRoleSwitcherStateFactory::EIdle); + } + +void TRSStateChangingRoleWithEPR::TimerExpired(CRoleSwitcher& aContext) const + { + LOG_FUNC + aContext.CancelNotify(); + ChangeState(aContext, CRoleSwitcherStateFactory::EIdle); + } + +//---------------------------------------------------------------------------------- +TRSStateEnablingEncryption::TRSStateEnablingEncryption(CRoleSwitcherStateFactory& aFactory) +: TRoleSwitcherState(aFactory) + { + LOG_FUNC + STATENAME("TRSStateEnablingEncryption"); + } + +void TRSStateEnablingEncryption::Enter(CRoleSwitcher& aContext) const + { + LOG_FUNC + if (aContext.iIsEncrypted) + { + aContext.QueueTimer(KTimeoutOneCommand); + aContext.EnableEncryption(); + } + else + { + ChangeState(aContext, CRoleSwitcherStateFactory::EIdle); + } + } + +void TRSStateEnablingEncryption::Exit(CRoleSwitcher& aContext) const + { + LOG_FUNC + if (aContext.iIsEncrypted) + { + // enable data traffic + aContext.iLinkMgr.LinkManagerProtocol().ACLController().SetParked(aContext.iLink.Handle(), EFalse); + } + } + +void TRSStateEnablingEncryption::EventReceived(CRoleSwitcher& aContext, TBTBasebandEventNotification& aEvent) const + { + LOG_FUNC + aContext.RemoveTimer(); // watchdog timer + if (aEvent.EventType()==ENotifyEncryptionChangeOn && aEvent.ErrorCode()==KErrNone) + { + ChangeState(aContext, CRoleSwitcherStateFactory::EIdle); + aContext.iIsEncryptionDisabledForRoleSwitch = EFalse; + } + else + { + LOG(_L("CRoleSwitcher SetEncryption failed, disconnect link")); + if (aContext.iLink.Terminate(ERemoteUserEndedConnection) != KErrNone) + { + LOG(_L("CRoleSwitcher OOM")); + } + ChangeState(aContext, CRoleSwitcherStateFactory::EIdle); + } + } + +void TRSStateEnablingEncryption::TimerExpired(CRoleSwitcher& aContext) const + { + LOG_FUNC + LOG(_L("CRoleSwitcher Timeout in EncryptionEnable, disconnect")); + aContext.CancelNotify(); + if (aContext.iLink.Terminate(ERemoteUserEndedConnection) != KErrNone) + { + LOG(_L("CRoleSwitcher OOM")); + } + ChangeState(aContext, CRoleSwitcherStateFactory::EIdle); + } + + +