bluetoothcommsprofiles/btpan/panagt/panagtstates.cpp
author jontanne
Thu, 14 Oct 2010 11:30:12 +0100
changeset 27 83036355c0f3
parent 0 29b1cd4cb562
permissions -rw-r--r--
Add USB HCTL to bt package

// 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 role state machine state implementations
*/

#include <bluetooth/logger.h>
#include "panagtstates.h"
#include "panagtremdev.h"
#include "panlocalsdphelper.h"
#include "BTSec.h"
using namespace PanAgent;

#ifdef __FLOG_ACTIVE
_LIT8(KLogComponent, LOG_COMPONENT_PAN_AGENT);
#endif

CPanAgtStateBase* CPanAgtStateUninitialised::NewL(MPanAgtStateMachineNotify& aStateMachine)
	{
	CPanAgtStateUninitialised* self = new (ELeave) CPanAgtStateUninitialised(aStateMachine);
	CleanupStack::PushL(self);
	self->BaseConstructL();
	CleanupStack::Pop();
	return self;
	}
	
void CPanAgtStateUninitialised::OnEntryL()
	{	
	}

CPanAgtStateUninitialised::CPanAgtStateUninitialised(MPanAgtStateMachineNotify& aStateMachine) :
	CPanAgtStateBase(aStateMachine, EPanAgentStateUninitialised)
	{
	}
//
// CPanAgentStateInitialising
//
CPanAgentStateInitialising::CPanAgentStateInitialising(MPanAgtStateMachineNotify& aStateMachine) :
	CPanAgtStateBase(aStateMachine, EPanAgentStateInitialising)
/**

*/
	{	}
	
CPanAgtStateBase* CPanAgentStateInitialising::NewL(MPanAgtStateMachineNotify& aStateMachine)
	{
	CPanAgentStateInitialising* self = new (ELeave) CPanAgentStateInitialising(aStateMachine);
	CleanupStack::PushL(self);
	self->BaseConstructL();
	CleanupStack::Pop();
	return self;
	}
	
void CPanAgentStateInitialising::OnEntryL()
/**

*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()==0, PanicInState(EActiveDevicesInArrayInInitialisingState));
	__ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(ENegotiatingDevicesInArrayInInitialisingState));

	LOG(_L("RoleState: <initialising> - entering state"));
	
	// Have a look in commdb to see if we have a defined local role
	TUint32 roleTemp;
	StateMachine().Database().GetIntL(TPtrC(PAN_SERVICE_EXTENSIONS), TPtrC(PAN_LOCAL_ROLE), roleTemp);
	__ASSERT_DEBUG(roleTemp!=0xffff, PanicInState(EOldFormatPanRoleBeingUsedInCommdb));
	StateMachine().FixedLocalRole() = static_cast<TBluetoothPanRole>(roleTemp);
	LOG1(_L("RoleState: <initialising> - local device state in commdb is %x"), StateMachine().FixedLocalRole());

	// same thing for remote role
	StateMachine().Database().GetIntL(TPtrC(PAN_SERVICE_EXTENSIONS), TPtrC(PAN_PEER_ROLE), roleTemp);
	__ASSERT_DEBUG(roleTemp!=0xffff, PanicInState(EOldFormatPanRoleBeingUsedInCommdb));
	StateMachine().FixedRemoteRole() = static_cast<TBluetoothPanRole>(roleTemp);
	LOG1(_L("RoleState: <initialising> - remote device state in commdb is %x"), StateMachine().FixedRemoteRole());

	// Check if PAN NAP is allowed as a local role.
	TBool napEnabled = EFalse;
	TRAP_IGNORE(StateMachine().Database().GetBoolL(TPtrC(PAN_SERVICE_EXTENSIONS), TPtrC(PAN_NAP_SERVICE_ENABLED), napEnabled));
	StateMachine().SetNapEnabled(napEnabled);	
	
	// Check for incoming connection support and enable if necessary
	TBool allowIncoming;
	StateMachine().Database().GetBoolL(TPtrC(PAN_SERVICE_EXTENSIONS), TPtrC(PAN_ALLOW_INCOMING), allowIncoming);
	StateMachine().SetAllowIncoming(allowIncoming);	

	// make sure the fixed roles (if there are any) make sense
	User::LeaveIfError(IsRoleRequestValid(StateMachine().FixedLocalRole(), StateMachine().FixedRemoteRole()));

	if(napEnabled)
		{
		// NAP can only be enabled for a listening IAP.
		if(!allowIncoming) 
			{
			LOG(_L("RoleState: <initialising> - Listening must be enabled when NAP is enabled.  Fail initialisation"));
			User::Leave(KErrArgument);
			}
			
		if(!(StateMachine().FixedLocalRole() == EPanRoleUnknown || StateMachine().FixedLocalRole() == EPanRoleNap))
			{
			LOG1(_L("RoleState: <initialising> - Invalid Fixed Local Role %x"), StateMachine().FixedLocalRole());
			User::Leave(KErrArgument);
			}
		}
	else
		{
		if(StateMachine().FixedLocalRole() == EPanRoleNap)
			{
			LOG(_L("RoleState: <initialising> - Invalid Fixed Local Role PAN-NAP when NAP not enabled"));
			User::Leave(KErrArgument);
			}
		}
		
	if(allowIncoming)
		{
		// Only any point in advertising in SDP if we're allowing incoming connections...
		LOG(_L("RoleState: <initialising> - incoming support is enabled"));

		if(StateMachine().FixedLocalRole() == EPanRoleU)
			{
			LOG(_L("RoleState: <initialising> - Invalid PAN-U Fixed Local Role for listening IAP"));
			User::Leave(KErrArgument);
			}

		if(!(StateMachine().FixedRemoteRole() == EPanRoleUnknown || StateMachine().FixedRemoteRole() == EPanRoleU))
			{
			LOG1(_L("RoleState: <initialising> - Invalid Fixed Remote Role for listening IAP %x"), StateMachine().FixedRemoteRole());
			User::Leave(KErrArgument);
			}
		
		//If other services are active currently, we will not register sdp records and open listen socket
		if (StateMachine().IsNewPanConnectionAllowed())
			{
			StartListenerL();
			}
		}
#ifdef _DEBUG
	else  	// no incoming support, so just start outgoing connections and move to idle state
			// if incoming support is enabled, this will be done after all the SDP roles are registered
		{
		LOG(_L("RoleState: <initialising> - incoming support is disabled"));
		}
#endif		
	DoStartOutgoingL();
	}
		
void CPanAgentStateInitialising::DoStartOutgoingL()
/**
Start setting up outgoing connections, and move to the idle state
*/
	{
	if(StateMachine().SuppressOutgoing())	// check that outgoing connections are not suppressed 
											// (to allow UIs to start the ad-hoc IAP in incoming mode only,
											// and to allow reuse of the registering SDP records state to 
											// perform reregistration of SDP records - when reregistering
											// records, we don't want to prompt to start an outgoing connection)
		{
		LOG(_L("RoleState: <initialising/registering local SDP records> - outgoing connections suppressed, resetting suppression flag and moving directly to idle state"));
		StateMachine().ResetSuppressOutgoing(); // stop future outgoing connections being suppressed
		if(!(StateMachine().IsIncomingConnectionListenerEnabled()))
			{
			LOG(_L("RoleState: <initialising/registering local SDP records> - This is an invalid state while outgoing connection is suppressed without incoming listening enabled."));
			// outstanding async request will be cancelled by state machine when we leave
			User::Leave(KErrListenForIncomingConnectionRequestedWithoutListeningSupport);
			}
		}
	else
		{
		// outstanding async request will be cancelled by state machine when we leave
		StateMachine().SetupOutgoingConnectionsL();
		}
	
	CPanAgtStateBase* nextState = CPanAgtStateIdle::NewL(StateMachine());			
	StateMachine().SetState(*nextState);
	delete this;
	return;
	}

//
// CPanAgtStateIdle
//
CPanAgtStateBase* CPanAgtStateIdle::NewL(MPanAgtStateMachineNotify& aStateMachine)
	{
	CPanAgtStateIdle* self = new (ELeave) CPanAgtStateIdle(aStateMachine);
	CleanupStack::PushL(self);
	self->BaseConstructL();
	CleanupStack::Pop();
	return self;
	}
	
CPanAgtStateIdle::CPanAgtStateIdle(MPanAgtStateMachineNotify& aStateMachine) :
	CPanAgtStateBase(aStateMachine, EPanAgtStateIdle)
/**

*/
	{	}
	
void CPanAgtStateIdle::OnEntryL()
/**

*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()==0, PanicInState(EActiveDevicesInArrayInInitialisingState));
	__ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(ENegotiatingDevicesInArrayInInitialisingState));

	LOG(_L("RoleState: <idle> - entering state"));

	StateMachine().SendProgress(EPanAgtIdle, KErrNone);
	StartNegotiationWithFirstPendingDevice(); // if there's not already a device negotiating, start one negotiating
	}
	
void CPanAgtStateIdle::InitiateOutgoingConnectionL(TBluetoothPanRole& aRequestedLocalRole, TBluetoothPanRole& aRequestedRemoteRole, TPanDeviceWorthTryingRolesList& aWorthTryingRemoteRoles)
/**

*/
	{	
	LOG(_L("RoleState: <idle> - InitiateOutgoingConnectionL"));
	LOG3(_L("RoleState: <idle> - ...worthTrying roles - U:%x GN:%x NAP:%x..."), aWorthTryingRemoteRoles.IsWorthTryingU(), aWorthTryingRemoteRoles.IsWorthTryingGn(), aWorthTryingRemoteRoles.IsWorthTryingNap());
	
	// Determine the roles for this outgoing connection.
	aRequestedLocalRole = StateMachine().FixedLocalRole(); 
	if(aRequestedLocalRole == EPanRoleUnknown)
		{
		aRequestedLocalRole = EPanRoleU;
		}

	// aRequestedLocalRole should be set to the local role we want to be by the time we call the method below
	User::LeaveIfError(SelectRemoteRoleBasedOnLocalRole(aRequestedLocalRole, aRequestedRemoteRole, aWorthTryingRemoteRoles));

	// and now transition to the appropriate state
	CPanAgtStateBase* nextState = NULL;
	switch(aRequestedLocalRole)
		{
		case EPanRoleU:
			{
			// What about a multiple start case where there are several devices started at once,
			// you may be asking?
			// This is the wrong state to go into then...  However, if they all arrive in the 
			// outgoing connection starter at the same time (which they will), then they'll all 
			// get dumped into the array sychronously, and since each one has to asyhronously
			// connect a socket, by the time they call us for their role request, we'll know 
			// there's >1 device
			nextState = CPanAgtStateNegotiatingURole::NewL(StateMachine());
			break;			
			}
		case EPanRoleGn:
		case EPanRoleNap:
			{
			nextState = CPanAgtStateNegotiatingGnOrNapRole::NewL(StateMachine());
			break;
			}

		default:
			{
			PanicInState(EPanAgentRoleStateMachineInvalidLocalRole);
			break;
			}
		}

	__ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));
	StateMachine().SetState(*nextState);
	delete this;
	}

void CPanAgtStateIdle::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice)
/**
A remote device has disconnected before it even began role negotiation!  Obviously something dodgy about their role request...
*/
	{
	DoDeviceDisconnectL(aDevice);
	}

void CPanAgtStateIdle::IncomingConnectionFromPeerL(TBluetoothPanRole aLocalRole)
	{
	CPanAgtStateBase* nextState = NULL;
	switch(aLocalRole)
		{
		case EPanRoleU:
			{
			nextState = CPanAgtStateNegotiatingURole::NewL(StateMachine());
			break;			
			}

		case EPanRoleGn:
		case EPanRoleNap:
			{
			nextState = CPanAgtStateNegotiatingGnOrNapRole::NewL(StateMachine());
			break;
			}

		default:
			PanicInState(EInvalidRoleForIncomingConnectionFromPeerL);
		}
	__ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));
	StateMachine().SetState(*nextState);
	delete this;
	}

//
// CPanAgtStateNegotiatingURole
//
CPanAgtStateBase* CPanAgtStateNegotiatingURole::NewL(MPanAgtStateMachineNotify& aStateMachine)
	{
	CPanAgtStateNegotiatingURole* self = new (ELeave) CPanAgtStateNegotiatingURole(aStateMachine);
	CleanupStack::PushL(self);
	self->BaseConstructL();
	CleanupStack::Pop();
	return self;
	}
	
CPanAgtStateNegotiatingURole::CPanAgtStateNegotiatingURole(MPanAgtStateMachineNotify& aStateMachine) :
	CPanAgtStateBase(aStateMachine, EPanAgtStateNegotiatingURole)
/**

*/
	{	}

CPanAgtStateNegotiatingURole::CPanAgtStateNegotiatingURole(MPanAgtStateMachineNotify& aStateMachine, TPanAgtStates aStateNumber) :
	CPanAgtStateBase(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 CPanAgtStateNegotiatingURole::OnEntryL()
/**
Start deregistering unwanted local SDP records
*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()==0, PanicInState(EActiveDevicesInArrayInNegotiatingPanUState));
	__ASSERT_DEBUG(NegotiatingDeviceCount()==1, PanicInState(EMoreThanOneDeviceInNegotiatingModeInArray));

	LOG(_L("RoleState: <negotiating U> - entering state"));
		
	if(StateMachine().AllowIncoming())
		{
		// stop advertising U record
		StateMachine().PanLocalSdpRegistrar().UnregisterLocalSdpRecord(EPanRoleU);
		}
	}
	
void CPanAgtStateNegotiatingURole::InitiateOutgoingConnectionL(TBluetoothPanRole& /*aRequestedLocalRole*/, TBluetoothPanRole& /*aRequestedRemoteRole*/, TPanDeviceWorthTryingRolesList& /*aWorthTryingRemoteRoles*/)
/**
Don't accept more role requests when we're negotiating
*/
	{
	LOG(_L("RoleState: <negotiating U> - InitiateOutgoingConnectionL to another device, returning busy"));
	User::Leave(KErrLocked);
	}

void CPanAgtStateNegotiatingURole::IncomingConnectionFromPeerL(TBluetoothPanRole /*aLocalRole*/)
	{
	LOG(_L("RoleState: <negotiating U> - IncomingConnectionFromPeerL , returning busy"));
	User::Leave(KErrLocked);
	}
	
void CPanAgtStateNegotiatingURole::DeviceActiveL(CPanRemoteDeviceStateMachine& aDevice)
/**
A device has finished negotiation and is now active
*/
	{
	__ASSERT_ALWAYS(FindDeviceInArray(aDevice)>=0, PanicInState(EDeviceAttemptingToNegotiateThatIsNotInArray));
	__ASSERT_DEBUG(aDevice.GetState() == EActive, PanicInState(EDeviceActiveCalledByDeviceNotInActiveState));

	CPanAgtStateBase* nextState = CPanAgtStateURole::NewL(StateMachine());		
	StateMachine().SetState(*nextState);
	delete this;
	}

void CPanAgtStateNegotiatingURole::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice)
/**
A device has disconnected
*/
	{
	//This function will only be called when device is in EDisconnecting State.
	//Remote device state machine will first shutdown itself and then call panagent to
	//disconnect this device and remove it from the device array
	__ASSERT_DEBUG(aDevice.GetState() == EDisconnecting, PanicInState(EInvalidRemoteDeviceState));
	
	// disconnect them and shutdown or return to the idle state
	// outstanding async request will be cancelled by state machine when we leave
	DoDeviceDisconnectL(aDevice); // will leave and shutdown the connection if necessary

		StartListenerL();

	CPanAgtStateBase* nextState = CPanAgtStateIdle::NewL(StateMachine());
	StateMachine().SetState(*nextState);
	delete this;
	return;
	}

//
// CPanAgtStateURole
//
CPanAgtStateBase* CPanAgtStateURole::NewL(MPanAgtStateMachineNotify& aStateMachine)
	{
	CPanAgtStateURole* self = new (ELeave) CPanAgtStateURole(aStateMachine);
	CleanupStack::PushL(self);
	self->BaseConstructL();
	CleanupStack::Pop();
	return self;
	}
	
CPanAgtStateURole::CPanAgtStateURole(MPanAgtStateMachineNotify& aStateMachine) :
	CPanAgtStateBase(aStateMachine, EPanAgtStateURole)
/**

*/
	{	}
	
void CPanAgtStateURole::OnEntryL()
/**

*/
	{
	__ASSERT_DEBUG(NegotiatingDeviceCount()==0,PanicInState(EDeviceInNegotiatingModeOnEntryToUState));
	__ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ETooManyDevicesAttachedInURole));

	LOG(_L("RoleState: <U role> - entering state"));

	StateMachine().SendProgress(EPanAgtURole, KErrNone);
	StartNegotiationWithFirstPendingDevice();
	}
	
void CPanAgtStateURole::InitiateOutgoingConnectionL(TBluetoothPanRole& /*aRequestedLocalRole*/, TBluetoothPanRole& /*aRequestedRemoteRole*/, TPanDeviceWorthTryingRolesList& /*aWorthTryingRemoteRoles*/)
	{
	// Need to become GN / NAP.  Check that this will be acceptable for the fixed roles
	if(StateMachine().FixedLocalRole() == EPanRoleU || 
	   (StateMachine().FixedRemoteRole() == EPanRoleNap || StateMachine().FixedRemoteRole() == EPanRoleGn))
		{
		User::Leave(KErrInvalidOrUnacceptableRoleCombination);
		}
	else
		{
		CPanAgtStateBase* nextState = CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::NewL(StateMachine());
		StateMachine().SetState(*nextState);
		delete this;
		User::Leave(KErrLocked);
		}
	}

void CPanAgtStateURole::IncomingConnectionFromPeerL(TBluetoothPanRole aLocalRole)
	{
	if(aLocalRole == EPanRoleU)
		{
		// An existing connection is established to the PAN-U role.
		User::Leave(KErrInvalidOrUnacceptableRoleCombination);
		}

	// Start upgrade to GN/NAP
	CPanAgtStateBase* nextState = CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::NewL(StateMachine());
	StateMachine().SetState(*nextState);
	delete this;
	User::Leave(KErrLocked); // hold the new device off until we've renegotiated with the existing one			
	}

void CPanAgtStateURole::RoleChangeRequestFromPeerL(TBluetoothPanRole aLocalRole)
	{
	CPanAgtStateBase* nextState = NULL;
	switch(aLocalRole)
		{
		case EPanRoleU:
			nextState = CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::NewL(StateMachine());
			break;
			
		case EPanRoleGn:
		case EPanRoleNap:
			nextState = CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::NewL(StateMachine());
			break;
			
		default:
			PanicInState(EInvalidLocalRoleFromRoleChangeRequestFromPeer);
		}
		
	__ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));
	StateMachine().SetState(*nextState);
	delete this;
	}
	
#ifdef _DEBUG
void CPanAgtStateURole::DeviceActiveL(CPanRemoteDeviceStateMachine& aDevice)
#else
void CPanAgtStateURole::DeviceActiveL(CPanRemoteDeviceStateMachine& /*aDevice*/)
#endif // _DEBUG
/**
@note This is only allowed if it's the same device as we're already attached to 
ie. we're performing a role switch
*/
	{
	__ASSERT_DEBUG(aDevice.GetState() == EPerformingNegotiation, PanicInState(EUnexpectedDeviceActiveReceivedByState));
	}

void CPanAgtStateURole::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice)
/**
A remote device has completed its shutdown
*/
	{
	LOG(_L("RoleState: <U role> - device disconnected..."));
	DoDeviceDisconnectL(aDevice); // if there are no devices in the array and we're not supporting incoming connection this method will leave

	// This could be the on device connected to the U or it could be a failed upgrade device.
	if(StateMachine().Devices().Count() == 0)
		{
		StartListenerL();
		CPanAgtStateBase* nextState = CPanAgtStateIdle::NewL(StateMachine());
		StateMachine().SetState(*nextState);
		delete this;
		}
	}

void CPanAgtStateURole::StateSendRoleNotification()
	{
	StateMachine().SendProgress(EPanAgtURole, KErrNone);
	}
		
//
// CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest
//
CPanAgtStateBase* CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::NewL(MPanAgtStateMachineNotify& aStateMachine)
	{
	CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest* self = new (ELeave) CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest(aStateMachine);
	CleanupStack::PushL(self);
	self->BaseConstructL();
	CleanupStack::Pop();
	return self;
	}
	
CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest(MPanAgtStateMachineNotify& aStateMachine) :
	CPanAgtStateBase(aStateMachine, EPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest)
/**

*/
	{	}
	
void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::OnEntryL()
/**
@pre Just come from U mode, so only one active device in the array
*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ETooManyDevicesAttachedWhenRenegotiatingActiveConnectionForGnOrNapUpgrade)); // not quite enough to ensure we were previously in U role, but as good as we're going to get

	LOG(_L("RoleState: <CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest> - entering state"));
	
	StateMachine().SendProgress(EPanAgtReconfiguringPiconet, KErrNone);
	
	CPanRemoteDeviceStateMachine& currentActiveDevice = FindDeviceInActiveState(); // there will only be one (we're in U role)
	currentActiveDevice.ReadyForRoleRequest(); // signal it to redo role negotiation
	}
	
void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::InitiateOutgoingConnectionL(TBluetoothPanRole& /*aRequestedLocalRole*/, TBluetoothPanRole& /*aRequestedRemoteRole*/, TPanDeviceWorthTryingRolesList& /*aWorthTryingRemoteRoles*/)
	{
	// Negotiation in progress - Wait...
	User::Leave(KErrLocked);
	}
	
void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::IncomingConnectionFromPeerL(TBluetoothPanRole /*aLocalRole*/)
	{
	// Negotiation in progress - Wait...
	User::Leave(KErrLocked);
	}

void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::RoleChangeRequestFromPeerL(TBluetoothPanRole /*aLocalRole*/)
	{
	// Not in a state to handle this unexpected event.
	User::Leave(KErrNotReady);
	}

void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::PerformLocalRoleChangeRequestL(TBluetoothPanRole& aLocalRole, TBluetoothPanRole& aRemoteRole)
	{
	aLocalRole = StateMachine().NapEnabled() ? EPanRoleNap : EPanRoleGn;
	aRemoteRole = EPanRoleU;
	}
	
void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::DeviceActiveL(CPanRemoteDeviceStateMachine& aDevice)
/**
We've successfully managed to renegotiate roles with the currently connected device
*/
	{
	__ASSERT_ALWAYS(FindDeviceInArray(aDevice)>=0, PanicInState(EDeviceAttemptingToNegotiateThatIsNotInArray));
	__ASSERT_DEBUG(aDevice.GetState() == EActive, PanicInState(EDeviceActiveCalledByDeviceNotInActiveState));
	LOG(_L("RoleState: <CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest> - device active received"));

	CPanAgtStateBase* nextState = CPanAgtStateGnOrNapRole::NewL(StateMachine());
	StateMachine().SetState(*nextState);
	delete this;
	}

void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::DeviceRoleChangeFailedL(CPanRemoteDeviceStateMachine& /*aDevice*/)
/**
Role upgrade failed, return to our previous state
*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()==0, PanicInState(EActiveDevicesInArrayInRenegActConnToGnOrNapRoleAtOurBehest));
	__ASSERT_DEBUG(NegotiatingDeviceCount()==1, PanicInState(EMoreThanOneDeviceInNegotiatingModeInArray));
	
	LOG(_L("RoleState: <CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest> - role change failed..."));
	// there should be (at least one) pending device (the one that caused us to attempt the upgrade to GN/NAP)
	// disconnect it (them), because the role change failed
	// need to do this because the new device may have been added by the user, so we can't rely
	// on a timeout from a remote device, because there may not be one connected
	RPointerArray<CPanRemoteDeviceStateMachine>& deviceArray = StateMachine().Devices();
	for(TInt i = 0; i < deviceArray.Count(); ++i)
		{
		if(deviceArray[i]->GetState() != EPerformingNegotiation)	// ie. it's not the device we just failed to get to change role
			{
			LOG(_L("RoleState: <CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest> - ...disconnecting non-negotiating device..."));
			deviceArray[i]->Disconnect();
			}
		}
		
	LOG(_L("RoleState: <CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest> - ...setting original device active again and going to U role"));

	// since we're negotiating GN/NAP role, then we must previously have been in U role
	__ASSERT_DEBUG(ActiveDeviceCount()==0, PanicInState(ETooManyDevicesAttachedWhenRenegotiatingActiveConnectionForGnOrNapUpgrade)); // not quite enough to ensure we were previously in U role, but as good as we're going to get
	__ASSERT_DEBUG(NegotiatingDeviceCount()==1, PanicInState(EMoreThanOneDeviceInNegotiatingModeInArray));

	// Enter negotiating U role state and wait for the device active 
	// notification from the remote device state machine
	CPanAgtStateBase* nextState = CPanAgtStateNegotiatingURole::NewL(StateMachine());
	StateMachine().SetState(*nextState);
	delete this;
	return;
	}

void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice)
/**

*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()==0, PanicInState(EActiveDevicesInArrayInRenegActConnToGnOrNapRoleAtOurBehest));
	__ASSERT_DEBUG(NegotiatingDeviceCount()==1, PanicInState(EMoreThanOneDeviceInNegotiatingModeInArray));


	//This function will only be called when device is in EDisconnecting State.
	//Remote device state machine will first shutdown itself and then call panagent to
	//disconnect this device and remove it from the device array
	__ASSERT_DEBUG(aDevice.GetState() == EDisconnecting, PanicInState(EInvalidRemoteDeviceState));

	LOG(_L("RoleState: <CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest> - whoops, the remote device we're trying to upgrade has disconnected!"));
	DoDeviceDisconnectL(aDevice); // will leave if there are no other devices waiting and we're not accepting incoming connections

	// go back to idle state and start negotiating with the idle device that should be in the array
	// there should be one there, as it was the reason that we tried to do role upgrade in the first place!
	StartListenerL();

	CPanAgtStateBase* nextState = CPanAgtStateIdle::NewL(StateMachine());
	StateMachine().SetState(*nextState);
	delete this;
	return;

	}

CPanRemoteDeviceStateMachine& CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::FindDeviceInActiveState()
/**
Return the device that is in the active state
@pre There is only one device in an active state
*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(EMoreThanOneActiveDeviceWhenTryingToRenegotiateUToGnOrNapRoleChange));

	RPointerArray<CPanRemoteDeviceStateMachine>& deviceArray = StateMachine().Devices();
	for(TInt i=0;i<deviceArray.Count();++i)
		{
		if(deviceArray[i]->GetState() == EActive)
			{
			return (*(deviceArray[i]));
			}
		}
		
	PanicInState(ENoActiveDeviceInArray);
	// next bit will never be reached, but it keeps the compiler quiet...
	CPanRemoteDeviceStateMachine* notUsed = NULL;
	return(*notUsed);
	}

//
// CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest
//
CPanAgtStateBase* CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::NewL(MPanAgtStateMachineNotify& aStateMachine)
	{
	CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest* self = new (ELeave) CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest(aStateMachine);
	CleanupStack::PushL(self);
	self->BaseConstructL();
	CleanupStack::Pop();
	return self;
	}
	
CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest(MPanAgtStateMachineNotify& aStateMachine) :
	CPanAgtStateBase(aStateMachine, EPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest)
/**

*/
	{	}
	
void CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::OnEntryL()
/**

*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ENoActiveDeviceInArrayInRenegActConnToURoleAtPeersBehest)); 		// if we're going to U and we've not got an active device, we're in trouble
	__ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray));
	LOG(_L("RoleState: <renegotiating active connection to U role at peers behest> - entering state"));

	StateMachine().SendProgress(EPanAgtReconfiguringPiconet, KErrNone);	
	
	// we've already had the role request from the remote device in the previous state, so just
	// wait for device active or role changed failed
	}
	
void CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::InitiateOutgoingConnectionL(TBluetoothPanRole& /*aRequestedLocalRole*/, TBluetoothPanRole& /*aRequestedRemoteRole*/, TPanDeviceWorthTryingRolesList& /*aWorthTryingRemoteRoles*/)
	{
	// Negotiation in progress - Wait...
	User::Leave(KErrLocked);
	}
	
void CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::IncomingConnectionFromPeerL(TBluetoothPanRole /*aLocalRole*/)
	{
	// Negotiation in progress - Wait...
	User::Leave(KErrLocked);
	}

void CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::DeviceActiveL(CPanRemoteDeviceStateMachine& aDevice)
/**
We've successfully managed to renegotiate roles with the currenly connected device
*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(EActiveDevicesInArrayInRenegActConnToGnOrNapRoleAtOurBehest));
	__ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray));

	LOG(_L("RoleState: <renegotiating active connection to U role at peers behest> - device active, role change successful"));

	if(aDevice.GetState() == EActive) // we've succeeded in changing role
		{
		CPanAgtStateBase* nextState = CPanAgtStateURole::NewL(StateMachine());
		StateMachine().SetState(*nextState);
		delete this;
		return;
		}
	else
		{
		PanicInState(EUnexpectedDeviceActiveReceivedByState);
		}
	}
	
void CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::DeviceRoleChangeFailedL(CPanRemoteDeviceStateMachine& /*aDevice*/)
/**
Unlikey this can happen - if we get into this state we've decided we can do the role change.
If this gets called, the remote device state machine is probably doing something dodgy
*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ENoActiveDeviceInArrayInRenegActConnToURoleAtPeersBehest));
	__ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray));

	LOG(_L("RoleState: <renegotiating active connection to U role at peers behest> - role changed failed - strange, the peer must have asked us to go to U role, but for some reason we decided we could, then it turned out we couldn't.  Sounds like remote device state machine is doing something dodgy"));

	// we couldn't go to U role (unlikely this can happen) so go back to GN/NAP state
	CPanAgtStateBase* nextState = CPanAgtStateGnOrNapRole::NewL(StateMachine());
	StateMachine().SetState(*nextState);
	delete this;
	return;
	}
	
void CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice)
/**

*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ENoActiveDeviceInArrayInRenegActConnToURoleAtPeersBehest));
	__ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray));

	LOG(_L("RoleState: <renegotiating active connection to U role at peers behest> - whoops, the remote device we're trying to upgrade has disconnected!"));
	DoDeviceDisconnectL(aDevice); // will leave if there are no other devices waiting and we're not accepting incoming connections

	// return to idle (possibly after reregistering local SDP record) - there can't be
	// any active devices left attached
	StartListenerL();

	CPanAgtStateBase* nextState = CPanAgtStateIdle::NewL(StateMachine());
	StateMachine().SetState(*nextState);
	delete this;
	return;
	}
	
//
// CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest
//
CPanAgtStateBase* CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::NewL(MPanAgtStateMachineNotify& aStateMachine)
	{
	CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest* self = new (ELeave) CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest(aStateMachine);
	CleanupStack::PushL(self);
	self->BaseConstructL();
	CleanupStack::Pop();
	return self;
	}
	
CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest(MPanAgtStateMachineNotify& aStateMachine) :
	CPanAgtStateBase(aStateMachine, EPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest)
/**

*/
	{	}

void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::OnEntryL()
/**

*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ENoActiveDevicesInArrayInRenegActConnToGnOrNapRoleAtPeersBehest));
	__ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray));

	LOG(_L("RoleState: <CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest> - entering state"));
	
	StateMachine().SendProgress(EPanAgtReconfiguringPiconet, KErrNone);
	
	// we've already had the role request from the remote device in the previous state, so just
	// wait for device active or role changed failed	
	}


void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::InitiateOutgoingConnectionL(TBluetoothPanRole& /*aLocalRole*/, TBluetoothPanRole& /*aRemoteRole*/, TPanDeviceWorthTryingRolesList& /*aWorthTryingRemoteRoles*/)
	{
	// Negotiation in progress - Wait...
	User::Leave(KErrLocked);
	}
	
void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::IncomingConnectionFromPeerL(TBluetoothPanRole /*aLocalRole*/)
	{
	// Negotiation in progress - Wait...
	User::Leave(KErrLocked);
	}

void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::DeviceActiveL(CPanRemoteDeviceStateMachine& /*aDevice*/)
/**

*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ENoActiveDevicesInArrayInRenegActConnToGnOrNapRoleAtPeersBehest));
	__ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray));

	LOG(_L("RoleState: <CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest> - device active received from negotitaing device"));	

	CPanAgtStateBase* nextState = CPanAgtStateGnOrNapRole::NewL(StateMachine());
	StateMachine().SetState(*nextState);
	delete this;
	return;
	}

void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::DeviceRoleChangeFailedL(CPanRemoteDeviceStateMachine& /*aDevice*/)
/**
Unlikey this can happen - if we get into this state we've decided we can do the role change.
If this gets called, the remote device state machine is probably doing something dodgy
*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ENoActiveDevicesInArrayInRenegActConnToGnOrNapRoleAtPeersBehest));
	__ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray));

	LOG(_L("RoleState: <CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest> - role changed failed - strange, the peer must have asked us to go to U role, but for some reason we decided we could, then it turned out we couldn't.  Sounds like remote device state machine is doing something dodgy"));

	// we couldn't go to GN/NAP role (unlikely this can happen) so go back to U role
	CPanAgtStateBase* nextState = CPanAgtStateURole::NewL(StateMachine());
	StateMachine().SetState(*nextState);
	delete this;
	return;
	}

void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice)
/**

*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(EActiveDevicesInArrayInRenegActConnToGnOrNapRoleAtOurBehest));
	__ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray));

	LOG(_L("RoleState: <CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest> - whoops, the remote device we're trying to upgrade has disconnected!"));
	DoDeviceDisconnectL(aDevice); // will leave if there are no other devices waiting and we're not accepting incoming connections

	StartListenerL();

	CPanAgtStateBase* nextState = CPanAgtStateIdle::NewL(StateMachine());
	StateMachine().SetState(*nextState);
	delete this;
	return;
	}

//
// CPanAgtStateNegotiatingGnOrNapRole
//
CPanAgtStateBase* CPanAgtStateNegotiatingGnOrNapRole::NewL(MPanAgtStateMachineNotify& aStateMachine)
	{
	CPanAgtStateNegotiatingGnOrNapRole* self = new (ELeave) CPanAgtStateNegotiatingGnOrNapRole(aStateMachine);
	CleanupStack::PushL(self);
	self->BaseConstructL();
	CleanupStack::Pop();
	return self;
	}
	
CPanAgtStateNegotiatingGnOrNapRole::CPanAgtStateNegotiatingGnOrNapRole(MPanAgtStateMachineNotify& aStateMachine) :
	CPanAgtStateBase(aStateMachine, EPanAgtStateNegotiatingGnOrNapRole)
/**

*/
	{	}

CPanAgtStateNegotiatingGnOrNapRole::CPanAgtStateNegotiatingGnOrNapRole(MPanAgtStateMachineNotify& aStateMachine, TPanAgtStates aStateNumber) :
	CPanAgtStateBase(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 CPanAgtStateNegotiatingGnOrNapRole::OnEntryL()
/**
@note Remote device object will make us piconet master
*/
	{
	LOG(_L("RoleState: <CPanAgtStateNegotiatingGnOrNapRole> - entering state"));

	if(StateMachine().AllowIncoming()) // stop advertising U service record
		{
		StateMachine().PanLocalSdpRegistrar().UnregisterLocalSdpRecord(EPanRoleU);
		}
	}

void CPanAgtStateNegotiatingGnOrNapRole::InitiateOutgoingConnectionL(TBluetoothPanRole& /*aLocalRole*/, TBluetoothPanRole& /*aRemoteRole*/, TPanDeviceWorthTryingRolesList& /*aWorthTryingRemoteRoles*/)
	{
	// Negotiation in progress - Wait...
	User::Leave(KErrLocked);
	}
	
void CPanAgtStateNegotiatingGnOrNapRole::IncomingConnectionFromPeerL(TBluetoothPanRole /*aLocalRole*/)
	{
	// Negotiation in progress - Wait...
	User::Leave(KErrLocked);
	}

	
void CPanAgtStateNegotiatingGnOrNapRole::DeviceActiveL(CPanRemoteDeviceStateMachine& aDevice)
/**
We've completed BNEP negotiation with the remote device successfully
*/
	{
	__ASSERT_ALWAYS(FindDeviceInArray(aDevice)>=0, PanicInState(EActiveDeviceThatIsNotInArray));
	__ASSERT_DEBUG(aDevice.GetState() == EActive, PanicInState(EDeviceNotActive));

	LOG(_L("RoleState: <CPanAgtStateNegotiatingGnOrNapRole> - device active received..."));

	CPanAgtStateBase* nextState = CPanAgtStateGnOrNapRole::NewL(StateMachine());		
	StateMachine().SetState(*nextState);
	delete this;
	}

void CPanAgtStateNegotiatingGnOrNapRole::DeviceRoleChangeFailedL(CPanRemoteDeviceStateMachine& /*aDevice*/)
/**
Looks like the remote device asked us to act in a role that we couldn't support
@note This can only be called as part of a role change, not during initial negotiation with a device
*/
	{
	__ASSERT_DEBUG(NegotiatingDeviceCount()==1, PanicInState(EMoreThanOneDeviceInNegotiatingModeInArray));

	LOG(_L("RoleState: <CPanAgtStateNegotiatingGnOrNapRole> - role changed failed - this *might* be triggered by an incoming connection from a remote device asking us to be PAN-U, and we can't because we've got other attached devices"));

	CPanAgtStateBase* nextState = NULL;
	nextState = CPanAgtStateGnOrNapRole::NewL(StateMachine());		
	
	__ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));
	StateMachine().SetState(*nextState);
	delete this;
	}
	
void CPanAgtStateNegotiatingGnOrNapRole::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice)
/**

*/
	{

	//This function will only be called when device is in EDisconnecting State.
	//Remote device state machine will first shutdown itself and then call panagent to
	//disconnect this device and remove it from the device array
	__ASSERT_DEBUG(aDevice.GetState() == EDisconnecting, PanicInState(EInvalidRemoteDeviceState));

	LOG(_L("RoleState: <CPanAgtStateNegotiatingGnOrNapRole> - oops, the remote device we're negotiating with has disconnected"));
	// outstanding async request will be cancelled by state machine when we leave
	DoDeviceDisconnectL(aDevice); // will leave if there are no more devices connected and we're not accepting incoming connections

	CPanAgtStateBase* nextState = NULL;
	if(ActiveDeviceCount()>=1)
		{
		nextState = CPanAgtStateGnOrNapRole::NewL(StateMachine());
		}
	else
		{
	    StartListenerL();
		nextState = CPanAgtStateIdle::NewL(StateMachine()); // will trigger negotiation with idle device
		}
	__ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));		
	StateMachine().SetState(*nextState);
	delete this;
	return;
	
	}

	
//
// CPanAgtStateGnOrNapRole
//
CPanAgtStateBase* CPanAgtStateGnOrNapRole::NewL(MPanAgtStateMachineNotify& aStateMachine)
	{
	CPanAgtStateGnOrNapRole* self = new (ELeave) CPanAgtStateGnOrNapRole(aStateMachine);
	CleanupStack::PushL(self);
	self->BaseConstructL();
	CleanupStack::Pop();
	return self;
	}
	
CPanAgtStateGnOrNapRole::CPanAgtStateGnOrNapRole(MPanAgtStateMachineNotify& aStateMachine) :
	CPanAgtStateBase(aStateMachine, EPanAgtStateGnOrNapRole)
/**

*/
	{	}

void CPanAgtStateGnOrNapRole::OnEntryL()	
/**

*/
	{
	__ASSERT_DEBUG(ActiveDeviceCount()>=1, PanicInState(ENoActiveDeviceAfterNegotiationCompleted));
	__ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EDeviceInNegotiatingModeOnEntryToGnOrNapState));

	LOG1(_L("RoleState: <CPanAgtStateGnOrNapRole> - entering state, %d active devices"), ActiveDeviceCount());

	if(StateMachine().NapEnabled())
		{
		StateMachine().SendProgress(EPanAgtNapRole, KErrNone);
		}
	else
		{
		StateMachine().SendProgress(EPanAgtGnRole, KErrNone);
		}
		
	LockDeviceAsPiconetMasterL(); // apply piconet master lock each time we enter this state, to ensure all devices have this set

	// scan the array to see if there are any devices awaiting negotiation, if so, trigger negotiation with one of them
	StartNegotiationWithFirstPendingDevice();
	}
	
void CPanAgtStateGnOrNapRole::IncomingConnectionFromPeerL(TBluetoothPanRole aLocalRole)
	{
	if(StateMachine().NapEnabled())
		{
		if(aLocalRole != EPanRoleNap)
			{
			User::Leave(KErrInvalidOrUnacceptableRoleCombination);
			}
		}
	else
		{
		if(aLocalRole != EPanRoleGn)
			{
			User::Leave(KErrInvalidOrUnacceptableRoleCombination);
			}
		}
	}
	
void CPanAgtStateGnOrNapRole::RoleChangeRequestFromPeerL(TBluetoothPanRole aLocalRole)
	{
	if(aLocalRole == EPanRoleU)
		{
		// Check if we can change role.  There must be at least one connection.  Any more than
		// one and we can't change to U role.
		if(ActiveDeviceCount() == 1)
			{
			LOG(_L("RoleState: <CPanAgtStateGnOrNapRole> - ...remote device wants us to be U, accepting"));

			CPanAgtStateBase* nextState = CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::NewL(StateMachine());
			StateMachine().SetState(*nextState);
			delete this;
			}
		else
			{
			// Can't change local role.
			User::Leave(KErrInvalidOrUnacceptableRoleCombination);
			}
		}
	else
		{
		// The local role must be the same as our local role.
		// Nothing to do.  Accept request and wait for DeviceActive call.
		CPanAgtStateBase* nextState = CPanAgtStateNegotiatingGnOrNapRole::NewL(StateMachine());
		StateMachine().SetState(*nextState);
		delete this;
		}
	}
	
void CPanAgtStateGnOrNapRole::InitiateOutgoingConnectionL(TBluetoothPanRole& aLocalRole, TBluetoothPanRole& aRemoteRole, TPanDeviceWorthTryingRolesList& aWorthTryingRemoteRoles)
	{
	LOG(_L("RoleState: <CPanAgtStateGnOrNapRole> - InitiateOutgoingConnectionL"));

	// There must already be an existing connection (in GN/NAP role).  Set the local role to GN/NAP and the
	// remote to U
	aLocalRole = StateMachine().NapEnabled() ? EPanRoleNap : EPanRoleGn;
	
	// Check the a connection U role is worth trying
	if(aWorthTryingRemoteRoles.IsWorthTryingU())
		{
		aRemoteRole = EPanRoleU;
		}
	else
		{
		User::Leave(KErrInvalidOrUnacceptableRoleCombination);
		}
		
	CPanAgtStateBase* nextState = CPanAgtStateNegotiatingGnOrNapRole::NewL(StateMachine());
	StateMachine().SetState(*nextState);
	delete this;
	}

void CPanAgtStateGnOrNapRole::DeviceActiveL(CPanRemoteDeviceStateMachine& /*aDevice*/)
/**

*/
	{
	// A new device has been added to the bridge.
	}
	
void CPanAgtStateGnOrNapRole::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice)
/**

*/
	{
	LOG(_L("RoleState: <CPanAgtStateGnOrNapRole> - device disconnected..."));

	DoDeviceDisconnectL(aDevice); // if there are no devices in the array and we're not supporting incoming connection this method will leave
	
	if(StateMachine().Devices().Count())
		{
		LOG1(_L("RoleState: <CPanAgtStateGnOrNapRole> - ...%d device(s) remaining - staying in GN role"), StateMachine().Devices().Count());
		// do nothing - need to remain in GN/NAP role
		}
	else	// no devices left - decide what to do next...
		{
		LOG(_L("RoleState: <CPanAgtStateGnOrNapRole> - ...no devices remaining - choosing next role..."));
		CPanAgtStateBase* nextState = NULL;
		StartListenerL();

		LOG(_L("RoleState: <CPanAgtStateGnOrNapRole> - ...incoming connections not being accepted, going to idle state"));
		nextState = CPanAgtStateIdle::NewL(StateMachine());

		__ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet));
		StateMachine().SetState(*nextState);
		delete this;
		return;
		}
	}

void CPanAgtStateGnOrNapRole::StateSendRoleNotification()
	{
	if(StateMachine().NapEnabled())
		{
		StateMachine().SendProgress(EPanAgtNapRole, KErrNone);
		}
	else
		{
		StateMachine().SendProgress(EPanAgtGnRole, KErrNone);
		}
	}
	
//
// CPanAgtStateShutdown
//
CPanAgtStateBase* CPanAgtStateShutdown::NewL(MPanAgtStateMachineNotify& aStateMachine)
	{
	CPanAgtStateShutdown* self = new (ELeave) CPanAgtStateShutdown(aStateMachine);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop();
	return self;
	}
	
CPanAgtStateShutdown::CPanAgtStateShutdown(MPanAgtStateMachineNotify& aStateMachine) :
	CPanAgtStateBase(aStateMachine, EPanAgtStateShutdown)
/**

*/
	{	}

CPanAgtStateShutdown::~CPanAgtStateShutdown()
	{
	iShutdownCallback->Cancel();
	delete iShutdownCallback;
	}
void CPanAgtStateShutdown::ConstructL()
	{
	BaseConstructL();
	iShutdownCallback = new (ELeave) CAsyncCallBack(KPanAgtAoPriority);
	TCallBack callbackFunc(ShutdownCallback, this);
	iShutdownCallback->Set(callbackFunc);
	}

TInt CPanAgtStateShutdown::ShutdownCallback(TAny* aThisPtr)
/**
Callback function to do a full shutdown of the Pan Agent
*/
	{
	LOG(_L("RoleState: <shutdown> - shutting down"));

	CPanAgtStateShutdown* self = (CPanAgtStateShutdown*)aThisPtr;
	self->StateMachine().FullShutdownComplete();
	return KErrNone;
	}
	
void CPanAgtStateShutdown::OnEntryL()	
/**
Shut all the connections down
*/
	{
	LOG(_L("RoleState: <shutdown> - entering state"));

	// Start closing things down, and notify apps that we're shutting down
	StateMachine().CloseIncomingConnectionListener();
	StateMachine().SendProgress(EPanAgtDisconnecting, KErrNone);

	// Start disconnecting any attached devices...
	RPointerArray<CPanRemoteDeviceStateMachine>& deviceArray = StateMachine().Devices();
	if(deviceArray.Count()==0)	// ...no devices attached, shutdown straight away
		{
		LOG(_L("RoleState: <shutdown> - no devices connected, use callback to shutdown"));
		
		// Use a Callback function here to allow the connection to process any progress
		// before the shutdown is completed.
		// This is important if a connection is being created from an IAP entry and
		// the connection fails, without allowing the connection to process the progress
		// RConnection::Start will never return.
		iShutdownCallback->CallBack();		
		return;
		}
	else	// ...tell all the attached devices to shut down
		{
		for(TInt i=0; i < deviceArray.Count(); ++i)
			{
			deviceArray[i]->Disconnect();
			}
		}
	}
	
void CPanAgtStateShutdown::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice)
/**
Remote device has disconnected
@note *** Must not leave from here ***
*/
	{
	TRAPD(err, DoDeviceDisconnectL(aDevice));
	if(err==KErrAllDevicesDisconnected)	// all devices have disconnected, so we can shutdown now
		{
		LOG(_L("RoleState: <shutdown> - all devices disconnected, shutting down"));
		StateMachine().FullShutdownComplete();
		}
	else if(err)
		{
		LOG1(_L("RoleState: <shutdown> - unknown error %d, shutting down"), err);
		StateMachine().FullShutdownComplete();
		}
	else if(StateMachine().Devices().Count()==0)
		{
		LOG(_L("RoleState: <shutdown> - all devices disconnected but incoming connection listener active, stopping it and shutting down"));
		StateMachine().FullShutdownComplete();
		}
	}

//
// CPanAgtStateReconnect
//
CPanAgtStateBase* CPanAgtStateReconnect::NewL(MPanAgtStateMachineNotify& aStateMachine)
	{
	CPanAgtStateReconnect* self = new (ELeave) CPanAgtStateReconnect(aStateMachine);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop();
	return self;
	}
	
CPanAgtStateReconnect::CPanAgtStateReconnect(MPanAgtStateMachineNotify& aStateMachine) :
	CPanAgtStateBase(aStateMachine, EPanAgtStateReconnect)
/**

*/
	{	}

CPanAgtStateReconnect::~CPanAgtStateReconnect()
	{
	iReconnectCompleteCallback->Cancel();
	delete iReconnectCompleteCallback;
	}

void CPanAgtStateReconnect::ConstructL()
	{
	BaseConstructL();
	iReconnectCompleteCallback = new (ELeave) CAsyncCallBack(KPanAgtAoPriority);	
	TCallBack reconnectCompleteCallback(ReconnectCompleteCb, this);
	iReconnectCompleteCallback->Set(reconnectCompleteCallback);
	TCallBack serviceStartedCallback(ServiceStartedCb, this);
	iServiceStartedCallback->Set(serviceStartedCallback);
	}

void CPanAgtStateReconnect::OnEntryL()	
	{
	LOG(_L("RoleState: <reconnect> - entering state"));

	StateMachine().CloseIncomingConnectionListener();

	// Start disconnecting any attached devices...
	RPointerArray<CPanRemoteDeviceStateMachine>& deviceArray = StateMachine().Devices();
	if(deviceArray.Count()!=0)	// ...no devices attached, shutdown straight away
		{
		for(TInt i=0; i < deviceArray.Count(); ++i)
			{
			deviceArray[i]->Disconnect();
			}
		}
	iReconnectCompleteCallback->CallBack();
	}

void CPanAgtStateReconnect::Connect()
	{
	iServiceStartedCallback->CallBack();
	}

void CPanAgtStateReconnect::CancelReconnect()
	{
	iReconnectCompleteCallback->Cancel();
	}

void CPanAgtStateReconnect::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice)
/**
Remote device has disconnected
*/
	{
	DoDeviceDisconnectL(aDevice);
	}

void CPanAgtStateReconnect::ServiceStarted()
/**
@note Don't notify Nifman with ServiceStarted() because that will try to load the packet driver
again which will cause a panic.
*/
	{
	LOG(_L("CPanAgtStateBase: Service started"));

	StateMachine().SendProgress(EPanAgtInitialising, KErrNone);
	iConnectCompleteCallback->CallBack();
	}

TInt CPanAgtStateReconnect::ServiceStartedCb(TAny* aThisPtr)
/**
Connection callback function 
*/
	{
	__ASSERT_DEBUG(aThisPtr, PanAgentPanic(ENullTAnyPointer));

	CPanAgtStateReconnect* self = static_cast<CPanAgtStateReconnect*>(aThisPtr);
	self->ServiceStarted();
	return KErrNone;
	}
	
TInt CPanAgtStateReconnect::ReconnectCompleteCb(TAny* aThisPtr)
/**
Reconnect callback function
*/
	{
	__ASSERT_DEBUG(aThisPtr, PanAgentPanic(ENullTAnyPointer));

	CPanAgtStateReconnect* self = static_cast<CPanAgtStateReconnect*>(aThisPtr);
	self->StateMachine().ReconnectComplete(KErrNone);
	return KErrNone;
	}


#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
CPanAgtStatePaused* CPanAgtStatePaused::NewL(MPanAgtStateMachineNotify& aStateMachine, CPanAgtStateBase& aNextState)
    {
    CPanAgtStatePaused* self = new(ELeave) CPanAgtStatePaused(aStateMachine, aNextState);
    CleanupStack::PushL(self);
	self->BaseConstructL();
    CleanupStack::Pop();
    return self;
    }

CPanAgtStatePaused::CPanAgtStatePaused(MPanAgtStateMachineNotify& aStateMachine, CPanAgtStateBase& aNextState)
    : CPanAgtStateBase(aStateMachine, EPanAgtStatePaused), iNextState(&aNextState)
    {
    }
    
CPanAgtStatePaused::~CPanAgtStatePaused()
    {
    delete iNextState;
    }

void CPanAgtStatePaused::OnEntryL()
    {
    // Does nothing
    }
    
void CPanAgtStatePaused::TransitionToNextState()
    {
    StateMachine().SetState(*iNextState);
    
    // We no longer own the next state
    iNextState = NULL;
    delete this;
    }
    
#endif
// SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY