diff -r 000000000000 -r 29b1cd4cb562 bluetoothcommsprofiles/btpan/panagt/panagtremdev.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetoothcommsprofiles/btpan/panagt/panagtremdev.cpp Fri Jan 15 08:13:17 2010 +0200 @@ -0,0 +1,1123 @@ +// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +/** + @file + @note PAN agent remote device class implementation, and remote device state base class implementation +*/ + +#include +#include "panagtlog.h" +#include "panagtremdev.h" +#include "panagtremdevstates.h" + +using namespace PanAgent; + +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY +#include +#include "panmessages.h" + +using namespace ESock; +using namespace Messages; + +#ifdef ESOCK_EXTLOG_ACTIVE +_LIT8(KPanAgtSubTag, "panagt"); +#endif + +#endif +// SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + +#ifdef __FLOG_ACTIVE +_LIT8(KLogComponent, LOG_COMPONENT_PAN_AGENT); +#endif + +CPanRemoteDeviceStateMachine* CPanRemoteDeviceStateMachine::NewL(RInternalSocket& aConnectedSocket, MRemoteDeviceNotify& aParent, CCommsDbAccess& aDatabase) +/** +Create a new bnep channel in the nif using an already connected socket. +@note This is for incoming connections only. +@param aConnectedSocket A preconnected L2CAP socket ready to hand off to BNEP +@param aParent The class to be notified when events occur +@param aDatabase An handle to the commdb facade to allow us to read records from it +*/ + { + CPanRemoteDeviceStateMachine* self = new(ELeave) CPanRemoteDeviceStateMachine(aParent, aDatabase); + CleanupStack::PushL(self); + self->ConstructL(aConnectedSocket); + CleanupStack::Pop(self); + return(self); + } + +CPanRemoteDeviceStateMachine* CPanRemoteDeviceStateMachine::NewL(const TBTDevAddr& aRemDevAddr, MRemoteDeviceNotify& aParent, CCommsDbAccess& aDatabase) +/** +Create a new BNEP channel in the nif by connecting a socket and passing it across. +@note This is for outgoing connections only. +@param aRemDevAddr A preconnected L2CAP socket ready to hand off to BNEP +@param aParent The class to be notified when events occur +@param aDatabase An handle to the commdb facade to allow us to read records from it +*/ + { + CPanRemoteDeviceStateMachine* self = new(ELeave) CPanRemoteDeviceStateMachine(aParent, aDatabase); + CleanupStack::PushL(self); + self->ConstructL(aRemDevAddr); + CleanupStack::Pop(self); + return(self); + } + +CPanRemoteDeviceStateMachine::CPanRemoteDeviceStateMachine(MRemoteDeviceNotify& aParent, CCommsDbAccess& aDatabase) : + CActive(KPanAgtAoPriority), iParent(aParent), iDatabase(aDatabase) + { +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + NM_LOG_NODE_CREATE(KPanAgtSubTag, CPanRemoteDeviceStateMachine); +#endif + CONNECT_LOGGER + CActiveScheduler::Add(this); + } + +void CPanRemoteDeviceStateMachine::ConstructL(const TBTDevAddr& aRemDevAddr) +/** +Connect a new socket and create a BNEP channel to use it. +@note This happens for outgoing connections only. +*/ + { + iRemSockAddr.SetBTAddr(aRemDevAddr); + iRemSockAddr.SetPort(KBnepPsm); + iSockServ.Connect(); + +#ifdef __FLOG_ACTIVE + TBuf tempDevAddrBuf; + iRemSockAddr.BTAddr().GetReadable(tempDevAddrBuf, KNullDesC, KBtAddrSeparator, KNullDesC); + LOG2(_L("RemDev[%x]: connected to %S"), this, &tempDevAddrBuf); +#endif + + // preallocate the shutdown state + iShutdownState = new(ELeave) CPanRemDevStateShutdown(*this); + + LOG(_L("RemDevStateMachine - Deciding whether to perform SDP query")); + TBool sdpQueriesDisabledStatus; + Database().GetBoolL(TPtrC(PAN_SERVICE_EXTENSIONS), TPtrC(PAN_DISABLE_SDP_QUERY), sdpQueriesDisabledStatus); + + SdpQueriesDisabled(sdpQueriesDisabledStatus); + + // if we're allowed to use SDP, then perform the SDP query + CPanRemDevStateBase* nextState; + if(!IsSdpQueriesDisabled()) + { + // open an SDP query subsession + LOG(_L("RemDevStateMachine - Connected to remote SDP querier")); + User::LeaveIfError(RemoteSdpQuerier().Open()); + + nextState = new(ELeave) CPanRemDevStatePerformingSdpQuery(*this); + } + else // SDP queries are inhibited by setting in commdb + { + LOG(_L("RemDevStateMachine - SDP query inhibited by commdb settings")); + nextState = new(ELeave) CPanRemDevStateConnectingSocket(*this); + } + SetState(*nextState); + } + +void CPanRemoteDeviceStateMachine::ConstructL(RInternalSocket& aConnectedSocket) +/** +Take a preconnected socket and create a BNEP channel to use it. +@note This happens for incoming connections only. +*/ + { + User::LeaveIfError(iSocket.Transfer(aConnectedSocket)); // take ownership of the socket, so that the initial state can perform actions on it + + // make a note of the remote device address + iSocket.RemoteName(iRemSockAddr); + iSockServ.Connect(); + +#ifdef __FLOG_ACTIVE + TBuf tempDevAddrBuf; + iRemSockAddr.BTAddr().GetReadable(tempDevAddrBuf, KNullDesC, KBtAddrSeparator, KNullDesC); + LOG2(_L("RemDev[%x]: connected to %S"), this, &tempDevAddrBuf); +#endif + + // preallocate the shutdown state + iShutdownState = new(ELeave) CPanRemDevStateShutdown(*this); + +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + // Create the states first so if we Leave no message is sent to BNEP + CPanRemDevStateBase* nextState = new(ELeave) CPanRemDevStatePerformingRoleNegotiationForIncomingConnection(*this); + CleanupStack::PushL(nextState); + CPanRemDevStatePaused* pausedState = new(ELeave)CPanRemDevStatePaused(*this, *nextState); + CleanupStack::Pop(); + SetState(*pausedState); + + CreateNewBnepConnection(iSocket, TPanMessage::EActivityCreateChannelControllerForIncoming); + OpenPhysicalLinkAdapterL(); + +#else +// !SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + + // create the connection + CreateNewBnepConnectionL(iSocket); + OpenPhysicalLinkAdapterL(); + + CPanRemDevStateBase* nextState = new(ELeave) CPanRemDevStatePerformingRoleNegotiationForIncomingConnection(*this); + SetState(*nextState); +#endif +// SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + } + +CPanRemoteDeviceStateMachine::~CPanRemoteDeviceStateMachine() +/** +Delete the last state on the way out, and tidy up various other bits and pieces +*/ + { +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + __ASSERT_DEBUG(iBnepChannelController == TNodeId::NullId(), PanAgentPanic(EDeletingRemoteDeviceWithoutDisconnecting)); +#else + __ASSERT_DEBUG(!iBnepChannelController, PanAgentPanic(EDeletingRemoteDeviceWithoutDisconnecting)); +#endif + + __ASSERT_DEBUG(iState, PanAgentPanic(ENoStateOnExit)); + __ASSERT_DEBUG(!IsActive(), PanAgentPanic(EStillActiveOnExit)); + + Cancel(); // in release builds, cancel the outstanding request + +#ifndef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + if(iBnepChannelController) + iBnepChannelController->Close(); +#endif + + delete iState; + iState = NULL; + + __ASSERT_DEBUG(!iShutdownState, PanAgentPanic(ERemoteDeviceDidNotUsePreallocatedShutdownState)); + // everyone should be shutting down by leaving from the appropriate method and letting the + // state machine clean up/shut down the connection. If this pointer is not NULL, it suggests + // that someone's created the shutdown state directly (which can fail in OOM situations) + delete iShutdownState; // delete the shutdown state if it exists + iSocket.Close(); // shouldn't be open, but just in case + iPhysicalLinkAdapter.Close(); + iRemoteSdpQuerier.Close(); + iSockServ.Close(); + +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + NM_LOG_NODE_DESTROY(KPanAgtSubTag, CPanRemoteDeviceStateMachine); +#endif + CLOSE_LOGGER + } + + +// +// CActive methods +// + +void CPanRemoteDeviceStateMachine::RunL() +/** +Called when the new socket is connected +@note Only used when creating a new socket for an outgoing connection +*/ + { + __ASSERT_ALWAYS(iState, PanAgentPanic(ENoRemDevState)); + + TRAPD(err, iState->AsyncEventCompleteL()); + if(err) + { + Shutdown(err); + } + } + +void CPanRemoteDeviceStateMachine::DoCancel() +/** +Cancel the connection +*/ + { + __ASSERT_ALWAYS(iState, PanAgentPanic(ENoRemDevState)); + + TRAPD(err, iState->AsyncEventCancelL()); + if(err) + { + Shutdown(err); + } + } + +// +// Other state machine downcall methods +// + +void CPanRemoteDeviceStateMachine::ReadyForRoleRequest() +/** +Pass the request from the local device to the appropriate control channel. +Called from the state machine when it's ready to negotiate roles for this connection +@note This can be called when the connection is active, and indicates that the state machine wants to renegotiate roles +@note Clients must set a flag and initiate a callback to start the RoleRequest() process to prevent call stacks from getting too large +*/ + { + __ASSERT_ALWAYS(iState, PanAgentPanic(ENoRemDevState)); + + TRAPD(err, iState->ReadyForRoleRequestL()); + if(err) + { + Cancel(); // cancel any outstanding async requests that states may have had running before shutting down + // note - not all states use async requests, so this may have no effect + Shutdown(err); + } + } + +void CPanRemoteDeviceStateMachine::Disconnect() +/** +Locally initiated disconnect +*/ + { + __ASSERT_ALWAYS(iState, PanAgentPanic(ENoRemDevState)); + + TRAPD(err, iState->ShutdownL()); + if(err) + { + Cancel(); // cancel any outstanding async requests that states may have had running before shutting down + // note - not all states use async requests, so this may have no effect + Shutdown(err); + } + } + +TInt CPanRemoteDeviceStateMachine::DisallowRoleSwitch() +/** +Change the link policy to prevent other devices performing master/slave switches +@note This is intended to lock us in the master role +*/ + { + TInt err = iPhysicalLinkAdapter.PreventRoleSwitch(); + +#ifdef __FLOG_ACTIVE + TBuf tempDevAddrBuf; + iRemSockAddr.BTAddr().GetReadable(tempDevAddrBuf, KNullDesC, KBtAddrSeparator, KNullDesC); + LOG2(_L("RemDev[%S]: ...prevent role change returned %d"), &tempDevAddrBuf, err); +#endif + + return err; + } + +TInt CPanRemoteDeviceStateMachine::AllowRoleSwitch() +/** +Change the link policy to allow other devices to perform master/slave switches +*/ + { + TInt err = iPhysicalLinkAdapter.AllowRoleSwitch(); + +#ifdef __FLOG_ACTIVE + TBuf tempDevAddrBuf; + iRemSockAddr.BTAddr().GetReadable(tempDevAddrBuf, KNullDesC, KBtAddrSeparator, KNullDesC); + LOG2(_L("RemDev[%S]: ...allow role change returned %d"), &tempDevAddrBuf, err); +#endif + + return err; + } + +TBTDevAddr CPanRemoteDeviceStateMachine::DevAddr() const +/** +Return the device address of the remote device +*/ + { + return(iRemSockAddr.BTAddr()); + } + +// +// MPanConnectionNotify methods +// + +void CPanRemoteDeviceStateMachine::BnepRoleRequestFromRemoteDevice(const TUUID& aRequestedLocalRole, const TUUID& aRequestedRemoteRole) +/** +Request from remote device for given BNEP roles +*/ + { + __ASSERT_ALWAYS(iState, PanAgentPanic(ENoRemDevState)); + + TRAPD(err, iState->BnepRoleRequestFromRemoteDeviceL(aRequestedLocalRole, aRequestedRemoteRole)); + if(err) + { + Cancel(); // cancel any outstanding async requests that states may have had running before shutting down + // note - not all states use async requests, so this may have no effect + Shutdown(err); + } + } + +void CPanRemoteDeviceStateMachine::BnepRoleResponseFromRemoteDevice(TBnepSetupConnectionResponseMessage aRoleResponseCode) +/** +Response from remote device to our request for BNEP roles +*/ + { + __ASSERT_ALWAYS(iState, PanAgentPanic(ENoRemDevState)); + + TRAPD(err, iState->BnepRoleResponseFromRemoteDeviceL(aRoleResponseCode)); + if(err) + { + Cancel(); // cancel any outstanding async requests that states may have had running before shutting down + // note - not all states use async requests, so this may have no effect + Shutdown(err); + } + } + +void CPanRemoteDeviceStateMachine::SetRetryConnect() + { + iParent.SetRetryConnect(*this); + } + +void CPanRemoteDeviceStateMachine::RemoteDeviceDisconnect(TInt aError) +/** +The remote device has disconnected +*/ + { + __ASSERT_ALWAYS(iState, PanAgentPanic(ENoRemDevState)); + + TRAPD(err, iState->RemoteDeviceDisconnectL(aError)); + if(err) + { + Cancel(); // cancel any outstanding async requests that states may have had running before shutting down + // note - not all states use async requests, so this may have no effect + Shutdown(err); + } + } + +TInt CPanRemoteDeviceStateMachine::IncrementConnectionRetryAttempts() + { + return iConnectionRetryAttempts++; + } + +void CPanRemoteDeviceStateMachine::ResetConnectionRetryAttempts() + { + iConnectionRetryAttempts = 0; + } + +void CPanRemoteDeviceStateMachine::ResetRetryParameters() + { + iRemoteWorthTryingRoles.ResetWorthTryingRoles(); + } + +TBool CPanRemoteDeviceStateMachine::WorthTrying() + { + LOG(_L("CPanRemoteDeviceStateMachine::WorthTrying")); + TBool retval = EFalse; // assume its not worth retrying until we prove otherwise + + if(iParent.WorthTrying(iRemoteWorthTryingRoles)) + { + if (RemoteWorthTryingRolesList().IsWorthTryingU()) + { + retval = ETrue; + } + else if (RemoteWorthTryingRolesList().IsWorthTryingGn()) + { + retval = ETrue; + } + else if (RemoteWorthTryingRolesList().IsWorthTryingNap()) + { + retval = ETrue; + } + } + return(retval); + } + +TRemoteDeviceState CPanRemoteDeviceStateMachine::GetState() const + { + TRemoteDeviceState state = EIdle; + if(iState) + { + state = iState->GetState(); + } + return state; + } + +TBool CPanRemoteDeviceStateMachine::NewConnectedDeviceProgressSent() const + { + return iNewConnectedDeviceProgressSent; + } + +void CPanRemoteDeviceStateMachine::SetNewConnectedDeviceProgressSent(TBool aNewConnectedDeviceProgressSent) + { + iNewConnectedDeviceProgressSent = aNewConnectedDeviceProgressSent; + } + +#ifndef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY +MPanLinkControlBase& CPanRemoteDeviceStateMachine::BnepConnectionController() + { + return iParent.BnepConnectionController(); + } +#endif + + + +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY +/** +*/ +void CPanRemoteDeviceStateMachine::ReceivedL(const Messages::TRuntimeCtxId& aSender, const Messages::TNodeId& /* aRecipient */, Messages::TSignatureBase& aCFMessage) + { + if (aCFMessage.MessageId().Realm() == TPanMessage::ERealmId) + { + switch (aCFMessage.MessageId().MessageId()) + { + case TPanMessage::TChannelControllerCreated::EId: + { + const TNodeCtxId& ctxId = address_cast (aSender); + TUint activityId = ctxId.NodeCtx(); + TPanMessage::TChannelControllerCreated& msg = message_cast(aCFMessage); + if (activityId == TPanMessage::EActivityCreateChannelControllerForIncoming) + { + // We now know that the socket has been transfered, or an error has occured + // and that either way it is now safe for the incoming connection listener + // to continue accepting connections + iParent.RestartIncomingConnectionListener(msg.iValue); + } + + if (msg.iValue == KErrNone) + { + // Channel controller created - transition into whatever next + // state is waiting + iBnepChannelController = aSender; + + // We would expect that iState should always be the paused state when + // we get here. We assert it in debug builds in case something we + // haven't accounted for changes it unexpectedly + __ASSERT_DEBUG(iState->iStateNumber == CPanRemDevStateBase::EPanRemDevStatePaused, PanAgentPanic(EPanAgtUnexpectedStateChange)); + if (iState->iStateNumber == CPanRemDevStateBase::EPanRemDevStatePaused) + { + // Calling AsyncEventCompleteL() on the paused state will make it + // transition to the real state, start its OnEntryL() processing + TRAPD(err, iState->AsyncEventCompleteL()); + if (err != KErrNone) + { + Shutdown(err); + } + } + } + else + { + // Error handling for the TCreateChannelController + if (activityId == TPanMessage::EActivityCreateChannelControllerForIncoming) + { + // For outgoing (initial connect or retry connect) the handling should + // be a call to Shutdown(msg.iValue); + Shutdown(msg.iValue); + } + else if (activityId != TPanMessage::EActivityCreateChannelControllerForIncoming) + { + __ASSERT_DEBUG(EFalse, PanAgentPanic(EPanAgtUnexpectedMessage)); + } + } + } + break; + + case TPanMessage::TRoleRequestFromRemoteDevice::EId: + { + TPanMessage::TRoleRequestFromRemoteDevice& msg = message_cast(aCFMessage); + BnepRoleRequestFromRemoteDevice(msg.iRequestedLocalRole, msg.iRequestedRemoteRole); + } + break; + + case TPanMessage::TRoleResponseFromRemoteDevice::EId: + { + TPanMessage::TRoleResponseFromRemoteDevice& msg = message_cast(aCFMessage); + BnepRoleResponseFromRemoteDevice(msg.iSetupResponse); + } + break; + + case TPanMessage::TRemoteDeviceDisconnect::EId: + { + TPanMessage::TRemoteDeviceDisconnect& msg = message_cast(aCFMessage); + RemoteDeviceDisconnect(msg.iValue); + } + break; + + default: + __ASSERT_DEBUG(EFalse, PanAgentPanic(EPanAgtUnexpectedMessage)); + break; + } + } + else + { + __ASSERT_DEBUG(EFalse, PanAgentPanic(EPanAgtUnexpectedMessage)); + } + + // Absorb messages + aCFMessage.ClearMessageId(); + } +#endif +// SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + + +// +// MPanAgtRemDevStateMachineNotify methods +// + +// +// getter methods +// +TBluetoothPanRole& CPanRemoteDeviceStateMachine::LocalRole() +/** +Get a handle to the local role +*/ + { + return(iLocalRole); + } + +TBluetoothPanRole& CPanRemoteDeviceStateMachine::RemoteRole() +/** +Get a handle to the remote role +*/ + { + return(iRemoteRole); + } + +RPanRemoteSdpQuerier& CPanRemoteDeviceStateMachine::RemoteSdpQuerier() +/** +Get handle to PAN remote SDP querier +*/ + { + return(iRemoteSdpQuerier); + } + + +TPanDeviceRolesList& CPanRemoteDeviceStateMachine::RemoteRolesList() +/** +Return a handle to the remote device roles list +*/ + { + return(iRemotePanRolesFromSdp); + } + +TPanDeviceWorthTryingRolesList& CPanRemoteDeviceStateMachine::RemoteWorthTryingRolesList() +/** +Return a handle to the remote device roles list +*/ + { + return(iRemoteWorthTryingRoles); + } + +TBTSockAddr& CPanRemoteDeviceStateMachine::RemSockAddr() +/** +Return the remote device address +*/ + { + return(iRemSockAddr); + } + +RInternalSocket& CPanRemoteDeviceStateMachine::Socket() +/** +Get a handle to the socket +*/ + { + return(iSocket); + } + +CCommsDbAccess& CPanRemoteDeviceStateMachine::Database() +/** +Get a handle to commdb +*/ + { + return(iDatabase); + } + +TRequestStatus& CPanRemoteDeviceStateMachine::Status() +/** +Return this objects TRequestStatus +*/ + { + return(iStatus); + } + +TBool CPanRemoteDeviceStateMachine::IsSdpQueriesDisabled() +/** +Are SDP queries disabled by settings in commdb? +*/ + { + return(iSdpQueriesDisabled); + } +void CPanRemoteDeviceStateMachine::SdpQueriesDisabled(TBool aSdpQueriesStatus) + { + iSdpQueriesDisabled = aSdpQueriesStatus; + } + +TInt CPanRemoteDeviceStateMachine::Error() const +/** +Return the last error to occur +*/ + { + return(iError); + } + +TBool CPanRemoteDeviceStateMachine::HasBnepChannel() const +/** +Have we got to a stage where we have a BNEP channel open? +*/ + { +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + return(iBnepChannelController != TNodeId::NullId() ? ETrue : EFalse); +#else + return(iBnepChannelController ? ETrue : EFalse); +#endif + } + +// +// do'er methods +// +void CPanRemoteDeviceStateMachine::SetActive() +/** +Set this object active +*/ + { + CActive::SetActive(); + } + +void CPanRemoteDeviceStateMachine::Cancel() +/** +Cancel the outstanding request +*/ + { + CActive::Cancel(); + } + +void CPanRemoteDeviceStateMachine::DeviceActive() +/** +Inform the PAN agent role state machine that we are active +*/ + { + iParent.DeviceActive(*this); + } + +void CPanRemoteDeviceStateMachine::RoleChangeFailed() +/** +Inform the PAN agent role state machine that the role upgrade failed +*/ + { + iParent.DeviceRoleChangeFailed(*this); + } + +void CPanRemoteDeviceStateMachine::ShutdownComplete() +/** +Inform the PAN agent role state machine that we have shut down +*/ + { + iParent.DeviceDisconnected(*this); + } + +TInt CPanRemoteDeviceStateMachine::InitiateOutgoingConnection(TBluetoothPanRole& aLocalRole, TBluetoothPanRole& aRemoteRole, TPanDeviceWorthTryingRolesList& aWorthTryingRemoteRoles) + { + return iParent.InitiateOutgoingConnection(aLocalRole, aRemoteRole, aWorthTryingRemoteRoles); + } + +TInt CPanRemoteDeviceStateMachine::PerformLocalRoleChangeRequest(TBluetoothPanRole& aLocalRole, TBluetoothPanRole& aRemoteRole) + { + return iParent.PerformLocalRoleChangeRequest(aLocalRole, aRemoteRole); + } + +TInt CPanRemoteDeviceStateMachine::RoleChangeRequestFromPeer(TBluetoothPanRole aLocalRole, TBluetoothPanRole aRemoteRole) + { + return iParent.RoleChangeRequestFromPeer(aLocalRole, aRemoteRole); + } + +TInt CPanRemoteDeviceStateMachine::IncomingConnectionFromPeer(TBluetoothPanRole aLocalRole, TBluetoothPanRole aRemoteRole) + { + return iParent.IncomingConnectionFromPeer(aLocalRole, aRemoteRole); + } + +void CPanRemoteDeviceStateMachine::SendRoleRequest(TBluetoothPanRole aLocalRole, TBluetoothPanRole aRemoteRole) +/** +Send a role request to the remote device +@param aLocalRole The proposed local role +@param aRemoteRole The proposed remote role +*/ + { +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + LOG3(_L("RemDev[%x]: - sending role request, local: %x, remote: %x"), this, aLocalRole, aRemoteRole); + __ASSERT_ALWAYS(iBnepChannelController != TNodeId::NullId(), PanAgentPanic(ECallToBnepChannelBeforeChannelSetup)); + __ASSERT_DEBUG(aLocalRole!=EPanRoleUnknown, PanAgentPanic(ESendingUnknownRoleInRoleRequest)); + __ASSERT_DEBUG(aRemoteRole!=EPanRoleUnknown, PanAgentPanic(ESendingUnknownRoleInRoleRequest)); + + TPanMessage::TRoleRequestFromLocalDevice msg(aLocalRole, aRemoteRole); + RClientInterface::OpenPostMessageClose(Id(),iBnepChannelController,msg); + +#else +// !SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + __ASSERT_ALWAYS(iBnepChannelController, PanAgentPanic(ECallToBnepChannelBeforeChannelSetup)); + __ASSERT_DEBUG(aLocalRole!=EPanRoleUnknown, PanAgentPanic(ESendingUnknownRoleInRoleRequest)); + __ASSERT_DEBUG(aRemoteRole!=EPanRoleUnknown, PanAgentPanic(ESendingUnknownRoleInRoleRequest)); + + LOG3(_L("RemDev[%x]: - sending role request, local: %x, remote: %x"), this, aLocalRole, aRemoteRole); + + iBnepChannelController->BnepRoleRequestFromLocalDevice(aLocalRole, aRemoteRole); +#endif +// SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + } + +void CPanRemoteDeviceStateMachine::SendRoleResponse(TBnepSetupConnectionResponseMessage aRoleResponseCode) +/** +Send a role reponse to the remote device +@param aRoleReponseCode A BNEP error code indicating the status of the request +*/ + { +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + __ASSERT_ALWAYS(iBnepChannelController != TNodeId::NullId(), PanAgentPanic(ECallToBnepChannelBeforeChannelSetup)); + + TPanMessage::TRoleResponseFromLocalDevice msg(aRoleResponseCode); + RClientInterface::OpenPostMessageClose(Id(),iBnepChannelController,msg); +#else +// !SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + + __ASSERT_ALWAYS(iBnepChannelController, PanAgentPanic(ECallToBnepChannelBeforeChannelSetup)); + iBnepChannelController->BnepRoleResponseFromLocalDevice(aRoleResponseCode); +#endif +// SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + } + +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY +/** +Get BNEP to create a new BNEP level connection for this remote device +*/ +void CPanRemoteDeviceStateMachine::CreateNewBnepConnection(RInternalSocket& aConnectedSocket, TPanMessage::TPanActivity aActivity) + { + __ASSERT_DEBUG(iBnepChannelController == TNodeId::NullId(), PanAgentPanic(EChannelControllerAlreadyExists)); + + TPanMessage::TCreateChannelController msg(&aConnectedSocket); + RClientInterface::OpenPostMessageClose(TNodeCtxId(aActivity,Id()),iParent.BnepConnectionManager(),msg); + } + +#else +// !SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + +/** +Get BNEP to create a new BNEP level connection for this remote device +*/ +void CPanRemoteDeviceStateMachine::CreateNewBnepConnectionL(RInternalSocket& aConnectedSocket) + { + __ASSERT_DEBUG(!iBnepChannelController, PanAgentPanic(EChannelControllerAlreadyExists)); + iBnepChannelController = &(iParent.BnepConnectionManager().NewBnepConnectionL(aConnectedSocket, *this)); + } +#endif +// SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + + +void CPanRemoteDeviceStateMachine::DisconnectBnepChannel() +/** +Tell the BNEP channel to disconnect; if there is no BNEP channel, just return +*/ + { +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + if(iBnepChannelController != TNodeId::NullId()) + { + TPanMessage::TCloseChannelController msg; + RClientInterface::OpenPostMessageClose(Id(),iBnepChannelController,msg); + iBnepChannelController = TNodeId::NullId(); + } + +#else +// !SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + if(iBnepChannelController) + { + iBnepChannelController->Close(); // shutdown the connection if it exists and detach this object from BNEP + iBnepChannelController = NULL; + } +#endif +// SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + } + +void CPanRemoteDeviceStateMachine::SetUplinkAccessAllowed(TBool aAllowed) + { + // Nothing to be done if the argument matches the current state. + if(aAllowed != iUplinkAccessAllowed) + { + if(aAllowed) + { + // Close any existing connection that has access to the uplink + // THIS SHOULD BE REMOVED WHEN >1 REMOTE DEVICE IS ALLOWED TO ACCESS THE UPLINK. + iParent.CloseExistingConnectionWithUplinkAccess(); + } + + iUplinkAccessAllowed = aAllowed; + +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + // Inform BNEP that packets can be forwarded to the uplink + TPanMessage::TSetUplinkAccessAllowedForBnepLink msg(iUplinkAccessAllowed); + RClientInterface::OpenPostMessageClose(Id(),iBnepChannelController,msg); + +#else + // Inform BNEP that packets can be forwarded to the uplink + iBnepChannelController->SetUplinkAccessAllowedForBnepLink(iUplinkAccessAllowed); +#endif + } + } + +TBool CPanRemoteDeviceStateMachine::UplinkAccessAllowed() const + { + return iUplinkAccessAllowed; + } + +void CPanRemoteDeviceStateMachine::SetState(CPanRemDevStateBase& aState) +/** +Change the current state to the one provided +*/ + { + iState = &aState; + TRAPD(err, iState->OnEntryL()); + if(err) + { + Cancel(); // cancel any outstanding async requests that states may have had running before shutting down + // note - not all states use async requests, so this may have no effect + Shutdown(err); + } + } + +RBTPhysicalLinkAdapter& CPanRemoteDeviceStateMachine::PhysicalLinkAdapter() + { + return iPhysicalLinkAdapter; + } + +void CPanRemoteDeviceStateMachine::OpenPhysicalLinkAdapterL() + { + TBTDevAddr addr = RemSockAddr().BTAddr(); + User::LeaveIfError( iPhysicalLinkAdapter.Open(iSockServ, addr) ); + } + +void CPanRemoteDeviceStateMachine::Shutdown(TInt aErr) +/** +Shutdown the connection using the preallocated shutdown state +@note This can either be because an unrecoverable error occured, or just a normal shutdown +*/ + { + __ASSERT_ALWAYS(iShutdownState, PanAgentPanic(EDoubleShutdownAttemptOnDevice)); + + iError = aErr; + + // set the member pointer to NULL to indicate that we've gone to the shutdown state + CPanRemDevStateBase* shutdownState = iShutdownState; // take a copy of the pointer, so we can NULLify the one in the class + iShutdownState = NULL; // shutdown is about to be the active state, so drop the second pointer to it + + // if the state has left, then it won't have performed the setup of the next state correctly + // this code performs the same actions to cleanup the old state and activate the new, but in + // reverse order - otherwise we'd lose the pointer to the old state when we activated the new + delete iState; + iState = NULL; + SetState(*shutdownState); + } + +void CPanRemoteDeviceStateMachine::GetExistingConnections(TPanConnectionList& aPanConnectionList) + { + iParent.GetExistingConnections(aPanConnectionList); + } + + +// +// State base class implementations +// + +CPanRemDevStateBase::CPanRemDevStateBase(MPanRemDevStateMachineNotify& aStateMachine, TPanRemDevStates aStateNumber) : +#ifdef _DEBUG + iStateMachine(aStateMachine), iStateNumber(aStateNumber) +#else + iStateMachine(aStateMachine), iStateNumber(aStateNumber) +#endif // _DEBUG +/** +Stash the state machine handle in our variable +*/ + { } + +CPanRemDevStateBase::~CPanRemDevStateBase() +/** +Nothing to do here... +*/ + { } + +/** +Calls the appropriate panic function to encode the panic +code with the current state identifier. +@param aPanic The panic code that the state is panicking with. +*/ +void CPanRemDevStateBase::PanicInState(TPanAgentPanic aPanic) const + { + PanAgentPanic(aPanic, iStateNumber); + } + +void CPanRemDevStateBase::BnepRoleRequestFromRemoteDeviceL(const TUUID& /*aRequestedLocalRole*/, const TUUID& /*aRequestedRemoteRole*/) +/** +Base class implementation - should never be called +*/ + { + PanicInState(EInvalidBnepRoleRequestReceived); + } + +void CPanRemDevStateBase::BnepRoleResponseFromRemoteDeviceL(TBnepSetupConnectionResponseMessage /*aRoleResponseCode*/) +/** +Base class implementation - should never be called +*/ + { + PanicInState(EInvalidBnepRoleResponseReceived); + } + +void CPanRemDevStateBase::RemoteDeviceDisconnectL(TInt /*aError*/) +/** +Base class implementation - should never be called +*/ + { + PanicInState(EInvalidRemoteDeviceDisconnectReceived); + } + +void CPanRemDevStateBase::ReadyForRoleRequestL() +/** +Base class implementation - should never be called +*/ + { + PanicInState(EInvalidReadyForRoleRequestReceived); + } + +void CPanRemDevStateBase::AsyncEventCompleteL() +/** +Base class implementation - should never be called +*/ + { + PanicInState(EUnexpectedAsyncEventReceivedByState); + } + +void CPanRemDevStateBase::AsyncEventCancelL() +/** +Base class implementation - should never be called +*/ + { + PanicInState(EUnexpectedAsyncEventReceivedByState); + } + +TInt CPanRemDevStateBase::PerformMasterSlaveSwitchIfNecessary(TBluetoothPanRole aLocalRole) +/** + +*/ + { + TInt rerr = KErrNone; + __ASSERT_ALWAYS((aLocalRole==EPanRoleU)||(aLocalRole==EPanRoleGn)||(aLocalRole==EPanRoleNap), PanicInState(ETryingToDecideWhetherToBecomePiconetMasterBasedOnInvalidRole)); + + if(aLocalRole==EPanRoleU) + { + LOG1(_L("RemDevSB: ...local role %x, don't need to be master"), aLocalRole); + } + else // we *must* be piconet master + { + // Check the current Master Slave role for this physical link. + TUint32 currentPhyState; + TInt err = StateMachine().PhysicalLinkAdapter().PhysicalLinkState(currentPhyState); + LOG2(_L("PerformMasterSlaveSwitchIfNecessary: PhysicalLinkState Err = %d, Link State = %x"), + err, currentPhyState); + + // If the current PHY state was retrieved successfully and the state indicates that + // this device is not currently master of the PHY then attempt to switch roles. + if(err == KErrNone && !(currentPhyState & ENotifyMaster)) + { + rerr = BecomePiconetMaster(); + } + else + { + // The represents the following logic: + // If retrieval of PHY state succeed but the local device is already master then + // return KErrNone. + // Otherwise return the failure reason from the PhysicalLinkState method. + rerr = err; + } + } + + return rerr; + } + +void CPanRemDevStateBase::ConvertUuidsToPanRolesL(const TUUID& aLocalRoleUuid, const TUUID& aRemoteRoleUuid, TBluetoothPanRole& aLocalRole, TBluetoothPanRole& aRemoteRole) +/** +Convert the supplied UUIDs to TBluetoothPanRoles +@note If this method leaves with an invalid UUID error, it will have sent a response to the +remote device with the appropriate failure code +@param aLocalRoleUuid The local role UUID +@param aRemoteRoleUuid The remote role UUID +@param aLocalRole On return, contains the local PAN role UUID in TBluetoothPanRole form +@param aRemoteRole On return, contains the remote PAN role UUID in TBluetoothPanRole form +@leave KErrInvalidDestinationServiceUuid, if the destination service UUID is invalid; KErrInvalidSourceServiceUuid if the source service UUID is invalid +*/ + { + TInt err; + err = UuidToPanRole(aLocalRoleUuid, aLocalRole); + if(err) + { + LOG(_L("RemDevState: <[base]> - sending invalid destination service UUID error.")); + StateMachine().SendRoleResponse(EInvalidDestinationServiceUuid); + User::Leave(KErrInvalidDestinationServiceUuid); + } + + err = UuidToPanRole(aRemoteRoleUuid, aRemoteRole); + if(err) + { + LOG(_L("RemDevState: <[base]> - sending invalid source service UUID error.")); + StateMachine().SendRoleResponse(EInvalidSourceServiceUuid); + User::Leave(KErrInvalidSourceServiceUuid); + } + } + +TInt CPanRemDevStateBase::UuidToPanRole(const TUUID& aUuid, TBluetoothPanRole& aRole) +/** +Convert the given UUID into a TBluetoothPanRole +@param aUuid The UUID to convert +@param aRole If successful, on return contains the UUID in TBluetoothPanRole form +@return KErrNone if successful; KErrArgument if the supplied UUID is an invalid PAN role +*/ + { + TInt err; + + TPtrC8 ptr(aUuid.ShortestForm()); + + TUint16 panRole = static_cast(EPanRoleUnknown); + if(ptr.Length()!=2) + { + err = KErrArgument; + } + else + { + panRole = static_cast((ptr.Ptr()[0] << 8) | ptr.Ptr()[1]); + err = KErrNone; + } + + aRole = static_cast(panRole); + + if(err || ((aRole!=EPanRoleU)&&(aRole!=EPanRoleGn)&&(aRole!=EPanRoleNap))) //@note Embeds knowledge of valid PAN roles + { + LOG(_L("RemDevSB: ...could not convert to PAN role, returning KErrArgument.")); + return KErrArgument; + } + else + { + LOG1(_L("RemDevSB: ...converted to PAN role %x"), panRole); + return KErrNone; + } + } + +TInt CPanRemDevStateBase::BecomePiconetMaster() +/** +Become the master of the piconet. +Code from RBTBaseband +@return KErrNone if successful; KErrWaitingForBasebandRoleSwitch if role switch is necessary and in progress; otherwise a Symbian standard error code +*/ + { +#ifdef _DEBUG + TBTDevAddr KNullDevAddr(MAKE_TINT64(0x0000, 0x00000000)); + __ASSERT_DEBUG(StateMachine().RemSockAddr().BTAddr()!=KNullDevAddr, PanicInState(ENullRemoteDeviceAddress)); +#endif + + + TInt err = StateMachine().PhysicalLinkAdapter().RequestMasterRole(); + return (err == KErrNone ? KErrWaitingForBasebandRoleSwitch : err); + } + +MPanRemDevStateMachineNotify& CPanRemDevStateBase::StateMachine() +/** +Return the handle to the state machine +*/ + { + return(iStateMachine); + } + + +