bluetoothcommsprofiles/btpan/panagt/panagtremdevstates.cpp
changeset 0 29b1cd4cb562
--- /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