--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothcommsprofiles/btpan/panagt/panagtremdevstates.cpp Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,2246 @@
+// 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 connection state implementations
+*/
+
+#include <bluetooth/logger.h>
+#include <networking/panuiinterfaces.h>
+#include "panagtremdevstates.h"
+#include "panagtpolicy.h"
+using namespace PanAgent;
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_PAN_AGENT);
+#endif
+
+//
+// CPanRemDevStatePerformingSdpQuery
+//
+
+CPanRemDevStatePerformingSdpQuery::CPanRemDevStatePerformingSdpQuery(MPanRemDevStateMachineNotify& aStateMachine) :
+ CPanRemDevStateBase(aStateMachine, EPanRemDevStatePerformingSdpQuery), iPanDevRolesListPtr(StateMachine().RemoteRolesList())
+/**
+
+*/
+ {
+ }
+
+void CPanRemDevStatePerformingSdpQuery::OnEntryL()
+/**
+Check out roles in commdb, perform SDP query if necessary, then check it's OK
+@note If SDP queries are inhibited by the setting in commdb, this class will just accept whatever is in there - if there isn't anything then the SDP query will be performed anyway
+*/
+ {
+ // perform SDP query to see what the remote device supports
+ User::LeaveIfError(StateMachine().RemoteSdpQuerier().Query(StateMachine().RemSockAddr().BTAddr(), iPanDevRolesListPtr, StateMachine().Status()));
+ StateMachine().SetActive();
+ }
+
+void CPanRemDevStatePerformingSdpQuery::AsyncEventCompleteL()
+/**
+The SDP query has completed
+*/
+ {
+ //The PAN spec says a device supporting PANU does not have to advertise that on SDP.
+ //But the spec is a bit vague on if such a device is connectable, so we try to connect
+ //to it anyway to maximise interoperability
+ if(StateMachine().Status()==KErrNone || StateMachine().Status()==KErrNotFound)
+ {
+ // If remote doesn't support GN, there is no point try it, so set it to Not WorthTrying
+ if(!StateMachine().RemoteRolesList().SupportsGn())
+ {
+ StateMachine().RemoteWorthTryingRolesList().SetWorthTryingGn(EFalse);
+ }
+ // If remote doesn't support NAP, there is no point try it, so set it to Not WorthTrying
+ if(!StateMachine().RemoteRolesList().SupportsNap())
+ {
+ StateMachine().RemoteWorthTryingRolesList().SetWorthTryingNap(EFalse);
+ }
+
+ // check whether FixedRemoteRole is supported by remote according to SDP query result
+ if(StateMachine().WorthTrying())
+ {
+ CPanRemDevStateBase* nextState = new(ELeave) CPanRemDevStateConnectingSocket(StateMachine());
+ LOG1(_L("RemDevState[%x]: <performing SDP query> - SDP query completed successfully, moving to <connecting socket> state"), &StateMachine());
+ StateMachine().SetState(*nextState);
+ delete this;
+ }
+ else
+ {
+ LOG1(_L("RemDevState[%x]: <performing SDP query> - SDP query completed successfully, but remote doesn't support the Fixed Remote Role we've specified."), &StateMachine());
+ User::Leave(KErrFixRemoteRoleIsNotSupportedByRemote);
+ }
+ }
+ else // error handling
+ {
+ LOG1(_L("RemDevState[%x]: <performing SDP query> - SDP query failed"), &StateMachine());
+ User::Leave(StateMachine().Status().Int());
+ }
+ }
+
+void CPanRemDevStatePerformingSdpQuery::AsyncEventCancelL()
+/**
+The SDP query has been cancelled
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing SDP query> - SDP query cancelled"), &StateMachine());
+
+ StateMachine().RemoteSdpQuerier().CancelQuery();
+ }
+
+void CPanRemDevStatePerformingSdpQuery::ShutdownL()
+/**
+The local device wants us to disconnect
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing SDP query> - locally requested disconnect received"), &StateMachine());
+
+ // outstanding async request will be cancelled by state machine when we leave
+ User::Leave(KErrLocallyInitiatedDisconnect);
+ }
+
+// This returns a distilled (i.e., not the actual remote device state)
+// version of the current connection status of the remote device
+TRemoteDeviceState CPanRemDevStatePerformingSdpQuery::GetState() const
+ {
+ return EIdle;
+ }
+
+//
+// CPanRemDevStateConnectingSocket
+//
+
+CPanRemDevStateConnectingSocket::CPanRemDevStateConnectingSocket(MPanRemDevStateMachineNotify& aStateMachine) :
+ CPanRemDevStateBase(aStateMachine, EPanRemDevStateConnectingSocket)
+/**
+
+*/
+ { }
+
+void CPanRemDevStateConnectingSocket::OnEntryL()
+/**
+
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <connecting socket> - entering state"), &StateMachine());
+
+ TBTServiceSecurity securitySettings;
+ // we override whatever security settings that came with the address with our own
+ securitySettings.SetAuthentication(KPanOutgoignAuthenticationRequired);
+ securitySettings.SetAuthorisation(KPanOutgoingAuthorisationRequired);
+ securitySettings.SetEncryption(KPanOutgoingEncryptionRequired);
+ securitySettings.SetUid(KBTPanAuthorisationUid);
+
+ StateMachine().RemSockAddr().SetSecurity(securitySettings);
+
+#if defined(_DEBUG) && defined(SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY)
+ TInt err = StateMachine().Socket().Open(KBTAddrFamily, KSockSeqPacket, KL2CAP);
+ __ASSERT_DEBUG(err != KErrBadName, PanicInState(EPanAgtMissingBinding));
+ User::LeaveIfError(err);
+#else
+ User::LeaveIfError(StateMachine().Socket().Open(KBTAddrFamily, KSockSeqPacket, KL2CAP));
+#endif
+
+ TUint16 bnepMtu = KBnepMtu;
+ TPckg<TUint16> mtuBuf(bnepMtu);
+
+ User::LeaveIfError(StateMachine().Socket().SetOpt(KL2CAPInboundMTU, KSolBtL2CAP, mtuBuf));
+ User::LeaveIfError(StateMachine().Socket().SetOpt(KL2CAPNegotiatedOutboundMTU, KSolBtL2CAP, mtuBuf));
+ // Register the CoD service - Networking bit (especially relevant for WinXP)
+ User::LeaveIfError(StateMachine().Socket().SetOpt(KBTRegisterCodService, KSolBtSAPBase, EMajorServiceNetworking));
+
+ StateMachine().Socket().Connect(StateMachine().RemSockAddr(), StateMachine().Status());
+ StateMachine().SetActive();
+ }
+
+void CPanRemDevStateConnectingSocket::AsyncEventCompleteL()
+/**
+Called when the new socket is connected
+*/
+ {
+ if(StateMachine().Status()==KErrNone)
+ {
+ LOG1(_L("RemDevState[%x]: <connecting socket> - async event complete, socket connected successfully"), &StateMachine());
+
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+ StateMachine().CreateNewBnepConnection(StateMachine().Socket(), TPanMessage::EActivityCreateChannelControllerForOutgoing);
+#else
+ StateMachine().CreateNewBnepConnectionL(StateMachine().Socket());
+#endif
+
+ StateMachine().OpenPhysicalLinkAdapterL();
+
+ CPanRemDevStateBase* nextState = new(ELeave) CPanRemDevStatePerformingRoleNegotiationForOutgoingConnection(StateMachine());
+
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+ CleanupStack::PushL(nextState);
+ CPanRemDevStatePaused* pausedState = new(ELeave)CPanRemDevStatePaused(StateMachine(), *nextState);
+ CleanupStack::Pop();
+ nextState = pausedState;
+#endif
+
+ StateMachine().SetState(*nextState);
+ delete this;
+ }
+ else // did not complete the connection to the remote device...
+ {
+ LOG2(_L("RemDevState[%x]: <connecting socket> - socket connect failed with %d"), &StateMachine(), StateMachine().Status().Int());
+ User::Leave(StateMachine().Status().Int());
+ }
+ }
+
+void CPanRemDevStateConnectingSocket::AsyncEventCancelL()
+/**
+Cancel the socket connect
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <connecting socket> - async event cancelled"), &StateMachine());
+
+ StateMachine().Socket().CancelConnect();
+ StateMachine().Socket().Close();
+ }
+
+void CPanRemDevStateConnectingSocket::ShutdownL()
+/**
+The local device wants us to disconnect
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <connecting socket> - locally requested disconnect received"), &StateMachine());
+
+ // outstanding async request will be cancelled by state machine when we leave
+ User::Leave(KErrLocallyInitiatedDisconnect);
+ }
+
+// This returns a distilled (i.e., not the actual remote device state)
+// version of the current connection status of the remote device
+TRemoteDeviceState CPanRemDevStateConnectingSocket::GetState() const
+ {
+ return EIdle;
+ }
+
+//
+// CPanRemDevStateReconnectingSocket
+//
+
+CPanRemDevStateReconnectingSocket::CPanRemDevStateReconnectingSocket(MPanRemDevStateMachineNotify& aStateMachine) :
+ CPanRemDevStateBase(aStateMachine, EPanRemDevStateConnectingSocket)
+ { }
+
+/**
+ Disconnect the socket for the case where the remote device doesn't
+*/
+void CPanRemDevStateReconnectingSocket::OnEntryL()
+ {
+ LOG1(_L("RemDevState[%x]: <reconnecting socket> - entering state"), &StateMachine());
+ StateMachine().Socket().Close();
+
+ StateMachine().SetRetryConnect();
+ }
+
+/**
+ Wait for device to disconnect before attempting reconnect
+*/
+void CPanRemDevStateReconnectingSocket::RemoteDeviceDisconnectL(TInt /*aErr*/)
+ {
+ LOG1(_L("RemDevState[%x]: <reconnecting socket> - remote device disconnected"), &StateMachine());
+ StateMachine().DisconnectBnepChannel();
+ TBTServiceSecurity securitySettings;
+ // we override whatever security settings that came with the address with our own
+ securitySettings.SetAuthentication(KPanOutgoignAuthenticationRequired);
+ securitySettings.SetAuthorisation(KPanOutgoingAuthorisationRequired);
+ securitySettings.SetEncryption(KPanOutgoingEncryptionRequired);
+ securitySettings.SetUid(KBTPanAuthorisationUid);
+
+ StateMachine().RemSockAddr().SetSecurity(securitySettings);
+
+#if defined(_DEBUG) && defined(SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY)
+ TInt err = StateMachine().Socket().Open(KBTAddrFamily, KSockSeqPacket, KL2CAP);
+ __ASSERT_DEBUG(err != KErrBadName, PanicInState(EPanAgtMissingBinding));
+ User::LeaveIfError(err);
+#else
+ User::LeaveIfError(StateMachine().Socket().Open(KBTAddrFamily, KSockSeqPacket, KL2CAP));
+#endif
+
+ TUint16 bnepMtu = KBnepMtu;
+ TPckg<TUint16> mtuBuf(bnepMtu);
+
+ User::LeaveIfError(StateMachine().Socket().SetOpt(KL2CAPInboundMTU, KSolBtL2CAP, mtuBuf));
+ User::LeaveIfError(StateMachine().Socket().SetOpt(KL2CAPNegotiatedOutboundMTU, KSolBtL2CAP, mtuBuf));
+
+ StateMachine().Socket().Connect(StateMachine().RemSockAddr(), StateMachine().Status());
+ StateMachine().SetActive();
+ }
+
+/**
+Called when the new socket is connected
+*/
+void CPanRemDevStateReconnectingSocket::AsyncEventCompleteL()
+ {
+ if(StateMachine().Status()==KErrNone)
+ {
+ LOG1(_L("RemDevState[%x]: <connecting socket> - async event complete, socket connected successfully"), &StateMachine());
+
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+ StateMachine().CreateNewBnepConnection(StateMachine().Socket(), TPanMessage::EActivityCreateChannelControllerForOutgoing);
+#else
+ StateMachine().CreateNewBnepConnectionL(StateMachine().Socket());
+#endif
+
+ StateMachine().OpenPhysicalLinkAdapterL();
+
+ CPanRemDevStateBase* nextState = new(ELeave) CPanRemDevStatePerformingRoleNegotiationForOutgoingConnection(StateMachine());
+
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+ CleanupStack::PushL(nextState);
+ CPanRemDevStatePaused* pausedState = new(ELeave)CPanRemDevStatePaused(StateMachine(), *nextState);
+ CleanupStack::Pop();
+ nextState = pausedState;
+#endif
+
+ StateMachine().SetState(*nextState);
+ delete this;
+ }
+ else // did not complete the connection to the remote device...
+ {
+ LOG2(_L("RemDevState[%x]: <connecting socket> - socket connect failed with %d"), &StateMachine(), StateMachine().Status().Int());
+ User::Leave(StateMachine().Status().Int());
+ }
+ }
+
+/**
+Cancel the socket connect
+*/
+void CPanRemDevStateReconnectingSocket::AsyncEventCancelL()
+ {
+ LOG1(_L("RemDevState[%x]: <connecting socket> - async event cancelled"), &StateMachine());
+
+ StateMachine().Socket().CancelConnect();
+ StateMachine().Socket().Close();
+ }
+
+/**
+The local device wants us to disconnect
+*/
+void CPanRemDevStateReconnectingSocket::ShutdownL()
+ {
+ LOG1(_L("RemDevState[%x]: <connecting socket> - locally requested disconnect received"), &StateMachine());
+
+ // outstanding async request will be cancelled by state machine when we leave
+ User::Leave(KErrLocallyInitiatedDisconnect);
+ }
+
+// This returns a distilled (i.e., not the actual remote device state)
+// version of the current connection status of the remote device
+TRemoteDeviceState CPanRemDevStateReconnectingSocket::GetState() const
+ {
+ return EIdle;
+ }
+
+//
+// CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForOutgoingConnection
+//
+
+CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForOutgoingConnection::CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForOutgoingConnection(MPanRemDevStateMachineNotify& aStateMachine) :
+ CPanRemDevStateBase(aStateMachine, EPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForOutgoingConnection)
+/**
+
+*/
+ { }
+
+void CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForOutgoingConnection::OnEntryL()
+/**
+Not much to do here - just waiting for role state machine to become available
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for outgoing connection> - entering state"), &StateMachine());
+
+ // do nothing
+ }
+
+void CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForOutgoingConnection::BnepRoleRequestFromRemoteDeviceL(const TUUID& /*aRequestedLocalRole*/, const TUUID& /*aRequestedRemoteRole*/)
+/**
+Oi! We're starting the connection here, so we get to send the role request!
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for outgoing connection> - BNEP role request received from remote device - they shouldn't be sending them, we're doing the outgoing connection, disconnecting them"), &StateMachine());
+
+ // drop the role request packet that the remote device has incorrectly sent us
+ }
+
+void CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForOutgoingConnection::BnepRoleResponseFromRemoteDeviceL(TBnepSetupConnectionResponseMessage /*aRoleResponseCode*/)
+/**
+Excuse me? We haven't sent a role request yet, so why are they sending a role response?
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for outgoing connection> - BNEP role response received from remote device before we've sent a request - disconnecting them"), &StateMachine());
+
+ // drop the role response packet that the remote device has incorrectly sent us
+ }
+
+void CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForOutgoingConnection::RemoteDeviceDisconnectL(TInt aError)
+/**
+Remote device has obviously given up waiting for us...
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for outgoing connection> - remote device disconnect received, looks like they've given up waiting for us."), &StateMachine());
+
+ User::Leave(aError); // will shutdown the connection
+ }
+
+void CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForOutgoingConnection::ReadyForRoleRequestL()
+/**
+Ahh, that's the event we've really been waiting for - role state machine has finished dealing with
+another device and is now ready for our role request
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for outgoing connection> - ready for role request received from role state machine"), &StateMachine());
+
+ TInt err;
+ CPanRemDevStateBase* nextState = NULL;
+ StateMachine().RemoteRole() = EPanRoleUnknown; // reset this for outgoing connection - we maybe trying a different role now
+ err = StateMachine().InitiateOutgoingConnection(StateMachine().LocalRole(), StateMachine().RemoteRole(), StateMachine().RemoteWorthTryingRolesList());
+
+ switch(err)
+ {
+ case KErrNone:
+ {
+ err = PerformMasterSlaveSwitchIfNecessary(StateMachine().LocalRole());
+ if(err==KErrWaitingForBasebandRoleSwitch)
+ {
+ nextState = new(ELeave) CPanRemDevStateWaitingForRoleSwitchForOutgoingConnection(StateMachine());
+ break;
+ }
+ else if(err)
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for outgoing connection> - ...M/S switch required and failed - disconnecting device."), &StateMachine());
+ // remote device would not perform role switch (maybe it needs to stay as master for another profile it's using...)
+ User::Leave(KErrCouldNotBecomePiconetMaster);
+ return;
+ }
+
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for outgoing connection> - ...M/S switch not required, sending role request."), &StateMachine());
+
+ nextState = new(ELeave) CPanRemDevStatePerformingDelayedRoleNegotiationForOutgoingConnection(StateMachine());
+ break;
+ }
+ case KErrLocked:
+ {
+ PanicInState(ERoleStateMachineCalledReadyForRoleRequestThenReturnedLocked);
+ break;
+ }
+ case KErrInvalidOrUnacceptableRoleCombination:
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for outgoing connection> - the roles the remote device proposed were invalid or unacceptable to us, disconnecting them"), &StateMachine());
+ User::Leave(KErrInvalidOrUnacceptableRoleCombination);
+ }
+ default:
+ {
+ // if err is something other than KErrNoMemory that might indicate an internal error in the state
+ // machine, so ASSERT_DEBUG. We can probably carry on even if the error is unexpected, as leaving
+ // will cause this connection to shutdown.
+ __ASSERT_DEBUG(err == KErrNoMemory, PanicInState(EPanAgentRoleStateMachineReturnedUnexpectedErrorCode));
+ User::Leave(err);
+ }
+ }
+
+ __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));
+ StateMachine().SetState(*nextState);
+ delete this;
+ return;
+ }
+
+void CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForOutgoingConnection::ShutdownL()
+/**
+Local device wants us to disconnect
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for outgoing connection> - locally requested disconnect received"), &StateMachine());
+
+ User::Leave(KErrLocallyInitiatedDisconnect); // disconnect the remote device
+ }
+
+// This returns a distilled (i.e., not the actual remote device state)
+// version of the current connection status of the remote device
+TRemoteDeviceState CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForOutgoingConnection::GetState() const
+ {
+ return EPendingNegotiation;
+ }
+
+//
+// CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingConnection
+//
+
+CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingConnection::CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingConnection(MPanRemDevStateMachineNotify& aStateMachine) :
+ CPanRemDevStateBase(aStateMachine, EPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingConnection)
+/**
+
+*/
+ { }
+
+CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingConnection::CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingConnection(MPanRemDevStateMachineNotify& aStateMachine, TPanRemDevStates aStateNumber) :
+ CPanRemDevStateBase(aStateMachine, aStateNumber)
+/**
+When implementing a new state that derives from this base class, ensure that
+it provides a unique number to identify the state from other possible
+states. @see PanAgent::TPanAgtStates.
+*/
+ { }
+
+void CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingConnection::OnEntryL()
+/**
+Not much to do here - just waiting for role state machine to become available
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for incoming connection> - entering state"), &StateMachine());
+
+ // do nothing
+ }
+
+void CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingConnection::BnepRoleRequestFromRemoteDeviceL(const TUUID& /*aRequestedLocalRole*/, const TUUID& /*aRequestedRemoteRole*/)
+/**
+
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for incoming connection> - BNEP role request received from remote device, still can't do anything with it until we get access to the role state machine"), &StateMachine());
+
+ // drop resent role request
+ }
+
+void CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingConnection::BnepRoleResponseFromRemoteDeviceL(TBnepSetupConnectionResponseMessage /*aRoleResponseCode*/)
+/**
+@note Shouldn't be called for incoming connections, as they should be sending requests, not responses
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for incoming connection> - BNEP role response received from remote device, what are they up to? They should be sending requests and we should be sending responses, disconnecting them"), &StateMachine());
+
+ // drop the role response packet that the remote device has incorrectly sent us
+ }
+
+void CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingConnection::RemoteDeviceDisconnectL(TInt aError)
+/**
+Remote device has obviously given up waiting for us...
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for incoming connection> - remote device disconnect received, looks like they've given up waiting for us."), &StateMachine());
+
+ User::Leave(aError); // will shutdown the connection
+ }
+
+void CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingConnection::ReadyForRoleRequestL()
+/**
+Ahh, that's the event we've really been waiting for - role state machine has finished dealing with
+another device and is now ready for our role request
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for incoming connection> - ready for role request received from role state machine"), &StateMachine());
+
+ TInt err;
+ CPanRemDevStateBase* nextState = NULL;
+ err = StateMachine().IncomingConnectionFromPeer(StateMachine().LocalRole(), StateMachine().RemoteRole());
+
+ switch(err)
+ {
+ case KErrNone:
+ {
+ err = PerformMasterSlaveSwitchIfNecessary(StateMachine().LocalRole());
+ if(err==KErrWaitingForBasebandRoleSwitch)
+ {
+ nextState = new(ELeave) CPanRemDevStateWaitingForRoleSwitchForIncomingConnection(StateMachine());
+ break;
+ }
+ else if(err)
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for incoming connection> - ...M/S switch required and failed - disconnecting device."), &StateMachine());
+ // remote device would not perform role switch (maybe it needs to stay as master for another profile it's using...)
+ StateMachine().SendRoleResponse(EConnectionNotAllowed);
+ User::Leave(KErrCouldNotBecomePiconetMaster);
+ return;
+ }
+
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for incoming connection> - ...M/S switch not required, sending successful connect response."), &StateMachine());
+ StateMachine().SendRoleResponse(EOperationSuccessful);
+
+ nextState = new(ELeave) CPanRemDevStateIncomingNotification(StateMachine());
+ break;
+ }
+ case KErrLocked:
+ {
+ PanicInState(ERoleStateMachineCalledReadyForRoleRequestThenReturnedLocked);
+ break;
+ }
+
+ default:
+ {
+ // An error has occured. Send a -ve role response and disconnect.
+ LOG2(_L("RemDevState[%x]: <waiting for role state machine for incoming connection> - Fail with error [%d]. Disconnecting peer"), &StateMachine(), err);
+ StateMachine().SendRoleResponse(EConnectionNotAllowed);
+ User::Leave(err);
+ }
+ }
+ __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));
+ StateMachine().SetState(*nextState);
+ delete this;
+ return;
+ }
+
+void CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingConnection::ShutdownL()
+/**
+Local device wants us to disconnect
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for incoming connection> - locally requested disconnect received"), &StateMachine());
+
+ // tell the other end that we're disconnecting
+ StateMachine().SendRoleResponse(EConnectionNotAllowed);
+ // and then disconnect the remote device
+ User::Leave(KErrLocallyInitiatedDisconnect);
+ }
+
+// This returns a distilled (i.e., not the actual remote device state)
+// version of the current connection status of the remote device
+TRemoteDeviceState CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingConnection::GetState() const
+ {
+ return EPendingNegotiation;
+ }
+
+//
+// CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingRoleChangeRequest
+//
+
+CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingRoleChangeRequest::CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingRoleChangeRequest(MPanRemDevStateMachineNotify& aStateMachine, TBluetoothPanRole aPendingLocalRole, TBluetoothPanRole aPendingRemoteRole)
+ : CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingConnection(aStateMachine, EPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingRoleChangeRequest),
+ iPendingLocalRole(aPendingLocalRole),
+ iPendingRemoteRole(aPendingRemoteRole)
+/**
+
+*/
+ { }
+
+void CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingRoleChangeRequest::OnEntryL()
+/**
+Not much to do here - just waiting for role state machine to become available
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for incoming role change request> - entering state"), &StateMachine());
+
+ // do nothing
+ }
+
+void CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingRoleChangeRequest::ReadyForRoleRequestL()
+/**
+Ahh, that's the event we've really been waiting for - role state machine has finished dealing with
+another device and is now ready for our role request
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for incoming role change request> - ready for role request received from role state machine"), &StateMachine());
+
+ TInt err;
+ CPanRemDevStateBase* nextState = NULL;
+ err = StateMachine().RoleChangeRequestFromPeer(iPendingLocalRole, iPendingRemoteRole);
+ switch(err)
+ {
+ case KErrNone:
+ {
+ err = PerformMasterSlaveSwitchIfNecessary(iPendingLocalRole);
+ if(err==KErrWaitingForBasebandRoleSwitch)
+ {
+ nextState = new(ELeave) CPanRemDevStateWaitingForRoleSwitchForIncomingRoleChangeRequest(StateMachine(), iPendingLocalRole, iPendingRemoteRole);
+ break;
+ }
+ else if(err)
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for incoming role change request> - ...M/S switch required and failed - disconnecting device."), &StateMachine());
+ // remote device would not perform role switch (maybe it needs to stay as master for another profile it's using...)
+ StateMachine().SendRoleResponse(EConnectionNotAllowed);
+ StateMachine().RoleChangeFailed();
+ nextState = new(ELeave) CPanRemDevStateActive(StateMachine());
+ break;
+ }
+
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for incoming role change request> - ...M/S switch not required, sending successful connect response."), &StateMachine());
+ StateMachine().SendRoleResponse(EOperationSuccessful);
+
+ // Store the new roles
+ StateMachine().LocalRole() = iPendingLocalRole;
+ StateMachine().RemoteRole() = iPendingRemoteRole;
+
+ // Changing role from GN/NAP to U. If this connection previously had access to the
+ // uplink this should be revoked.
+ if(StateMachine().LocalRole() == EPanRoleU)
+ {
+ StateMachine().SetUplinkAccessAllowed(EFalse);
+ }
+
+ nextState = new(ELeave) CPanRemDevStateActive(StateMachine());
+ break;
+ }
+ case KErrLocked:
+ {
+ PanicInState(ERoleStateMachineCalledReadyForRoleRequestThenReturnedLocked);
+ break;
+ }
+ case KErrInvalidOrUnacceptableRoleCombination:
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role state machine for incoming role change request> - the roles the remote device proposed were invalid or unacceptable to us, signalling failure and going to active state"), &StateMachine());
+ StateMachine().SendRoleResponse(EConnectionNotAllowed);
+ nextState = new(ELeave) CPanRemDevStateActive(StateMachine());
+ break;
+ }
+ default:
+ {
+ // if err is something other than KErrNoMemory that might indicate an internal error in the state
+ // machine, so ASSERT_DEBUG. We can probably carry on even if the error is unexpected, as leaving
+ // will cause this connection to shutdown.
+ __ASSERT_DEBUG(err == KErrNoMemory, PanicInState(EPanAgentRoleStateMachineReturnedUnexpectedErrorCode));
+ User::Leave(err);
+ }
+ }
+ __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));
+ StateMachine().SetState(*nextState);
+ delete this;
+ return;
+ }
+
+//
+// CPanRemDevStatePerformingRoleNegotiationForOutgoingBase
+//
+
+CPanRemDevStatePerformingRoleNegotiationForOutgoingBase::CPanRemDevStatePerformingRoleNegotiationForOutgoingBase(MPanRemDevStateMachineNotify& aStateMachine, TPanRemDevStates aStateNumber) :
+ CPanRemDevStateBase(aStateMachine, aStateNumber), iRetries(KMaxBnepNegotiationCyles)
+/**
+
+*/
+ { }
+
+void CPanRemDevStatePerformingRoleNegotiationForOutgoingBase::BnepRoleRequestFromRemoteDeviceL(const TUUID& /*aRequestedLocalRole*/, const TUUID& /*aRequestedRemoteRole*/)
+/**
+Something's gone wrong - we were expecting a response from the remote device - not a request.
+Not sure this can/should occur - I think the spec implies that only the initiating device can send role requests.
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - BNEP role request from remote device received - what are they doing? We're supposed to be sending the role requests."), &StateMachine());
+
+ // drop the role request packet that the remote device has incorrectly sent us
+ }
+
+void CPanRemDevStatePerformingRoleNegotiationForOutgoingBase::BnepRoleResponseFromRemoteDeviceL(TBnepSetupConnectionResponseMessage aRoleResponseCode)
+/**
+Woohoo! Our role response has arrived.
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - BNEP role response from remote device received, processing response..."), &StateMachine());
+
+ StateMachine().Cancel();
+
+ CPanRemDevStateBase* nextState = NULL;
+ switch(aRoleResponseCode)
+ {
+ case EOperationSuccessful:
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - ...operation successful, setting device active."), &StateMachine());
+ StateMachine().ResetConnectionRetryAttempts(); // reset the connection retry attempts
+ StateMachine().ResetRetryParameters(); // clears the triedpanu... type flags incase we want to reconnect later
+ nextState = DoRoleNegotiationSuccessL();
+ break;
+ }
+ case EConnectionNotAllowed:
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - ...operation failed, connection not allowed"), &StateMachine());
+ TInt retries = StateMachine().IncrementConnectionRetryAttempts();
+ // There is a race condition in some PC stacks that can bring us to this point when it shouldn't, so we retry the connection
+ if (retries<KPanAgtConnectionRetryAttempts)
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - ...operation failed, connection not allowed - retrying connection"), &StateMachine());
+ StateMachine().ResetRetryParameters(); // This feeds all the way back so we recalculate the role parameters just the same as we did last time
+ nextState = new(ELeave) CPanRemDevStateReconnectingSocket(StateMachine());
+
+ // 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
+ }
+ /* the intention is to allow the retrys required by the PC stacks above
+ then if it's worth retrying (we can try new roles) we will
+ This is particularly useful when we don't have sdp records to suggest
+ what we should do
+ */
+ else if (StateMachine().WorthTrying())
+ {
+ // if we've still not made a successful connection then we can have a quick try
+ // at connecting using different remote roles
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - ...operation failed, connection not allowed - retrying connection with different roles"), &StateMachine());
+ nextState = new(ELeave) CPanRemDevStateReconnectingSocket(StateMachine());
+
+ // 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
+ }
+ else
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - ...operation failed, connection not allowed"), &StateMachine());
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - ...operation failed, unrecognised response code, shutting down"), &StateMachine());
+ StateMachine().ResetConnectionRetryAttempts(); // reset the connection retry attempts
+ StateMachine().ResetRetryParameters(); // clears the triedpanu... type flags incase we want to try connect later
+ nextState = DoRoleNegotiationFailureL(KErrCouldNotConnect);
+ }
+ break;
+ }
+ default:
+ {
+ // this nested switch avoids the old multiple logging lines which was really nasty
+ switch(aRoleResponseCode)
+ {
+ case EInvalidDestinationServiceUuid: // we've tried to negotiate roles that are unsuitable
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - ...operation failed, invalid destination service UUID"), &StateMachine());
+ break;
+ }
+ case EInvalidSourceServiceUuid:
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - ...operation failed, invalid source service UUID"), &StateMachine());
+ break;
+ }
+ case EInvalidServiceUuidSize:
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - ...operation failed, invalid UUID size"), &StateMachine());
+ break;
+ }
+ default:
+ {
+ LOG2(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - ...operation failed, unrecognised response code (%x), shutting down"), &StateMachine(),aRoleResponseCode);
+ break;
+ }
+ }
+ StateMachine().ResetConnectionRetryAttempts(); // reset the connection retry attempts
+ StateMachine().ResetRetryParameters(); // clears the triedpanu... type flags incase we want to try connect later
+ nextState = DoRoleNegotiationFailureL(KErrCouldNotConnect);
+ break;
+ }
+ }
+ __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));
+ StateMachine().SetState(*nextState);
+ delete this;
+ return;
+ }
+
+void CPanRemDevStatePerformingRoleNegotiationForOutgoingBase::RemoteDeviceDisconnectL(TInt aError)
+/**
+Remote device has disconnected.
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - remote device disconnect received, looks like our requests weren't acceptable, or they just gave up"), &StateMachine());
+
+ // outstanding async request will be cancelled by state machine when we leave
+ User::Leave(aError); // will shutdown the connection
+ }
+
+void CPanRemDevStatePerformingRoleNegotiationForOutgoingBase::ShutdownL()
+/**
+Local device wants us to disconnect
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - locally requested disconnect received"), &StateMachine());
+
+ // outstanding async request will be cancelled by state machine when we leave
+ User::Leave(KErrLocallyInitiatedDisconnect); // will shutdown the connection
+ }
+
+void CPanRemDevStatePerformingRoleNegotiationForOutgoingBase::AsyncEventCompleteL()
+/**
+Timer completion
+*/
+ {
+ --iRetries;
+
+ LOG2(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - async event complete, looks like the timer triggered before they responded. %d retries remaining..."), &StateMachine(), iRetries);
+
+ if(iRetries==0)
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - ...disconnecting."), &StateMachine());
+ CPanRemDevStateBase* nextState = DoRoleNegotiationFailureL(KErrRemoteDeviceFailedToRespondToRoleRequests);
+ StateMachine().SetState(*nextState);
+ delete this;
+ return;
+ }
+ else // resend the role request, and start the timer running again
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - ...retrying."), &StateMachine());
+ StateMachine().SendRoleRequest(StateMachine().LocalRole(), StateMachine().RemoteRole());
+ iTimer.After(StateMachine().Status(), KMaxTimeToWaitForRoleResponse);
+ StateMachine().SetActive();
+ }
+ }
+
+void CPanRemDevStatePerformingRoleNegotiationForOutgoingBase::AsyncEventCancelL()
+/**
+Timer cancel
+@note Typically it will be this state that cancels the async event (timer in this case) when we decide we don't need it any longer
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation [base]> - async event cancelled, cancelling timer"), &StateMachine());
+
+ iTimer.Cancel();
+ iTimer.Close();
+ }
+
+// This returns a distilled (i.e., not the actual remote device state)
+// version of the current connection status of the remote device
+TRemoteDeviceState CPanRemDevStatePerformingRoleNegotiationForOutgoingBase::GetState() const
+ {
+ return EPerformingNegotiation;
+ }
+
+//
+// CPanRemDevStatePerformingRoleNegotiationForOutgoingConnection
+//
+
+CPanRemDevStatePerformingRoleNegotiationForOutgoingConnection::CPanRemDevStatePerformingRoleNegotiationForOutgoingConnection(MPanRemDevStateMachineNotify& aStateMachine) :
+ CPanRemDevStatePerformingRoleNegotiationForOutgoingBase(aStateMachine, EPanRemDevStatePerformingRoleNegotiationForOutgoingConnection)
+/**
+
+*/
+ { }
+
+CPanRemDevStatePerformingRoleNegotiationForOutgoingConnection::CPanRemDevStatePerformingRoleNegotiationForOutgoingConnection(MPanRemDevStateMachineNotify& aStateMachine, TPanRemDevStates aStateNumber) :
+ CPanRemDevStatePerformingRoleNegotiationForOutgoingBase(aStateMachine, aStateNumber)
+/**
+When implementing a new state that derives from this base class, ensure that
+it provides a unique number to identify the state from other possible
+states. @see PanAgent::TPanAgtStates.
+*/
+ { }
+
+void CPanRemDevStatePerformingRoleNegotiationForOutgoingConnection::OnEntryL()
+/**
+Send the role request to the remote device
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation> - entering state"), &StateMachine());
+
+ User::LeaveIfError(iTimer.CreateLocal());
+
+ TInt err;
+ CPanRemDevStateBase* nextState = NULL;
+ StateMachine().RemoteRole() = EPanRoleUnknown; // reset this for outgoing connection - we maybe trying a different role now
+ err = StateMachine().InitiateOutgoingConnection(StateMachine().LocalRole(), StateMachine().RemoteRole(), StateMachine().RemoteWorthTryingRolesList());
+
+ switch(err)
+ {
+ case KErrNone:
+ {
+ LOG3(_L("RemDevState[%x]: <performing outgoing role negotiation> - role state machine changed our proposed role; now local: %x, remote: %x"), &StateMachine(), StateMachine().LocalRole(), StateMachine().RemoteRole());
+ err = PerformMasterSlaveSwitchIfNecessary(StateMachine().LocalRole());
+
+ if(err==KErrWaitingForBasebandRoleSwitch)
+ {
+ nextState = new(ELeave) CPanRemDevStateWaitingForRoleSwitchForOutgoingConnection(StateMachine());
+ break;
+ }
+ else if(err)
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation> - ...M/S switch required and failed - disconnecting device."), &StateMachine());
+ // remote device would not perform role switch (maybe it needs to stay as master for another profile it's using...)
+ User::Leave(KErrCouldNotBecomePiconetMaster);
+ return;
+ }
+
+ StateMachine().SendRoleRequest(StateMachine().LocalRole(), StateMachine().RemoteRole());
+ iTimer.After(StateMachine().Status(), KMaxTimeToWaitForRoleResponse);
+ StateMachine().SetActive();
+ return;
+ }
+ case KErrLocked: // someone else is negotiating, so go to the wait state
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation> - role state machine busy, waiting for notification of its availability"), &StateMachine());
+ nextState = new(ELeave) CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForOutgoingConnection(StateMachine());
+ break;
+ }
+
+ case KErrInvalidOrUnacceptableRoleCombination:
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation> - this state generated and proposed an illegal role combination"), &StateMachine());
+ // fall through
+
+ default:
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation> - unexpected response from role state machine"), &StateMachine());
+ // if err is something other than KErrNoMemory that might indicate an internal error in the state
+ // machine, so ASSERT_DEBUG. We can probably carry on even if the error is unexpected, as leaving
+ // will cause this connection to shutdown.
+ User::Leave(err);
+ }
+
+ __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));
+ StateMachine().SetState(*nextState);
+ delete this;
+ return;
+ }
+
+CPanRemDevStateBase* CPanRemDevStatePerformingRoleNegotiationForOutgoingConnection::DoRoleNegotiationSuccessL()
+/**
+Role negotiation succeeded, tell role state machine and go to active state
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation> - role negotiation succeeded, going to active state"), &StateMachine());
+
+ CPanRemDevStateBase* nextState = new(ELeave) CPanRemDevStateActive(StateMachine());
+ return nextState;
+ }
+
+CPanRemDevStateBase* CPanRemDevStatePerformingRoleNegotiationForOutgoingConnection::DoRoleNegotiationFailureL(TInt aError)
+/**
+Role negotiation failed, disconnect
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing outgoing role negotiation> - role negotiation failed, shutting down connection"), &StateMachine());
+ User::Leave(aError);
+ return NULL; // will never be reached
+ }
+
+//
+// CPanRemDevStatePerformingRoleNegotiationForIncomingConnection
+//
+
+CPanRemDevStatePerformingRoleNegotiationForIncomingConnection::CPanRemDevStatePerformingRoleNegotiationForIncomingConnection(MPanRemDevStateMachineNotify& aStateMachine) :
+ CPanRemDevStateBase(aStateMachine, EPanRemDevStatePerformingRoleNegotiationForIncomingConnection)
+/**
+
+*/
+ { }
+
+void CPanRemDevStatePerformingRoleNegotiationForIncomingConnection::OnEntryL()
+/**
+
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing incoming role negotiation> - entering state"), &StateMachine());
+
+ // do nothing - just wait for incoming role request
+ }
+
+void CPanRemDevStatePerformingRoleNegotiationForIncomingConnection::BnepRoleRequestFromRemoteDeviceL(const TUUID& aRequestedLocalRole, const TUUID& aRequestedRemoteRole)
+/**
+This is what we're waiting for...
+*/
+ {
+// LOG1(_L("RemDevState[%x]: <performing incoming role negotiation> - BNEP role request from remote device, they propose local: %S, remote: %S"), &StateMachine(), (aRequestedLocalRole.ShortestForm()), (aRequestedRemoteRole.ShortestForm()));
+
+ TInt err;
+ CPanRemDevStateBase* nextState = NULL;
+
+ TBluetoothPanRole localRole;
+ TBluetoothPanRole remoteRole;
+ ConvertUuidsToPanRolesL(aRequestedLocalRole, aRequestedRemoteRole, localRole, remoteRole); // will send response to remote device and shutdown the connection if there is an error
+
+ LOG1(_L("RemDevState[%x]: <performing incoming role negotiation> - checking role request..."), &StateMachine());
+
+ err = StateMachine().IncomingConnectionFromPeer(localRole, remoteRole);
+
+ // store the requested roles, so the next state knows what was asked for
+ StateMachine().LocalRole() = localRole;
+ StateMachine().RemoteRole() = remoteRole;
+
+ switch(err)
+ {
+ case KErrNone:
+ {
+ LOG1(_L("RemDevState[%x]: <performing incoming role negotiation> - ...successful, checking to see if M/S switch necessary..."), &StateMachine());
+
+ err = PerformMasterSlaveSwitchIfNecessary(localRole);
+ if(err==KErrWaitingForBasebandRoleSwitch)
+ {
+ nextState = new(ELeave) CPanRemDevStateWaitingForRoleSwitchForIncomingConnection(StateMachine());
+ break;
+ }
+ else if(err)
+ {
+ LOG1(_L("RemDevState[%x]: <performing incoming role negotiation> - ...M/S switch required and failed - disconnecting device."), &StateMachine());
+ // remote device would not perform role switch (maybe it needs to stay as master for another profile it's using...)
+ StateMachine().SendRoleResponse(EConnectionNotAllowed);
+ User::Leave(KErrCouldNotBecomePiconetMaster);
+ return;
+ }
+
+ LOG1(_L("RemDevState[%x]: <performing incoming role negotiation> - ...M/S switch not required, sending successful connect response."), &StateMachine());
+ StateMachine().SendRoleResponse(EOperationSuccessful);
+
+ // Check if the incoming notifier is required.
+ nextState = new(ELeave) CPanRemDevStateIncomingNotification(StateMachine());
+ break;
+ }
+ case KErrLocked:
+ {
+ LOG1(_L("RemDevState[%x]: <performing incoming role negotiation> - ...role state machine busy, waiting."), &StateMachine());
+ // and create the "waiting" state
+ nextState = new (ELeave) CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingConnection(StateMachine());
+ break;
+ }
+
+ default:
+ {
+ // An error has occured. Send a -ve role response and disconnect.
+ LOG2(_L("RemDevState[%x]: <CPanRemDevStatePerformingRoleNegotiationForIncomingConnection> - Fail with error [%d]. Disconnecting peer"), &StateMachine(), err);
+ StateMachine().SendRoleResponse(EConnectionNotAllowed);
+ User::Leave(err);
+ }
+ }
+
+ __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));
+ StateMachine().SetState(*nextState);
+ delete this;
+ }
+
+void CPanRemDevStatePerformingRoleNegotiationForIncomingConnection::BnepRoleResponseFromRemoteDeviceL(TBnepSetupConnectionResponseMessage /*aRoleResponseCode*/)
+/**
+Something's gone wrong - we were expecting a request from the remote device - not a response.
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing incoming role negotiation> - BNEP role reponse from remote device - what are they up to? They're supposed to be sending the role request."), &StateMachine());
+
+ // drop the role response packet that the remote device has incorrectly sent us
+ }
+
+void CPanRemDevStatePerformingRoleNegotiationForIncomingConnection::RemoteDeviceDisconnectL(TInt aError)
+/**
+Remote device has disconnected
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing incoming role negotiation> - remote device disconnect received, they've obviously given up talking to us."), &StateMachine());
+
+ User::Leave(aError); // will shutdown the connection
+ }
+
+void CPanRemDevStatePerformingRoleNegotiationForIncomingConnection::ShutdownL()
+/**
+Local device wants us to disconnect
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing incoming role negotiation> - locally requested disconnect received"), &StateMachine());
+
+ User::Leave(KErrLocallyInitiatedDisconnect); // will shutdown the connection
+ }
+
+// This returns a distilled (i.e., not the actual remote device state)
+// version of the current connection status of the remote device
+TRemoteDeviceState CPanRemDevStatePerformingRoleNegotiationForIncomingConnection::GetState() const
+ {
+ return EPerformingNegotiation;
+ }
+
+//
+// CPanRemDevStatePerformingRoleNegotiationForOutgoingRoleChange
+//
+
+CPanRemDevStatePerformingRoleNegotiationForOutgoingRoleChange::CPanRemDevStatePerformingRoleNegotiationForOutgoingRoleChange(MPanRemDevStateMachineNotify& aStateMachine) :
+ CPanRemDevStatePerformingRoleNegotiationForOutgoingBase(aStateMachine, EPanRemDevStatePerformingRoleNegotiationForOutgoingRoleChange)
+/**
+
+*/
+ { }
+
+void CPanRemDevStatePerformingRoleNegotiationForOutgoingRoleChange::OnEntryL()
+ {
+ LOG1(_L("RemDevState[%x]: <performing role negotiation for outgoing role change> - entering state"), &StateMachine());
+
+ User::LeaveIfError(iTimer.CreateLocal());
+
+ // It may appear as though we ought to do a new SDP query, rather than relying on a potentially
+ // stale one, but in reality if we're being asked to renegotiate, then the roles are pretty much
+ // going to be known by the role state machine, so we just ask it
+ TInt err = StateMachine().PerformLocalRoleChangeRequest(StateMachine().LocalRole(), StateMachine().RemoteRole());
+ switch(err)
+ {
+ case KErrNone:
+ {
+ LOG3(_L("RemDevState[%x]: <performing role negotiation for outgoing role change> - role state machine changed our proposed role; now local: %x, remote: %x"), &StateMachine(), StateMachine().LocalRole(), StateMachine().RemoteRole());
+
+ // send the role request and wait for a response first, so the remote device
+ // understands that we're trying to role switch the baseband because we want to be GN/NAP,
+ // and releases their piconet master lock
+ StateMachine().SendRoleRequest(StateMachine().LocalRole(), StateMachine().RemoteRole());
+
+ // start waiting for the role response
+ iTimer.After(StateMachine().Status(), KMaxTimeToWaitForRoleResponse);
+ StateMachine().SetActive();
+ return;
+ }
+ case KErrLocked:
+ // this must not happen - if the state machine requests that we renegotiate, then it needs to be ready for us
+ {
+ PanicInState(ERoleStateMachineRequestedWeRenegotiateRolesThenReturnedLocked);
+ }
+ case KErrInvalidOrUnacceptableRoleCombination:
+ // Unable to find a valid role combination to send to the peer device. fall through
+
+ default:
+ LOG1(_L("RemDevState[%x]: <performing role negotiation for outgoing role change> - unexpected response from role state machine"), &StateMachine());
+ User::Leave(err);
+ break;
+ }
+ }
+
+void CPanRemDevStatePerformingRoleNegotiationForOutgoingRoleChange::BnepRoleResponseFromRemoteDeviceL(TBnepSetupConnectionResponseMessage aRoleResponseCode)
+/**
+The role response has arrived from the peer device.
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <CPanRemDevStatePerformingRoleNegotiationForOutgoingRoleChange> - BNEP role response from remote device received, processing response..."), &StateMachine());
+
+ StateMachine().Cancel();
+
+ CPanRemDevStateBase* nextState = NULL;
+ switch(aRoleResponseCode)
+ {
+ case EOperationSuccessful:
+ {
+ LOG1(_L("RemDevState[%x]: <CPanRemDevStatePerformingRoleNegotiationForOutgoingRoleChange> - ...operation successful, setting device active."), &StateMachine());
+ nextState = DoRoleNegotiationSuccessL();
+ break;
+ }
+ default:
+ {
+ LOG2(_L("RemDevState[%x]: <CPanRemDevStatePerformingRoleNegotiationForOutgoingRoleChange> - ...operation failed [result code = %d], connection not allowed"), &StateMachine(), aRoleResponseCode);
+ nextState = DoRoleNegotiationFailureL(KErrCouldNotConnect);
+ break;
+ }
+ };
+
+ __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));
+ StateMachine().SetState(*nextState);
+ delete this;
+ return;
+ }
+
+CPanRemDevStateBase* CPanRemDevStatePerformingRoleNegotiationForOutgoingRoleChange::DoRoleNegotiationSuccessL()
+/**
+Role negotiation succeeded, decide whether we need to perform a baseband role switch
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing role negotiation for outgoing role change> - role negotiation succeeded, deciding whether we need to role switch"), &StateMachine());
+
+ TInt err;
+ // start going through the M/S switch routine
+ err = PerformMasterSlaveSwitchIfNecessary(StateMachine().LocalRole());
+
+ CPanRemDevStateBase* nextState = NULL;
+ if(err==KErrWaitingForBasebandRoleSwitch)
+ {
+ nextState = new(ELeave) CPanRemDevStateWaitingForRoleSwitchForOutgoingRoleChangeRequest(StateMachine());
+ }
+ else if(err)
+ {
+ LOG1(_L("RemDevState[%x]: <performing role negotiation for outgoing role change> - ...M/S switch required and failed - disconnecting device."), &StateMachine());
+ // remote device would not perform role switch (maybe it needs to stay as master for another
+ // profile it's using...)
+ // Whilst the spec says we should return to previous roles when this role upgrade fails,
+ // we're now in the situation that we're GN/NAP, they're U, and we can't become the piconet
+ // master - so the best/most reliable/only way to recover is to disconnect them. Not
+ // entirely according-to-spec, but then they shouldn't let us become master then refuse
+ // to role switch!
+ User::Leave(KErrCouldNotBecomePiconetMaster);
+ }
+ else
+ {
+ nextState = new(ELeave) CPanRemDevStateActive(StateMachine());
+ }
+ __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));
+ return nextState;
+ }
+
+CPanRemDevStateBase* CPanRemDevStatePerformingRoleNegotiationForOutgoingRoleChange::DoRoleNegotiationFailureL(TInt /*aError*/)
+/**
+Role negotiation failed, return to active state
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing role negotiation for outgoing role change> - role negotiation failed, returning to active state"), &StateMachine());
+
+ // let the role state machine know that the role change failed
+ StateMachine().RoleChangeFailed();
+ CPanRemDevStateBase* nextState = new(ELeave) CPanRemDevStateActive(StateMachine());
+ return nextState;
+ }
+
+//
+// CPanRemDevStatePerformingDelayedRoleNegotiationForOutgoingConnection
+//
+
+CPanRemDevStatePerformingDelayedRoleNegotiationForOutgoingConnection::CPanRemDevStatePerformingDelayedRoleNegotiationForOutgoingConnection(MPanRemDevStateMachineNotify& aStateMachine) :
+ CPanRemDevStatePerformingRoleNegotiationForOutgoingConnection(aStateMachine, EPanRemDevStatePerformingDelayedRoleNegotiationForOutgoingConnection)
+/**
+
+*/
+ { }
+
+void CPanRemDevStatePerformingDelayedRoleNegotiationForOutgoingConnection::OnEntryL()
+/**
+Send the role request and start the timer
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <performing delayed role negotiation for outgoing connection> - entering state"), &StateMachine());
+
+ User::LeaveIfError(iTimer.CreateLocal());
+
+ // send the role request to the remote device
+ StateMachine().SendRoleRequest(StateMachine().LocalRole(), StateMachine().RemoteRole());
+ iTimer.After(StateMachine().Status(), KMaxTimeToWaitForRoleResponse);
+ StateMachine().SetActive();
+ }
+
+//
+// CPanRemDevStateWaitingForRoleSwitchBase
+//
+
+CPanRemDevStateWaitingForRoleSwitchBase::CPanRemDevStateWaitingForRoleSwitchBase(MPanRemDevStateMachineNotify& aStateMachine, TPanRemDevStates aStateNumber) :
+ CPanRemDevStateBase(aStateMachine, aStateNumber)
+/**
+
+*/
+ { }
+
+CPanRemDevStateWaitingForRoleSwitchBase::~CPanRemDevStateWaitingForRoleSwitchBase()
+/**
+We own an object, so need our own destructor here to delete it
+(this is the only state that does/needs this)
+*/
+ {
+ delete iTimerHelper;
+ iTimerHelper = NULL;
+ }
+
+void CPanRemDevStateWaitingForRoleSwitchBase::OnEntryL()
+/**
+
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch [base]> - entering state"), &StateMachine());
+
+ //Proceed to the next state if role switch is not required
+ TUint32 state;
+ StateMachine().PhysicalLinkAdapter().PhysicalLinkState(state);
+ if(state & ENotifyMaster)
+ {
+ CPanRemDevStateBase *nextState = DoRoleSwitchSuccessL();
+ __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));
+ StateMachine().SetState(*nextState);
+ delete this;
+ return;
+ }
+
+ // create and start the timer helper object
+ iTimerHelper = CPanAgtTimerHelper::NewL(*this);
+ iTimerHelper->SetTimer(KMaxTimeToWaitForBasebandRoleSwitch);
+
+ // subscribe to the link status change event notification
+ iEventNotification() = ENotifyMaster; // must set this to the event we're interested in, otherwise we don't see it
+ StateMachine().PhysicalLinkAdapter().NotifyNextBasebandChangeEvent(iEventNotification, StateMachine().Status());
+ StateMachine().SetActive();
+ }
+
+void CPanRemDevStateWaitingForRoleSwitchBase::RemoteDeviceDisconnectL(TInt aError)
+/**
+Oh well, they've given up
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch> - remote device disconnect received, they've obviously given up talking to us."), &StateMachine());
+ // outstanding async request will be cancelled by state machine when we leave
+ User::Leave(aError); // will shutdown the connection
+ }
+
+void CPanRemDevStateWaitingForRoleSwitchBase::ShutdownL()
+/**
+
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch> - locally requested disconnect received"), &StateMachine());
+ // outstanding async request will be cancelled by state machine when we leave
+ User::Leave(KErrLocallyInitiatedDisconnect); // will shutdown the connection
+ }
+
+void CPanRemDevStateWaitingForRoleSwitchBase::AsyncEventCompleteL()
+/**
+Timer or baseband change event notification completion
+*/
+ {
+ CPanRemDevStateBase* nextState = NULL;
+ if(StateMachine().Status()==KErrNone)
+ {
+ if(iTimerCompleted) // work out whether the timer fired or the baseband change event notification completed
+ {
+ // timer fired
+ LOG1(_L("RemDevState[%x]: <waiting for role switch> - timer fired, giving up and disconnecting remote device"), &StateMachine());
+
+ // cancel the outstanding request for baseband change event notification
+ // need to cancel it directly, as the timer completes the state machine AO (through
+ // the TimerComplete() and TimerCancel() methods, so just calling
+ // StateMachine().Cancel() won't have any effect
+ StateMachine().PhysicalLinkAdapter().CancelNextBasebandChangeEventNotifier();
+
+ User::WaitForRequest(StateMachine().Status()); // have to catch the KErrCancel manually, as we're not active at the moment
+
+ nextState = DoRoleSwitchFailureL(KErrNone);
+ }
+ else
+ {
+ // Baseband change event notification completed
+ if(iEventNotification().EventType() & ENotifyMaster)
+ {
+ LOG2(_L("RemDevState[%x]: <waiting for role switch> - received link event %32b, now piconet master - sending role response and going to active state"), &StateMachine(), iEventNotification().EventType());
+
+ // cancel the timer
+ iTimerHelper->Cancel(); // need to cancel it directly, as the state machine AO is
+ // no longer active, so just cancelling all async events
+ // through the state machine won't work
+
+ // success - get this state to do it's stuff
+ // they *must* return the next state
+ nextState = DoRoleSwitchSuccessL();
+ }
+ else // event that we're not interested in, repost 'baseband change event notification' request
+ {
+ iEventNotification() = ENotifyMaster; // must set this to the event we're interested in, otherwise we don't see it
+ StateMachine().PhysicalLinkAdapter().NotifyNextBasebandChangeEvent(iEventNotification, StateMachine().Status());
+ LOG2(_L("RemDevState[%x]: <waiting for role switch> - received link event %32b, throwing away"), &StateMachine(), iEventNotification().EventType());
+ StateMachine().SetActive();
+ return;
+ }
+ }
+ }
+ else
+ {
+ StateMachine().Cancel();
+ nextState = DoRoleSwitchFailureL(StateMachine().Status().Int());
+ }
+
+ __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));
+ StateMachine().SetState(*nextState);
+ delete this;
+ return;
+ }
+
+void CPanRemDevStateWaitingForRoleSwitchBase::AsyncEventCancelL()
+/**
+Cancel all outstanding async events
+@note This only works when the state machine AO is active - ie. calling StateMachine().Cancel()
+from other code is only any good when *both* timer and baseband change event notification are outstanding, because the
+completion of either will mark the state machine AO as inactive
+*/
+ {
+ iTimerHelper->Cancel();
+ StateMachine().PhysicalLinkAdapter().CancelNextBasebandChangeEventNotifier();
+ }
+
+void CPanRemDevStateWaitingForRoleSwitchBase::TimerComplete()
+/**
+The timer has completed
+*/
+ {
+ iTimerCompleted = ETrue;
+ TRequestStatus* status = &StateMachine().Status();
+ User::RequestComplete(status, KErrNone);
+ }
+
+void CPanRemDevStateWaitingForRoleSwitchBase::TimerError(TInt aError)
+/**
+There was a problem with the timer
+*/
+ {
+ iTimerCompleted = ETrue;
+ TRequestStatus* status = &StateMachine().Status();
+ User::RequestComplete(status, aError);
+ }
+
+// This returns a distilled (i.e., not the actual remote device state)
+// version of the current connection status of the remote device
+TRemoteDeviceState CPanRemDevStateWaitingForRoleSwitchBase::GetState() const
+ {
+ return EPerformingNegotiation;
+ }
+
+//
+// CPanRemDevStateWaitingForRoleSwitchForOutgoingConnection
+//
+
+CPanRemDevStateWaitingForRoleSwitchForOutgoingConnection::CPanRemDevStateWaitingForRoleSwitchForOutgoingConnection(MPanRemDevStateMachineNotify& aStateMachine) :
+ CPanRemDevStateWaitingForRoleSwitchBase(aStateMachine, EPanRemDevStateWaitingForRoleSwitchForOutgoingConnection)
+/**
+
+*/
+ { }
+
+CPanRemDevStateWaitingForRoleSwitchForOutgoingConnection::CPanRemDevStateWaitingForRoleSwitchForOutgoingConnection(MPanRemDevStateMachineNotify& aStateMachine, TPanRemDevStates aStateNumber) :
+ CPanRemDevStateWaitingForRoleSwitchBase(aStateMachine, aStateNumber)
+/**
+When implementing a new state that derives from this base class, ensure that
+it provides a unique number to identify the state from other possible
+states. @see PanAgent::TPanAgtStates.
+*/
+ { }
+
+void CPanRemDevStateWaitingForRoleSwitchForOutgoingConnection::OnEntryL()
+/**
+
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for outgoing connection> - entering state"), &StateMachine());
+
+ // call base class's method
+ CPanRemDevStateWaitingForRoleSwitchBase::OnEntryL();
+ }
+
+void CPanRemDevStateWaitingForRoleSwitchForOutgoingConnection::BnepRoleRequestFromRemoteDeviceL(const TUUID& /*aRequestedLocalRole*/, const TUUID& /*aRequestedRemoteRole*/)
+/**
+Ignore it, we're waiting for them to role switch
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for outgoing connection> - BNEP role request from remote device: ignoring, as we're waiting for baseband role switch"), &StateMachine());
+
+ // do nothing
+ }
+
+void CPanRemDevStateWaitingForRoleSwitchForOutgoingConnection::BnepRoleResponseFromRemoteDeviceL(TBnepSetupConnectionResponseMessage /*aRoleResponseCode*/)
+/**
+Err, what's going on?
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for outgoing connection> - BNEP role response from remote device: huh? What are they up to? This is an incoming connection, so they're supposed to be sending the requests, not the responses"), &StateMachine());
+
+ // drop the role response packet that the remote device has incorrectly sent us
+ }
+
+CPanRemDevStateBase* CPanRemDevStateWaitingForRoleSwitchForOutgoingConnection::DoRoleSwitchSuccessL()
+/**
+It worked - now perform the role negotiation
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for outgoing connection> - role switch succeeded"), &StateMachine());
+ CPanRemDevStateBase* nextState = new(ELeave) CPanRemDevStatePerformingDelayedRoleNegotiationForOutgoingConnection(StateMachine());
+ return(nextState);
+ }
+
+CPanRemDevStateBase* CPanRemDevStateWaitingForRoleSwitchForOutgoingConnection::DoRoleSwitchFailureL(TInt aError)
+/**
+Shutdown the connection
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for outgoing connection> - role switch failed, shutting down"), &StateMachine());
+ if(aError==KErrNone) // the timer has fired
+ {
+ User::Leave(KErrCouldNotBecomePiconetMaster);
+ }
+ else // a more general error occured
+ {
+ User::Leave(aError);
+ }
+ return NULL; // should never be reached
+ }
+
+
+// This returns a distilled (i.e., not the actual remote device state)
+// version of the current connection status of the remote device
+TRemoteDeviceState CPanRemDevStateWaitingForRoleSwitchForOutgoingConnection::GetState() const
+ {
+ return EPendingNegotiation;
+ }
+
+//
+// CPanRemDevStateWaitingForRoleSwitchForIncomingConnection
+//
+
+CPanRemDevStateWaitingForRoleSwitchForIncomingConnection::CPanRemDevStateWaitingForRoleSwitchForIncomingConnection(MPanRemDevStateMachineNotify& aStateMachine) :
+ CPanRemDevStateWaitingForRoleSwitchBase(aStateMachine, EPanRemDevStateWaitingForRoleSwitchForIncomingConnection)
+/**
+
+*/
+ { }
+
+CPanRemDevStateWaitingForRoleSwitchForIncomingConnection::CPanRemDevStateWaitingForRoleSwitchForIncomingConnection(MPanRemDevStateMachineNotify& aStateMachine, TPanRemDevStates aStateNumber) :
+ CPanRemDevStateWaitingForRoleSwitchBase(aStateMachine, aStateNumber)
+/**
+When implementing a new state that derives from this base class, ensure that
+it provides a unique number to identify the state from other possible
+states. @see PanAgent::TPanAgtStates.
+*/
+ { }
+
+void CPanRemDevStateWaitingForRoleSwitchForIncomingConnection::OnEntryL()
+/**
+
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for incoming connection> - entering state"), &StateMachine());
+
+ // call base class's method
+ CPanRemDevStateWaitingForRoleSwitchBase::OnEntryL();
+ }
+
+void CPanRemDevStateWaitingForRoleSwitchForIncomingConnection::BnepRoleRequestFromRemoteDeviceL(const TUUID& /*aRequestedLocalRole*/, const TUUID& /*aRequestedRemoteRole*/)
+/**
+Ignore it, we're waiting for them to role switch
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for incoming [base]> - BNEP role request from remote device: ignoring, as we're waiting for baseband role switch"), &StateMachine());
+
+ // ignore resent role request
+ }
+
+void CPanRemDevStateWaitingForRoleSwitchForIncomingConnection::BnepRoleResponseFromRemoteDeviceL(TBnepSetupConnectionResponseMessage /*aRoleResponseCode*/)
+/**
+Err, what's going on?
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for incoming [base]> - BNEP role response from remote device: huh? What are they up to? This is an incoming connection, so they're supposed to be sending the requests, not the responses"), &StateMachine());
+
+ // drop the role response packet that the remote device has incorrectly sent us
+ }
+
+CPanRemDevStateBase* CPanRemDevStateWaitingForRoleSwitchForIncomingConnection::DoRoleSwitchSuccessL()
+/**
+It worked - tell the remote device and go to active state
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for incoming [base]> - role switch succeeded"), &StateMachine());
+
+ // tell the remote device the connection was successful
+ StateMachine().SendRoleResponse(EOperationSuccessful);
+ // let the role state machine know that this connection is now active
+ CPanRemDevStateBase* nextState = new(ELeave) CPanRemDevStateIncomingNotification(StateMachine());
+ return(nextState);
+ }
+
+CPanRemDevStateBase* CPanRemDevStateWaitingForRoleSwitchForIncomingConnection::DoRoleSwitchFailureL(TInt aError)
+/**
+Shutdown the connection
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for incoming connection> - role switch failed, shutting down"), &StateMachine());
+
+ //send response DEF068158
+ StateMachine().SendRoleResponse(EConnectionNotAllowed);
+ //and cancel next base band change event notifier DEF067708
+
+ StateMachine().PhysicalLinkAdapter().CancelNextBasebandChangeEventNotifier();
+
+
+ if(aError==KErrNone) // the timer has fired
+ {
+ User::Leave(KErrCouldNotBecomePiconetMaster);
+ }
+ else // a more general error occured
+ {
+ User::Leave(aError);
+ }
+ return NULL; // should never be reached
+ }
+
+//
+// CPanRemDevStateWaitingForRoleSwitchForOutgoingRoleChangeRequest
+//
+
+CPanRemDevStateWaitingForRoleSwitchForOutgoingRoleChangeRequest::CPanRemDevStateWaitingForRoleSwitchForOutgoingRoleChangeRequest(MPanRemDevStateMachineNotify& aStateMachine) :
+ CPanRemDevStateWaitingForRoleSwitchForOutgoingConnection(aStateMachine, EPanRemDevStateWaitingForRoleSwitchForOutgoingRoleChangeRequest)
+/**
+
+*/
+ { }
+
+void CPanRemDevStateWaitingForRoleSwitchForOutgoingRoleChangeRequest::OnEntryL()
+/**
+
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for outgoing role change request> - entering state"), &StateMachine());
+
+ // call base class's method
+ CPanRemDevStateWaitingForRoleSwitchBase::OnEntryL();
+ }
+
+void CPanRemDevStateWaitingForRoleSwitchForOutgoingRoleChangeRequest::BnepRoleResponseFromRemoteDeviceL(TBnepSetupConnectionResponseMessage /*aRoleResponseCode*/)
+/**
+They've responded to our role request twice!
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for outgoing role change request> - BNEP role response from remote device, they've already replied once - disconnecting them!"), &StateMachine());
+
+ // drop the role response packet that the remote device has incorrectly sent us
+ }
+
+CPanRemDevStateBase* CPanRemDevStateWaitingForRoleSwitchForOutgoingRoleChangeRequest::DoRoleSwitchSuccessL()
+/**
+We've managed to role switch, so the role upgrade has completed successfully
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for outgoing role change request> - role switch succeeded, going to active state"), &StateMachine());
+
+ CPanRemDevStateBase* nextState = new(ELeave) CPanRemDevStateActive(StateMachine());
+ return nextState;
+ }
+
+CPanRemDevStateBase* CPanRemDevStateWaitingForRoleSwitchForOutgoingRoleChangeRequest::DoRoleSwitchFailureL(TInt /*aError*/)
+/**
+Role switch failed, but this was a role change so return to old role in active state
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for outgoing role change request> - role change failed, disconnecting remote device"), &StateMachine());
+
+ // Whilst the spec says we should return to previous roles when this role upgrade fails,
+ // we're now in the situation that we're GN/NAP, they're U, and we can't become the piconet
+ // master - so the best/most reliable/only way to recover is to disconnect them. Not
+ // entirely according-to-spec, but then they shouldn't let us become master then refuse
+ // to role switch!
+ User::Leave(KErrCouldNotBecomePiconetMaster);
+ return NULL; // will never get here
+ }
+
+//
+// CPanRemDevStateWaitingForRoleSwitchForIncomingRoleChangeRequest
+//
+
+CPanRemDevStateWaitingForRoleSwitchForIncomingRoleChangeRequest::CPanRemDevStateWaitingForRoleSwitchForIncomingRoleChangeRequest(MPanRemDevStateMachineNotify& aStateMachine, TBluetoothPanRole aPendingLocalRole, TBluetoothPanRole aPendingRemoteRole)
+ : CPanRemDevStateWaitingForRoleSwitchForIncomingConnection(aStateMachine, EPanRemDevStateWaitingForRoleSwitchForIncomingRoleChangeRequest),
+ iPendingLocalRole(aPendingLocalRole),
+ iPendingRemoteRole(aPendingRemoteRole)
+
+/**
+
+*/
+ { }
+
+void CPanRemDevStateWaitingForRoleSwitchForIncomingRoleChangeRequest::OnEntryL()
+/**
+
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for incoming role change request> - entering state"), &StateMachine());
+
+ // call base class's method
+ CPanRemDevStateWaitingForRoleSwitchBase::OnEntryL();
+ }
+
+CPanRemDevStateBase* CPanRemDevStateWaitingForRoleSwitchForIncomingRoleChangeRequest::DoRoleSwitchSuccessL()
+ {
+ LOG1(_L("RemDevState[%x]: <CPanRemDevStateWaitingForRoleSwitchForIncomingRoleChangeRequest> - role switch succeeded"), &StateMachine());
+
+ // tell the remote device the connection was successful
+ StateMachine().SendRoleResponse(EOperationSuccessful);
+
+ // Store the new roles
+ StateMachine().LocalRole() = iPendingLocalRole;
+ StateMachine().RemoteRole() = iPendingRemoteRole;
+
+ // Changing role from GN/NAP to U. If this connection previously had access to the
+ // uplink this should be revoked.
+ if(StateMachine().LocalRole() == EPanRoleU)
+ {
+ StateMachine().SetUplinkAccessAllowed(EFalse);
+ }
+
+ // let the role state machine know that this connection is now active
+ CPanRemDevStateBase* nextState = new(ELeave) CPanRemDevStateIncomingNotification(StateMachine());
+ return(nextState);
+ }
+
+CPanRemDevStateBase* CPanRemDevStateWaitingForRoleSwitchForIncomingRoleChangeRequest::DoRoleSwitchFailureL(TInt /*aError*/)
+/**
+Signal the remote device that the role change didn't work, and go back to active state
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <waiting for role switch for incoming role change request> - role change failed, signalling remote device and going to active state"), &StateMachine());
+ // tell the remote device the connection was unsuccessful
+ StateMachine().SendRoleResponse(EConnectionNotAllowed);
+ // let the role state machine know that the role change failed
+ StateMachine().RoleChangeFailed();
+ CPanRemDevStateBase* nextState = new(ELeave) CPanRemDevStateActive(StateMachine());
+ return(nextState);
+ }
+
+//
+// CPanRemDevStateActive
+//
+
+CPanRemDevStateActive::CPanRemDevStateActive(MPanRemDevStateMachineNotify& aStateMachine) :
+ CPanRemDevStateBase(aStateMachine, EPanRemDevStateActive)
+/**
+
+*/
+ { }
+
+void CPanRemDevStateActive::OnEntryL()
+/**
+
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <device active> - entering state"), &StateMachine());
+
+ StateMachine().DeviceActive();
+ }
+
+void CPanRemDevStateActive::BnepRoleRequestFromRemoteDeviceL(const TUUID& aRequestedLocalRole, const TUUID& aRequestedRemoteRole)
+/**
+Remote device is trying to renegotiate roles with us
+@note This may also occur because our role response got lost, so send it again...
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <device active> - BNEP role request received from remote device..."), &StateMachine());
+
+ TInt err;
+ TBluetoothPanRole proposedLocalRole;
+ TBluetoothPanRole proposedRemoteRole;
+
+ // Convert the role from the remote device. If these are invalid the connection will be terminated.
+ ConvertUuidsToPanRolesL(aRequestedLocalRole, aRequestedRemoteRole, proposedLocalRole, proposedRemoteRole);
+
+ if((StateMachine().LocalRole() == proposedLocalRole) && (StateMachine().RemoteRole() == proposedRemoteRole)) // they've lost our response, so resend
+ {
+ LOG1(_L("RemDevState[%x]: <device active> - ...roles are the same as before, they obviously lost our role response - resending"), &StateMachine());
+ StateMachine().SendRoleResponse(EOperationSuccessful);
+ }
+ else // it's an attempt to renegotiate roles
+ {
+ LOG1(_L("RemDevState[%x]: <device active> - ..., they want to renegotiate roles"), &StateMachine());
+
+ CPanRemDevStateBase* nextState = NULL;
+
+ LOG1(_L("RemDevState[%x]: <active> - checking role request for incoming role upgrade attempt..."), &StateMachine());
+ err = StateMachine().RoleChangeRequestFromPeer(proposedLocalRole, proposedRemoteRole);
+ switch(err)
+ {
+ case KErrNone:
+ {
+ LOG1(_L("RemDevState[%x]: <active> - ...successful, checking to see if M/S switch necessary..."), &StateMachine());
+
+ err = PerformMasterSlaveSwitchIfNecessary(proposedLocalRole);
+ if(err==KErrWaitingForBasebandRoleSwitch)
+ {
+ nextState = new(ELeave) CPanRemDevStateWaitingForRoleSwitchForIncomingRoleChangeRequest(StateMachine(), proposedLocalRole, proposedRemoteRole);
+ break;
+ }
+ else if(err)
+ {
+ LOG1(_L("RemDevState[%x]: <active> - ...M/S switch required and failed - disconnecting device."), &StateMachine());
+ // remote device would not perform role switch (maybe it needs to stay as master for another profile it's using...)
+ StateMachine().SendRoleResponse(EConnectionNotAllowed);
+ StateMachine().RoleChangeFailed();
+ break;
+ }
+
+ LOG1(_L("RemDevState[%x]: <active> - ...M/S switch not required, sending successful connect response."), &StateMachine());
+ StateMachine().SendRoleResponse(EOperationSuccessful);
+
+ // Store the new roles
+ StateMachine().LocalRole() = proposedLocalRole;
+ StateMachine().RemoteRole() = proposedRemoteRole;
+
+ // Changing role from GN/NAP to U. If this connection previously had access to the
+ // uplink this should be revoked.
+ if(StateMachine().LocalRole() == EPanRoleU)
+ {
+ StateMachine().SetUplinkAccessAllowed(EFalse);
+ }
+
+ // remain in active state
+ StateMachine().DeviceActive();
+ break;
+ }
+ case KErrLocked:
+ {
+ LOG1(_L("RemDevState[%x]: <active> - ...role state machine busy, waiting."), &StateMachine());
+
+ // Create the "waiting" state
+ nextState = new(ELeave) CPanRemDevStateWaitingForLocalRoleStateMachineAvailabilityForIncomingRoleChangeRequest(StateMachine(), proposedLocalRole, proposedRemoteRole);
+ break;
+ }
+
+ case KErrInvalidOrUnacceptableRoleCombination:
+ LOG1(_L("RemDevState[%x]: <active> - ...Role change request can't be processed."), &StateMachine());
+ StateMachine().SendRoleResponse(EConnectionNotAllowed);
+ // We don't want to change state or inform the state machine as it returned the error.
+ break;
+
+ default:
+ // if err is something other than KErrNoMemory that might indicate an internal error in the state
+ // machine, so ASSERT_DEBUG. We can probably carry on even if the error is unexpected, as leaving
+ // will cause this connection to shutdown.
+ __ASSERT_DEBUG(err == KErrNoMemory, PanicInState(EPanAgentRoleStateMachineReturnedUnexpectedErrorCode));
+ User::Leave(err);
+ break;
+ };
+
+ if(nextState) // we've decided we need to go to another state to continue
+ {
+ StateMachine().SetState(*nextState);
+ delete this;
+ return;
+ }
+ }
+ }
+
+void CPanRemDevStateActive::BnepRoleResponseFromRemoteDeviceL(TBnepSetupConnectionResponseMessage aRoleResponseCode)
+/**
+Something's gone very wrong - what is the other device doing?
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <device active> - BNEP role response received from remote device, what are they up to? We haven't got an outstanding role request (this might change after a refactoring of the remote device states though)"), &StateMachine());
+
+ // for robustness sake, accept a successful role response, but disconnect them otherwise
+ if(aRoleResponseCode!=EOperationSuccessful)
+ {
+ User::Leave(KErrDodgyResponseFromRemoteDevice);
+ }
+ }
+
+void CPanRemDevStateActive::RemoteDeviceDisconnectL(TInt aError)
+/**
+Remote device has disconnected
+@param aError The reason for the remote device disconnect
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <device active> - remote device disconnect received, they've obviously given up talking to us."), &StateMachine());
+
+ StateMachine().ResetConnectionRetryAttempts(); // reset the connection retry attempts
+
+ User::Leave(aError); // will shutdown the connection
+ }
+
+void CPanRemDevStateActive::ReadyForRoleRequestL()
+/**
+Indication that the main state machine wants us to renegotiate our roles
+@note According to the spec, if we fail to negotiate a new role we remain connected and in our old roles
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <device active> - ready for role request received from role state machine - it obviously wants us to renegotiate our roles."), &StateMachine());
+
+ CPanRemDevStateBase* nextState = new(ELeave) CPanRemDevStatePerformingRoleNegotiationForOutgoingRoleChange(StateMachine());
+ StateMachine().SetState(*nextState);
+ delete this;
+ return;
+ }
+
+void CPanRemDevStateActive::ShutdownL()
+/**
+Disconnect command from local device
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <device active> - locally requested disconnect received."), &StateMachine());
+
+ User::Leave(KErrLocallyInitiatedDisconnect); // will shutdown the connection
+ }
+
+// This returns a distilled (i.e., not the actual remote device state)
+// version of the current connection status of the remote device
+TRemoteDeviceState CPanRemDevStateActive::GetState() const
+ {
+ return EActive;
+ }
+
+//
+// CPanRemDevStateShutdown
+//
+
+CPanRemDevStateShutdown::CPanRemDevStateShutdown(MPanRemDevStateMachineNotify& aStateMachine) :
+ CPanRemDevStateBase(aStateMachine, EPanRemDevStateShutdown)
+/**
+
+*/
+ { }
+
+void CPanRemDevStateShutdown::OnEntryL()
+/**
+
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <shutting down connection> - entering state"), &StateMachine());
+ // put an async break in here to ensure that if we arrive here synchronously from
+ // the initialising state in the role state machine, that we give the role state
+ // machine chance to transition to a new state before telling it we're shutting down
+ TRequestStatus* status = &StateMachine().Status();
+ User::RequestComplete(status, KErrNone);
+ StateMachine().SetActive();
+ }
+
+void CPanRemDevStateShutdown::BnepRoleRequestFromRemoteDeviceL(const TUUID& /*aRequestedLocalRole*/, const TUUID& /*aRequestedRemoteRole*/)
+/**
+Shouldn't receive this (the remote device should be disconnected) but just in case...
+@note *Must not* leave from here, otherwise we're in an endless loop
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <shutting down connection> - BNEP role request received from remote device, but we're shutting down so just ignore it."), &StateMachine());
+
+ // better tell them that we're not going to do anything
+ StateMachine().SendRoleResponse(EConnectionNotAllowed);
+ }
+
+void CPanRemDevStateShutdown::BnepRoleResponseFromRemoteDeviceL(TBnepSetupConnectionResponseMessage /*aRoleResponseCode*/)
+/**
+Shouldn't receive this (the remote device should be disconnected) but just in case...
+@note *Must not* leave from here, otherwise we're in an endless loop
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <shutting down connection> - BNEP role response received from remote device, but we're shutting down so just ignore it."), &StateMachine());
+
+ // We're disconnecting, so we don't care, just bin it (ie. do nothing...)
+ }
+
+void CPanRemDevStateShutdown::RemoteDeviceDisconnectL(TInt /*aError*/)
+/**
+Shouldn't receive this (the remote device should be disconnected) but just in case...
+@note *Must not* leave from here, otherwise we're in an endless loop
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <shutting down connection> - remote device disconnect received; odd, they should already be disconnected."), &StateMachine());
+
+ // Again, we're disconnecting, so we don't care, just bin it (ie. do nothing...)
+ }
+
+void CPanRemDevStateShutdown::ShutdownL()
+/**
+Whoops - double disconnect from local device...
+@note *Must not* leave from here, otherwise we're in an endless loop
+*/
+ {
+ // It is possible to request a shutdown of a remote device when it is already in
+ // the shutdown state, so don't panic. This occurs when the last remote device receives a
+ // disconnect and places itself in the shutdown state but only removes itself from the agent
+ // after an async event.
+ // As it was the last remote device this cause LinkLayerDown() to be called on Nifman which
+ // shuts down the agent. The agent then disconnects all remote devices. If the async event
+ // has not occured for the last remote device shutdown then the agent calls shutdown on the
+ // remote device again. This is ok as the async event completing will inform the agent and then
+ // the agent will do a full shutdown.
+
+ LOG1(_L("RemDevState[%x]: <shutting down connection> - remote device disconnect request received, already shutting down so nothing to do."), &StateMachine());
+ }
+
+void CPanRemDevStateShutdown::AsyncEventCompleteL()
+/**
+Async callback to tell us to shutdown the state machine
+@note *Must not* leave from here, otherwise we're in an endless loop
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <shutting down connection> - async event complete, shutting down"), &StateMachine());
+
+ if(StateMachine().HasBnepChannel())
+ {
+ StateMachine().DisconnectBnepChannel();
+ }
+
+ StateMachine().ShutdownComplete();
+ // don't "delete this" - this is the terminal state, so the state machine has to delete us
+ }
+
+void CPanRemDevStateShutdown::AsyncEventCancelL()
+/**
+
+@note *Must not* leave from here, otherwise we're in an endless loop
+*/
+ {
+ TRequestStatus* status = &StateMachine().Status();
+ User::RequestComplete(status, KErrCancel); // to keep CActive::Cancel() happy
+ }
+
+// This returns a distilled (i.e., not the actual remote device state)
+// version of the current connection status of the remote device
+TRemoteDeviceState CPanRemDevStateShutdown::GetState() const
+ {
+ return EDisconnecting;
+ }
+
+//
+// CPanRemDevStateIncomingNotification
+//
+
+CPanRemDevStateIncomingNotification::CPanRemDevStateIncomingNotification(MPanRemDevStateMachineNotify& aStateMachine) :
+ CPanRemDevStateBase(aStateMachine, EPanRemDevStateIncomingNotification)
+/**
+This state manages the incoming uplink access allowed for local NAP role notifier
+*/
+ { }
+
+CPanRemDevStateIncomingNotification::~CPanRemDevStateIncomingNotification()
+ {
+ delete iNapUplinkAuthorisationHelper;
+ }
+
+void CPanRemDevStateIncomingNotification::OnEntryL()
+ {
+ if(StateMachine().LocalRole() == EPanRoleNap)
+ {
+ iNapUplinkAuthorisationHelper = new(ELeave) CNapUplinkAuthorisationHelper(*this);
+
+ // Set requested connection address.
+ TBTDevAddr requestingDeviceAddr = StateMachine().RemSockAddr().BTAddr();
+ iNapUplinkAuthorisationHelper->PanConnectionList().SetRequestedConnectionAddr(requestingDeviceAddr);
+
+ // Get current connection information.
+ StateMachine().GetExistingConnections(iNapUplinkAuthorisationHelper->PanConnectionList());
+
+ iNapUplinkAuthorisationHelper->PerformNapUplinkAuthorisationL();
+ }
+ else
+ {
+ // Notifier not required - go to active state.
+ CPanRemDevStateBase* nextState = new(ELeave) CPanRemDevStateActive(StateMachine());
+ StateMachine().SetState(*nextState);
+ delete this;
+ return; // Just to be safe after 'delete this'
+ }
+ }
+
+// From MNapUplinkAuthorisationRequester
+void CPanRemDevStateIncomingNotification::MnuarNapUplinkAuthorisationHelperComplete(TInt aError, TNapConnectionResult aResult)
+ {
+ if(aError == KErrNone)
+ {
+ switch(aResult)
+ {
+ case EDisallowNewNapConnection:
+ // Disconnect this connection by moving into the shutdown state.
+ ShutdownConnection(KErrAccessDenied);
+ break;
+
+ case EAcceptNapConnectionAllowUplinkAccess:
+ // Inform the packet driver that this connection should have access to the NAP service and
+ // close any connection that currently has access to the uplink.
+ StateMachine().SetUplinkAccessAllowed(ETrue);
+
+ // Fall onto next case...
+
+ case EAcceptNapConnectionDisallowUplinkAccess:
+ {
+ CPanRemDevStateBase* nextState = NULL;
+ TRAPD(err, nextState = new(ELeave) CPanRemDevStateActive(StateMachine()));
+ if(err == KErrNone)
+ {
+ StateMachine().SetState(*nextState);
+ delete this;
+ return;
+ }
+ else
+ {
+ ShutdownConnection(err);
+ }
+ }
+ break;
+
+ default:
+ PanicInState(EInvalidResultCodeFromNapUplinkAuthorisationNotifier);
+ break;
+ };
+ }
+ else
+ {
+ // Disconnect this connection by moving into the shutdown state.
+ ShutdownConnection(aError);
+ }
+ }
+
+void CPanRemDevStateIncomingNotification::BnepRoleRequestFromRemoteDeviceL(const TUUID& /*aRequestedLocalRole*/, const TUUID& /*aRequestedRemoteRole*/)
+/**
+A role request from the remote device can't be handled at this time
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <Waiting for incoming notification> - BNEP role reponse from remote device."), &StateMachine());
+
+ // drop the role request packet that the remote device has sent us
+ }
+
+void CPanRemDevStateIncomingNotification::BnepRoleResponseFromRemoteDeviceL(TBnepSetupConnectionResponseMessage /*aRoleResponseCode*/)
+/**
+A role request has not been sent by this device. This is unexpected behaviour by the remote.
+*/
+ {
+ LOG1(_L("RemDevState[%x]: <Waiting for incoming notification> - BNEP role reponse from remote device."), &StateMachine());
+
+ // drop the role response packet that the remote device has incorrectly sent us
+ }
+
+void CPanRemDevStateIncomingNotification::RemoteDeviceDisconnectL(TInt aError)
+ {
+ LOG1(_L("RemDevState[%x]: <Waiting for incoming notification> - remote device disconnect received; odd, they should already be disconnected."), &StateMachine());
+
+ // Shutdown the connection.
+ ShutdownConnection(aError);
+ }
+
+void CPanRemDevStateIncomingNotification::ShutdownL()
+ {
+ LOG1(_L("RemDevState[%x]: <CPanRemDevStateIncomingNotification> - locally requested disconnect received"), &StateMachine());
+
+ // outstanding async request will be cancelled by state machine when we leave
+ User::Leave(KErrLocallyInitiatedDisconnect);
+ }
+
+// This returns a distilled (i.e., not the actual remote device state)
+// version of the current connection status of the remote device
+TRemoteDeviceState CPanRemDevStateIncomingNotification::GetState() const
+ {
+ return EPerformingNegotiation;
+ }
+
+void CPanRemDevStateIncomingNotification::ShutdownConnection(TInt aError)
+ {
+ if(!iShutdownCalled)
+ {
+ // Shutdown the connection.
+ iShutdownCalled = ETrue;
+ StateMachine().Shutdown(aError);
+ }
+ }
+
+
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+CPanRemDevStatePaused::CPanRemDevStatePaused(MPanRemDevStateMachineNotify& aStateMachine, CPanRemDevStateBase& aNextState)
+ : CPanRemDevStateBase(aStateMachine, EPanRemDevStatePaused), iNextState(&aNextState)
+ {
+ }
+
+CPanRemDevStatePaused::~CPanRemDevStatePaused()
+ {
+ delete iNextState;
+ }
+
+void CPanRemDevStatePaused::OnEntryL()
+ {
+ // Does nothing
+ }
+
+void CPanRemDevStatePaused::ShutdownL()
+ {
+ // We don't know the appropriate action so allow the next states
+ // ShutdownL to execute. We'll cleanup the next state when the
+ // RemDevStateMachine deletes us
+ iNextState->ShutdownL();
+ }
+
+TRemoteDeviceState CPanRemDevStatePaused::GetState() const
+ {
+ return iNextState->GetState();
+ }
+
+void CPanRemDevStatePaused::AsyncEventCancelL()
+ {
+ // Next state hasn't started yet so no need to cancel it
+ }
+
+void CPanRemDevStatePaused::AsyncEventCompleteL()
+ {
+ StateMachine().SetState(*iNextState);
+
+ // We no longer own the next state
+ iNextState = NULL;
+ delete this;
+ }
+
+#endif
+// SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY