bluetooth/btstack/linkmgr/linkmgr.cpp
changeset 0 29b1cd4cb562
child 13 20fda83a6398
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/linkmgr/linkmgr.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1560 @@
+// Copyright (c) 1999-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:
+// This implements the CLinkMgrProtocol object that is the contact point from
+// BT PRT to the LinkMgr stack
+// At present this class also remembers the configuration of the controller
+// -- no particular reason - could be encapsulated in a class that the facade
+// knows about.
+// 
+//
+
+#include <bt_sock.h>
+#include <bluetooth/logger.h>
+#include "debug.h"
+#include <utf.h>
+#include <bluetooth/hci/hciframe.h>
+#include <bluetooth/aclsockaddr.h>
+
+#include "linkmgr.h"
+#include "hcifacade.h"
+#include "bt.h"
+#include "hostresolver.h"
+#include "linkmuxer.h"
+#include "physicallinksmanager.h"
+#include "linkconsts.h"
+#include "eirmanserver.h"
+#include "eirmanager.h"
+#include "eirpublisherlocalname.h"
+#include "eirpublishertxpowerlevel.h"
+
+
+#include "ProxySAP.h"
+#include "SCOSAP.h"
+#include "ACLSAP.h"
+#include "VendorSAP.h"
+#include "vendorspecific.h"
+
+#include "Subscribers.h"
+#include "BTSec.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_LINKMGR);
+#endif
+
+#ifdef _DEBUG
+PANICCATEGORY("linkmgr");
+#endif
+
+const TInt KLengthOfDeviceClass = 11;			// 11 bits in the device class portion of the CoD
+const TInt KStartingOffsetOfDeviceClass = 2;	// 2 LSB bits for format type
+const TUint32 KDeviceClassReset = 0;			// used to reset persistent data
+
+// Constant which can be ANDed with a complete CoD bitmask to extract the device class portion.
+const TInt KDeviceClassBitMask = ((1 << KLengthOfDeviceClass) - 1) << KStartingOffsetOfDeviceClass;
+
+
+enum TLinkMgrPanic
+	{
+	ELinkMgrProtocolOpenedAfterClose,
+	ELinkMgrProtocolBadAFHHostChannelClassification,
+	EUnknownFatalError,
+	ELocalDeviceBadHandle,
+	ERegistrySessionClosedTooManyTimes,
+	ERegistrySessionDeletedWhenOpen,
+	};
+
+void Panic(TLinkMgrPanic aPanic)
+// Panic L2CAP due to stack bug.
+	{
+	LOG_STATIC_FUNC
+	_LIT(KL2CAPPanicName, "BTLinkMgr");
+	User::Panic(KL2CAPPanicName, aPanic);
+	}
+
+// Construction & Initialisation
+
+CLinkMgrProtocol::CLinkMgrProtocol(CBTSecMan& aSecMan, RBTControlPlane& aControlPlane, CBTCodServiceMan& aCodMan)
+: CBluetoothProtocolBase(aSecMan, aControlPlane, aCodMan)
+, iDebugModeDefinitionResult(KErrGeneral)
+	{
+	LOG_FUNC
+	TCallBack cb(TryToClose, this);
+	iIdleTimerEntry.Set(cb);
+	}
+
+CLinkMgrProtocol::~CLinkMgrProtocol()
+/**
+	Delete all our stuff
+**/
+   
+	{
+	LOG_FUNC
+	RemoveIdleTimerEntry();
+	
+	// Delete setter P&S values
+	iProperty.Delete(KPropertyUidBluetoothCategory,	KPropertyKeyBluetoothSetScanningStatus);
+	iProperty.Delete(KPropertyUidBluetoothCategory,	KPropertyKeyBluetoothSetLimitedDiscoverableStatus);
+	iProperty.Delete(KPropertyUidBluetoothCategory,	KPropertyKeyBluetoothSetDeviceClass);
+	iProperty.Delete(KPropertyUidBluetoothCategory,	KPropertyKeyBluetoothSetAFHHostChannelClassification);
+	iProperty.Delete(KPropertyUidBluetoothCategory,	KPropertyKeyBluetoothSetAFHChannelAssessmentMode);
+	iProperty.Delete(KPropertyUidBluetoothCategory,	KPropertyKeyBluetoothSetDeviceName);
+	iProperty.Delete(KPropertyUidBluetoothCategory,	KPropertyKeyBluetoothSetAcceptPairedOnlyMode);
+
+	// Delete standard P&S values (possibly trying to delete already deleted shared set+get values)
+	iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothGetLocalDeviceAddress);
+	iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothGetPHYCount);
+	iProperty.Delete(KPropertyUidBluetoothCategory,	KPropertyKeyBluetoothGetConnectingStatus);
+	iProperty.Delete(KPropertyUidBluetoothCategory,	KPropertyKeyBluetoothGetScanningStatus);
+	iProperty.Delete(KPropertyUidBluetoothCategory,	KPropertyKeyBluetoothGetLimitedDiscoverableStatus);
+	iProperty.Delete(KPropertyUidBluetoothCategory,	KPropertyKeyBluetoothGetDeviceClass);
+	iProperty.Delete(KPropertyUidBluetoothCategory,	KPropertyKeyBluetoothGetDeviceName);
+	iProperty.Delete(KPropertyUidBluetoothCategory,	KPropertyKeyBluetoothGetAcceptPairedOnlyMode);
+	iProperty.Delete(KPropertyUidBluetoothCategory,	KPropertyKeyBluetoothHostResolverActive);
+	iProperty.Delete(KPropertyUidBluetoothCategory,	KPropertyKeyBluetoothSetSimplePairingDebugMode);
+
+	delete iPhysicalLinksMgr;
+	delete iInquiryMgr;
+	delete iEirManServer;
+	delete iACLStateFactory;
+	delete iSCOStateFactory;
+
+	SecMan().ClearHCICommandQueue(); // clears up the commands
+	SecMan().ClearLinksMgrProtocol();
+	SecMan().ClearPhysicalLinksMgr();
+	
+	delete iLinkMuxer;
+	delete iHCIFacade;
+	
+	delete iRegistryUpdater;
+
+	DeletePublications();
+	iSubscribers.ResetAndDestroy();
+
+	iLocalDevice.Close();
+	delete iRegSess;
+	}
+
+CLinkMgrProtocol* CLinkMgrProtocol::NewL(CBTSecMan& aSecMan, RBTControlPlane& aControlPlane, CBTCodServiceMan& aCodMan)
+	{
+	LOG_STATIC_FUNC
+	CLinkMgrProtocol* i=new (ELeave) CLinkMgrProtocol(aSecMan, aControlPlane, aCodMan);
+	return i;
+	}
+
+void CLinkMgrProtocol::InitL(TDesC& /*aTag*/)
+/**
+	Pre-binding initialise.
+	Allocate any objects we need here.
+	ESOCK ensures that this function will only be called once per
+	object of this class, regardless of how long it hangs around.
+**/
+	{
+	LOG_FUNC
+
+	__ASSERT_DEBUG(!iClosePending, Panic(ELinkMgrProtocolOpenedAfterClose));
+	__ASSERT_DEBUG(!iIdleEntryQueued, Panic(ELinkMgrProtocolOpenedAfterClose));
+	__ASSERT_DEBUG(!iHCIFacade, Panic(ELinkMgrProtocolOpenedAfterClose));
+
+	// Get the local device settings from persistent store
+	// By keeping a session open for the lifetime of this protocol
+	// we prevent RegServ being created during connection time.
+	LOG(_L("LinkMgr : Initialising RegistryServer"));
+	iRegSess = CRegistrySession::NewL(*this);
+	TInt err = iLocalDevice.Open(iRegSess->RegServ());
+	
+	if (err ==KErrNone)
+		{
+		// read local device settings (e.g page scan\inquiry scan) from registry
+		err = iLocalDevice.Get(iLocalDeviceSettings);	// ignore error - can continue
+		__ASSERT_DEBUG(err==KErrNone, Panic(EUnknownFatalError));		
+		
+		
+		//
+		// Mask off the service class bits from the CoD -- we're not interested in the
+		// registry's values for anything other than the device class part.
+		// There's a nice terminology overload here, as the 'Class of Device' contains
+		// both a device class and a service class.  It might have been nice if the
+		// getter and setter methods were 'ClassOfDevice', but even that wouldn't help
+		// much...
+		//
+		iLocalDeviceSettings.SetDeviceClass(iLocalDeviceSettings.DeviceClass() & KDeviceClassBitMask);
+		
+		
+		//NB - no (ELeave) here - in OOM we'd rather continue and not update the registry
+		//than Leave.  All calls to methods are guarded by "if (iRegistryUpdater)"
+		iRegistryUpdater = new CRegistryUpdater(iLocalDevice, iLocalDeviceSettings);
+		}
+
+	LOG(_L("LinkMgr : Creating HCIFacade (and HCI)"));
+	iHCIFacade = CHCIFacade::NewL(*this); 	// Create HCI/HCIFacade first
+	iPhysicalLinksMgr = CPhysicalLinksManager::NewL(*this, *iHCIFacade, *iRegSess, SecMan(), CodMan());
+	iPhysicalLinksMgr->SetAcceptPairedOnlyMode(iLocalDeviceSettings.AcceptPairedOnlyMode()); // Tell the physical links manager the persisted value for the accept paired only mode
+	iHCIFacade->SetPhysicalLinksMgr(*iPhysicalLinksMgr); 	// Tell HCIFacade of ConnMgr
+
+	SecMan().SetPhysicalLinksMgr(*iPhysicalLinksMgr);
+	SecMan().SetLinksMgrProtocol(*this);
+	SecMan().SetHCICommandQueue(iHCIFacade->CommandQController());
+
+	LOG(_L("LinkMgr : Initialising Link Muxer"));
+	iLinkMuxer=CLinkMuxer::NewL(*this, *iHCIFacade);
+	iHCIFacade->SetLinkMuxer(*iLinkMuxer);
+
+	iACLStateFactory = CACLLinkStateFactory::NewL();
+	iSCOStateFactory = CSyncLinkStateFactory::NewL();
+				
+	LOG(_L("LinkMgr : Initialising EirManServer"));
+	iEirManServer = CEirManServer::NewL(iHCIFacade->CommandQController(), *this);
+
+	LOG(_L("LinkMgr : Initialising InquiryMgr"));
+	iInquiryMgr = CBTInquiryMgr::NewL(*this);
+	iInquiryMgr->SetHCICommandQueue(iHCIFacade->CommandQController());
+
+
+	LOG(_L("LinkMgr : Configuring HCIFacade)"));
+	iHCIFacade->InitL(iLocalDeviceSettings);// passes ownership of device
+	
+	// Inquiry and page scan is read from BT Registry and set it to P&S
+	// As there is no listening socket, they are set to OFF on HW yet!
+	// P&S value is taken to account as soon we open the first listening socket!
+	DefinePublications(iLocalDeviceSettings.ScanEnable());
+	
+	// set up subscribers
+	CSubscriber* subscriber;
+	
+	subscriber = CDiscoverabilitySubscriber::NewL(*this);
+	CleanupStack::PushL(subscriber);
+	User::LeaveIfError(iSubscribers.Append(subscriber));
+	CleanupStack::Pop(subscriber);
+
+	subscriber = CLimitedSubscriber::NewL(*this);
+	CleanupStack::PushL(subscriber);
+	User::LeaveIfError(iSubscribers.Append(subscriber));
+	CleanupStack::Pop(subscriber);
+
+	subscriber = CDeviceClassSubscriber::NewL(*this);
+	CleanupStack::PushL(subscriber);
+	User::LeaveIfError(iSubscribers.Append(subscriber));
+	CleanupStack::Pop(subscriber);
+	
+	subscriber = CAFHHostChannelClassificationSubscriber::NewL(*this);
+	CleanupStack::PushL(subscriber);
+	User::LeaveIfError(iSubscribers.Append(subscriber));
+	CleanupStack::Pop(subscriber);
+	
+	subscriber = CDeviceNameSubscriber::NewL(*this);
+	CleanupStack::PushL(subscriber);
+	User::LeaveIfError(iSubscribers.Append(subscriber));
+	CleanupStack::Pop(subscriber);
+
+	subscriber = CRegistryRemoteTableSubscriber::NewL(*this);
+	CleanupStack::PushL(subscriber);
+	User::LeaveIfError(iSubscribers.Append(subscriber));
+	CleanupStack::Pop(subscriber);
+	
+	subscriber = CAcceptPairedOnlySubscriber::NewL(*this);
+	CleanupStack::PushL(subscriber);
+	User::LeaveIfError(iSubscribers.Append(subscriber));
+	CleanupStack::Pop(subscriber);
+	
+	subscriber = CAFHChannelAssessmentModeSubscriber::NewL(*this);
+	CleanupStack::PushL(subscriber);
+	User::LeaveIfError(iSubscribers.Append(subscriber));
+	CleanupStack::Pop(subscriber);
+	
+	if(iDebugModeDefinitionResult == KErrNone)
+		{
+		// Only subscribe on debug mode if we have managed to successfully define
+		// the key ourselves (this is because it needs to be protected with the very 
+		// strong CommDD capability).
+		subscriber = CDebugModeSubscriber::NewL(*this);
+		CleanupStack::PushL(subscriber);
+		User::LeaveIfError(iSubscribers.Append(subscriber));
+		CleanupStack::Pop(subscriber);
+		}
+
+	// set CoD - leave if goes wrong, user's device will be "unknown" otherwise
+	// NB - In future we should tie this to the SDP Server...(or someother higher API...)
+	
+	if (iLocalDeviceSettings.DeviceClass() && iLocalDeviceSettings.IsValidDeviceClass())
+	// Some phones never set their CoD in s/w, we don't want to blat
+	// over their h/w settings
+		{
+		iPendingLocalDeviceSettings.SetDeviceClass(iLocalDeviceSettings.DeviceClass()); //we expect this after power on
+		}
+
+	CodMan().Initialise();	// Cod Service Manager can now get a valid CoD
+
+	if(iLocalDeviceSettings.AFHChannelAssessmentMode() == EFalse)
+	// If this feature is supported it will start off switched on
+		{
+		SetAFHChannelAssessmentModeL(iLocalDeviceSettings.AFHChannelAssessmentMode());
+		}
+
+	//Attempt to make sure that controller has the same value as the registry
+	//and that the P&S key 'KPropertyKeyBluetoothGetLimitedDiscoverableStatus'
+	//is, as a consequence, 'Set' appropriately (when the associated controller 
+	//event arrives).
+	DoSetLimitedDiscoverableL(iLocalDeviceSettings.LimitedDiscoverable());
+	
+	LOG(_L("LinkMgr : Initialising complete"));
+	}
+
+void CLinkMgrProtocol::DefinePublications(THCIScanEnable aHCIScanEnable)
+	{
+	LOG_FUNC
+	
+	// 6 properties for setting.
+	// Its possible that these are re-defined below, but we are discarding any KErrAlreadyExists.
+	// As the setters require more capabilities we ensure that they get defined first.
+
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothSetScanningStatus,
+							RProperty::EInt,
+							KLOCAL_SERVICES_AND_NETWORK_CONTROL,
+							KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+	
+	// Even if we initialise KPropertyKeyBluetoothSetScanningStatus to Inquiry & 
+	// Page scanning enabled, it's not turned on at this point. Only when first
+	// listening socket is opened, this value will control the inquiry scan & page scan
+
+	(void)(iProperty.Set(KPropertyUidBluetoothCategory,
+						 KPropertyKeyBluetoothSetScanningStatus,
+						 aHCIScanEnable));
+						 
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothSetLimitedDiscoverableStatus,
+							RProperty::EInt,
+							KLOCAL_SERVICES_AND_NETWORK_CONTROL,
+							KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothSetDeviceClass,
+							RProperty::EInt,
+							KLOCAL_SERVICES_AND_NETWORK_CONTROL,
+							KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothSetAFHHostChannelClassification,
+							RProperty::EByteArray,
+							KLOCAL_SERVICES_AND_NETWORK_CONTROL,
+							KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothSetAFHChannelAssessmentMode,
+							RProperty::EInt,
+							KLOCAL_SERVICES_AND_NETWORK_CONTROL,
+							KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothSetDeviceName,
+							RProperty::EText,
+							KLOCAL_SERVICES_AND_NETWORK_CONTROL,
+							KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothSetAcceptPairedOnlyMode,
+							RProperty::EInt,
+							KLOCAL_SERVICES_AND_NETWORK_CONTROL,
+							KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+	
+	iDebugModeDefinitionResult = (iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothSetSimplePairingDebugMode,
+							RProperty::EInt,
+							KLOCAL_SERVICES,
+							KCOMMDD
+							));
+
+
+	// Original Get P&S value definitions.
+
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothGetLocalDeviceAddress,
+							RProperty::EByteArray,
+							KLOCAL_SERVICES,
+						   	KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothGetPHYCount,
+							RProperty::EInt,
+							KLOCAL_SERVICES,
+						   	KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothGetConnectingStatus,
+							RProperty::EInt,
+							KLOCAL_SERVICES,
+						   	KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothGetScanningStatus,
+							RProperty::EInt,
+							KLOCAL_SERVICES,
+						   	KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothGetLimitedDiscoverableStatus,
+							RProperty::EInt,
+							KLOCAL_SERVICES,
+						   	KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothGetDeviceClass,
+							RProperty::EInt,
+							KLOCAL_SERVICES,
+						   	KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothGetDeviceName,
+							RProperty::EText,
+							KLOCAL_SERVICES,
+						   	KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+							
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothGetAcceptPairedOnlyMode,
+							RProperty::EInt,
+							KLOCAL_SERVICES,
+						   	KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+							
+ 	(void) (iProperty.Define(KPropertyUidBluetoothCategory,
+ 							KPropertyKeyBluetoothHostResolverActive,
+ 							RProperty::EInt,
+ 							KLOCAL_SERVICES,
+ 						   	KLOCAL_SERVICES_AND_NETWORK_CONTROL
+ 							));
+ 	
+	(void)(iProperty.Define(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothGetSimplePairingDebugMode,
+							RProperty::EInt,
+							KLOCAL_SERVICES,
+						   	KLOCAL_SERVICES_AND_NETWORK_CONTROL
+							));
+	}
+
+void CLinkMgrProtocol::DeletePublications()
+	{
+	LOG_FUNC
+	//we own them, so they'll get deleted
+	iProperty.Close();
+	}
+
+void CLinkMgrProtocol::StartL()
+/**
+	Binding complete.
+	Startup call from esock.  Do nothing
+	If HCI needs any start-up, do it here.
+**/
+	{
+	LOG_FUNC
+	}
+
+// From higher protocol
+void CLinkMgrProtocol::BindL(CProtocolBase* protocol, TUint /* id*/)
+	{
+	LOG_FUNC
+	TServerProtocolDesc prtDesc;
+	protocol->Identify(&prtDesc);
+
+#ifdef TCI
+	if(prtDesc.iAddrFamily!=KBTAddrFamily || prtDesc.iProtocol!=KTCIL2CAP)
+#else
+	if(prtDesc.iAddrFamily!=KBTAddrFamily || prtDesc.iProtocol!=KL2CAP)
+#endif
+		{
+		User::Leave(KErrBtEskError);
+		}
+	// Store this for error propogation
+	//
+	iUpperProtocol = protocol;
+	}
+
+// Factory functions
+
+CHostResolvProvdBase* CLinkMgrProtocol::NewHostResolverL()
+	{
+	LOG_FUNC
+	return iInquiryMgr->NewHostResolverL();
+	}
+
+// Query functions
+
+void CLinkMgrProtocol::Identify(TServerProtocolDesc* aDesc) const
+//
+// Identify request from SOCKET server
+//
+	{
+	LOG_FUNC
+	CLinkMgrProtocol::ProtocolIdentity(aDesc);
+	}
+
+void CLinkMgrProtocol::ProtocolIdentity(TServerProtocolDesc* aDesc)
+	{
+	LOG_STATIC_FUNC
+	_LIT(name,"BTLinkManager");
+	aDesc->iProtocol=KBTLinkManager;
+
+	aDesc->iName=name;
+	aDesc->iAddrFamily=KBTAddrFamily;
+	aDesc->iSockType=KUndefinedSockType;	// various!
+	
+	aDesc->iVersion=TVersion(KBTMajor,KBTMinor,KBTBuild);
+	aDesc->iByteOrder=ELittleEndian;
+
+/*
+	The following sockets are exposed as RSockets
+
+	'Proxy' = a SAP attached to a baseband connection that can influence it
+	'SCO'	= a SAP providing SCO services
+
+	Higher protocols can additionally ask for ACL SAPs, but these are not 
+	available as RSockets
+
+	This guides the direction of the ServiceInfo below
+
+*/
+
+	aDesc->iServiceInfo=KSIDatagram|KSIGracefulClose|KSIBroadcast|KSIQOS|KSICanReconnect|KSIConnectData|KSIDisconnectData; // slightly hijacked connectData
+	aDesc->iNamingServices=KNSNameResolution;
+	aDesc->iSecurity=KSocketNoSecurity;
+	aDesc->iMessageSize=Max(CHctlSynchronousDataFrame::KHCTLMaxSynchronousDataSize, CHctlAclDataFrame::KHCTLMaxACLDataSize);
+	aDesc->iServiceTypeInfo=ESocketSupport|ECantProcessMBufChains|ENeedMBufs|ETransport
+							|EPreferDescriptors|EUseCanSend;
+	aDesc->iNumSockets=100;	// one per baseband - including many parked!
+	}
+
+void CLinkMgrProtocol::Error(TInt aErr, CProtocolBase* /*aProt*/)
+	{
+	LOG_FUNC
+	// A fatal error has occurred (Power off hopefully!). Notify the upper protocol
+	// (of there is one) and the inquiry manager. 
+	__ASSERT_DEBUG(aErr==KErrHardwareNotAvailable, Panic(EUnknownFatalError));
+	iInquiryMgr->CompleteCommands(aErr);
+	iPhysicalLinksMgr->FatalError(aErr);
+	}
+
+void CLinkMgrProtocol::CloseNow()
+/**
+	Close command from base class.
+	Called when ref count reaches 0.
+	We don't actually have to close now, but when we finally
+	do, we must call CanClose (done within TryToClose). That'll
+	actually delete us. In the mean time, if a new client tries
+	to connect to LinkMgr, ESOCK will use this existing one and just
+	call Open on it.
+	What we do here, is queue an idle timer entry. It's expiry will
+	call TryToClose, which'll actually do the close.
+**/
+	{
+	LOG_FUNC
+	// synchronously update stack state in Registry
+	iLocalDevice.Modify(iLocalDeviceSettings); //ignore error		
+	
+	iClosePending = ETrue;
+	QueIdleTimerEntry();
+	}
+
+void CLinkMgrProtocol::Open()
+/**
+	Open LinkMgr protocol.
+	Called everytime a new client (of LinkMgr) wants to use it.
+**/
+	{
+	LOG_FUNC
+	LocalOpen();
+	if(iExternalRef++ == 0)
+		{
+		ExternalOpenInit();
+		}
+	}
+
+void CLinkMgrProtocol::Close()
+	{
+	LOG_FUNC
+	if(--iExternalRef == 0)
+		{
+		ExternalCloseCleanup();
+		}
+	LocalClose();
+	}
+
+void CLinkMgrProtocol::LocalOpen()
+	{
+	LOG_FUNC
+	iClosePending = EFalse;
+	RemoveIdleTimerEntry();
+	CProtocolBase::Open();
+	}
+
+void CLinkMgrProtocol::LocalClose()
+	{
+	LOG_FUNC
+	CProtocolBase::Close();
+	}
+
+void CLinkMgrProtocol::ExternalOpenInit()
+	{
+	LOG_FUNC
+	TRAP_IGNORE(iLocalNamePublisher = CEirPublisherLocalName::NewL());
+	TRAP_IGNORE(iTxPowerLevelPublisher = CEirPublisherTxPowerLevel::NewL());
+	if(iLocalNamePublisher)
+		{
+		// Publish the initial name.
+		iLocalNamePublisher->UpdateName(iLocalDeviceSettings.DeviceName());
+		}
+	}
+
+void CLinkMgrProtocol::ExternalCloseCleanup()
+	{
+	LOG_FUNC
+	// Currently just the internal publishers
+	delete iLocalNamePublisher;
+	iLocalNamePublisher = NULL;
+	delete iTxPowerLevelPublisher;
+	iTxPowerLevelPublisher = NULL;
+	}
+
+void CLinkMgrProtocol::QueIdleTimerEntry()
+/**
+	Queue idle timer entry.
+	When this timer expires, it'll call TryToClose, which actually
+	causes the thing to finally close down.
+**/
+	{
+	LOG_FUNC
+	RemoveIdleTimerEntry();
+	iIdleEntryQueued = ETrue;
+	BTSocketTimer::Queue(KLinkMgrProtocolIdleTimer, iIdleTimerEntry);
+	}
+
+void CLinkMgrProtocol::RemoveIdleTimerEntry()
+/**
+	Called whenever we're opened.
+	Checks there are no idle timer entries queued.
+**/
+	{
+	LOG_FUNC
+	if (!iIdleEntryQueued)
+		return;
+	BTSocketTimer::Remove(iIdleTimerEntry);
+	iIdleEntryQueued = EFalse;
+	}
+
+ /*static*/ TInt CLinkMgrProtocol::TryToClose(TAny* aProtocol)
+/**
+	Actually try to close the protocol.
+	Called after the idle timeout period by the BTSocketTimer. If
+	we're all set to close down, the thing is closed.
+**/
+	{
+	LOG_STATIC_FUNC
+	CLinkMgrProtocol* p=static_cast<CLinkMgrProtocol*>(aProtocol);
+	p->iIdleEntryQueued = EFalse;
+	if (p->iClosePending)
+		{
+		p->CanClose();	// deletes this
+		}
+	return EFalse;
+	}
+
+CServProviderBase* CLinkMgrProtocol::NewSAPL(TUint aSockType)
+/** 
+	Create a new SAP.
+	The SAP returned is owned by the caller -- this protocol will not clean it up.
+	esock uses this function to create a new SAP, and esock will delete when it
+	is finished with it.
+**/
+	{
+	LOG_FUNC
+
+	CServProviderBase* sap = NULL;
+	
+	switch (aSockType)
+		{
+		case KSockBluetoothTypeESCO:
+			{
+			sap = CeSCOLink::NewL(*iPhysicalLinksMgr, NULL);
+			break;
+			}
+
+		case KSockBluetoothTypeSCO:
+			{
+			sap = CSCOLink::NewL(*iPhysicalLinksMgr, NULL);
+			break;
+			}
+
+		case KSockBluetoothTypeACL:
+			{
+			// an explicit ACL link has been asked for (by L2CAP)
+			sap = CACLLink::NewL(*iPhysicalLinksMgr, NULL, *this); // don't know for which PHY at this stage
+			break;
+			}
+
+		case KSockBluetoothTypeVendorSpecific:
+			{
+			if (!iVendorSpecificSAP)
+				{
+				sap = CVendorSAP::NewL(*this);
+				}
+			else
+				{
+				User::Leave(KErrInUse); // only support one :o)
+				}
+			break;
+			}
+
+		case KSockBluetoothTypeRawBroadcast:
+		default:
+			{
+			__ASSERT_DEBUG((aSockType > KHCIMinimumHandle && aSockType < KHCIMaximumHandle)||(aSockType==KSockBluetoothTypeRawBroadcast), Panic(EBTProxySAPInvalidCreate));
+			// if the connection handle has been specified - find the connection: aSockType *is* a ConnectionHandle in this case
+			CPhysicalLink* phySAP = NULL;
+
+			if (aSockType!=KSockBluetoothTypeRawBroadcast)
+				{
+				// it's a proxy sap which we should try to bind to the PHY
+				// 
+				phySAP = iPhysicalLinksMgr->FindPhysicalLink(static_cast<THCIConnHandle>(aSockType));
+				}
+			// create Proxy telling it the possible PHY
+			CBTProxySAP* proxySAP = CBTProxySAP::NewLC(*iPhysicalLinksMgr, phySAP);
+			CleanupStack::Pop(proxySAP);
+			sap = proxySAP;
+			}
+		}
+	ASSERT_DEBUG(sap);
+	return sap;
+	}
+
+TBTDevHCIVersion CLinkMgrProtocol::GetHWHCIVersion() const
+	{
+	LOG_FUNC
+	return iHWHCIVersion;
+	}
+
+void CLinkMgrProtocol::SetLocalVersion(THCIErrorCode aErr, TBTDevHCIVersion aHCIVersion, TBTDevLMPVersion aLMPVersion)
+	{
+	LOG_FUNC
+	// we store this for possibly useful later use :-)
+	if (aErr == EOK)
+		{
+		iHWHCIVersion = aHCIVersion; // not especially useful for us: but maybe to exploit >BT1.1
+		iHWLMPVersion = aLMPVersion; // the LM in the HC ;-)
+		}
+	}
+
+void CLinkMgrProtocol::SetOverrideLPMTimeout(TUint aOverrideLPMTimeout)
+	{
+	LOG_FUNC
+	iOverrideLPMTimeout =aOverrideLPMTimeout;
+	}
+
+TInt CLinkMgrProtocol::StartProtocolListening()
+	{
+	LOG_FUNC
+	return KickDiscoverabilitySubscriber();
+	}
+
+// oh Dear! void again, how to report failure...
+void CLinkMgrProtocol::StopProtocolListening()
+	{
+	LOG_FUNC
+
+	// NB. If 'KickDiscoverabilitySubscriber' returns an error, then
+	// we've tried to get the value for ScanStatus, but we've failed.
+	// Not a lot we can do about it.  This means that we may be 
+	// leaving inquiry and page scan enabled with no listeners.
+	(void)KickDiscoverabilitySubscriber();
+	}
+
+TInt CLinkMgrProtocol::KickDiscoverabilitySubscriber()
+	{
+	/*
+	 Reset P&S with its current value. This will kick
+	 CDiscoverabilitySubscriber's RunL which calls 
+	 SetInquiryAndPageScanningL to check for the current 
+	 user wishes AND the existance of listeners before 
+	 sending the appropriate WriteScanEnable command to 
+	 the controller.
+	*/
+	LOG_FUNC
+
+	TInt scanVal;
+	TInt err = iProperty.Get(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothSetScanningStatus, scanVal);
+	
+	if (err != KErrNone)
+		{
+		return err;
+		}
+
+	THCIScanEnable scan = static_cast<THCIScanEnable>(scanVal);
+
+	// force CDiscoverabilitySubscriber to try to enable Page and Inquiry scan to HW, when set
+	(void)(iProperty.Set(KPropertyUidBluetoothCategory,
+						 KPropertyKeyBluetoothSetScanningStatus,
+						 scan));
+
+	return err;
+	}
+	
+void CLinkMgrProtocol::LocalSupportedFeaturesAvailable()
+	{
+	// Set options based on the features
+	iInquiryMgr->SetInquiryMode();
+	iEirManServer->NotifyFeaturesReady();
+	}
+	
+void CLinkMgrProtocol::SetLocalFeatures(THCIErrorCode aErr, const TBTFeatures& aMask)
+	{
+	LOG_FUNC
+	if (aErr == EOK)
+		{
+		// we store this for possibly useful later use :-)
+		iHWFeatures = aMask;
+		}
+	// else ignore for now...
+	iEirManServer->NotifyFeaturesReady();
+	}
+
+void CLinkMgrProtocol::SetLocalCommands(THCIErrorCode aErr, const TBluetoothHciCommands& aMask)
+	{
+	LOG_FUNC
+	if (aErr == EOK)
+		{
+		// we store this for possibly useful later use :-)
+		iHWCommands = aMask;
+		
+		}
+	// else ignore for now...
+	}
+
+void CLinkMgrProtocol::SetInquiryAndPageScanningL()
+	{
+	LOG_FUNC
+	
+	TInt requestedScanVal = 0; // no Inquiry or Page Scanning as default
+	
+	TInt err = iProperty.Get(KPropertyUidBluetoothCategory,
+						KPropertyKeyBluetoothSetScanningStatus,
+						requestedScanVal
+						);
+
+	THCIScanEnable requestedScanSetting;						
+	if (!err) 
+		{
+		requestedScanSetting = static_cast<THCIScanEnable>(requestedScanVal);
+		}
+	else
+		{
+		
+		// If err == KErrNotFound, we have not published this property yet, but in all error cases
+		// we will use the current device setting to define the scanning requirements instead.
+		requestedScanSetting = iLocalDeviceSettings.ScanEnable();
+		}
+
+	// we need to check to see if we have any listeners before we can enable page & inquiry scan
+	THCIScanEnable validScanSetting;
+	if(!IsListening() || (requestedScanSetting == EInquiryScanOnly))
+		{
+		validScanSetting = ENoScansEnabled;
+		}
+	else 
+		{
+		validScanSetting = requestedScanSetting;
+		}
+	
+	iPendingLocalDeviceSettings.SetScanEnable(validScanSetting);
+	
+	iHCIFacade->WriteScanEnableL(iPendingLocalDeviceSettings.ScanEnable());
+		
+	if (!err) 
+		{
+		// Update registry with the requested settings from the _set_ key
+		iLocalDeviceSettings.SetScanEnable(static_cast<THCIScanEnable>(requestedScanVal));			
+		UpdateSettings();
+		}		
+	}
+
+void CLinkMgrProtocol::SetAcceptPairedOnlyMode(TBool aOn)
+/*
+THIS WORKS DIFFERENTLY: It does not involve the controller - it is
+purely a stack setting. It is called directly when the user requests
+the stack value to be reset.
+*/
+	{
+	LOG_FUNC
+	iLocalDeviceSettings.SetAcceptPairedOnlyMode(aOn);
+	
+	//update UI
+	(void)iProperty.Set(KPropertyUidBluetoothCategory,
+						KPropertyKeyBluetoothGetAcceptPairedOnlyMode,
+						iLocalDeviceSettings.AcceptPairedOnlyMode()
+						);
+
+	UpdateSettings();
+	}
+
+void CLinkMgrProtocol::SetSimplePairingDebugMode(TBool aOn)
+/*
+THIS WORKS DIFFERENTLY: It does not involve the controller - it is
+purely a stack setting.
+*/
+	{
+	LOG_FUNC
+	//update UI
+	(void)iProperty.Set(KPropertyUidBluetoothCategory,
+						KPropertyKeyBluetoothGetSimplePairingDebugMode,
+						aOn
+						);
+	}
+
+void CLinkMgrProtocol::SetDeviceClassL(TUint32 aCoD)
+	{
+	LOG_FUNC
+	// This method is called from Subscribers when the P&S is used to write a new CoD
+	TInt err = KErrNone;
+	err = CodMan().PandSCodHandler(aCoD);	// Cod Service Manager will decide what gets written
+		 
+	User::LeaveIfError(err);	// P&S CoD failed to write, but at least Codman has a record of it
+	}
+
+void CLinkMgrProtocol::WriteClassOfDeviceL(TUint32 aCoD)
+	{
+	LOG_FUNC
+	// Only write the CoD bits if they have changed from the existing setting
+	if (iPendingLocalDeviceSettings.DeviceClass() != aCoD)
+		{
+		iPendingLocalDeviceSettings.SetDeviceClass(aCoD);
+		iHCIFacade->WriteDeviceClassL(aCoD);
+		}
+	}
+
+TInt CLinkMgrProtocol::SetLocalDeviceName(const TDesC8& aName)
+	{
+	LOG_FUNC
+	// We trap this HCI command and not the others in Set... to keep the 
+	// error path up to CBTHostResolver::SetHostName
+	TRAPD(err, iHCIFacade->WriteLocalNameL(aName));
+	if (err == KErrNone)
+		{
+		iPendingLocalDeviceSettings.SetDeviceName(aName);
+		}
+	return err;
+	}
+
+void CLinkMgrProtocol::SetAFHHostChannelClassificationL(const TBTAFHHostChannelClassification& aChannelClassification)
+	{
+	LOG_FUNC
+	iHCIFacade->SetAFHHostChannelClassificationL(aChannelClassification);
+	}
+	
+void CLinkMgrProtocol::SetAFHChannelAssessmentModeL(TBool aMode)
+	{
+	LOG_FUNC
+	iPendingLocalDeviceSettings.SetAFHChannelAssessmentMode(aMode);
+	iHCIFacade->WriteAFHChannelAssessmentModeL(aMode);
+	}
+
+void CLinkMgrProtocol::SetLimitedDiscoverableIfChangedL(TBool aOn)
+	{
+	LOG_FUNC
+	// Set limited discoverable if value differs from cached (= registry) value
+	// and previous change going the opposite way is not pending completion
+	// See also DoSetLimitedDiscoverableL
+	if ((aOn == iLocalDeviceSettings.LimitedDiscoverable()) &&
+		(iPendingLocalDeviceSettings.LimitedDiscoverable() == iLocalDeviceSettings.LimitedDiscoverable()))
+		return;
+
+	DoSetLimitedDiscoverableL(aOn);
+	}
+
+void CLinkMgrProtocol::DoSetLimitedDiscoverableL(TBool aOn)
+	{
+	LOG_FUNC
+	// HCI spec says we can always send >1 IAC! Controllers will take first
+	// so we can do what GAP says easily
+
+	TUint8 numIACs =0;
+	TUint iacs[2];
+
+	if (aOn)
+		{
+		// turn on LIAC
+		iPendingLocalDeviceSettings.SetLimitedDiscoverable(ETrue);
+		WriteClassOfDeviceL(iPendingLocalDeviceSettings.DeviceClass() | (EMajorServiceLimitedDiscoverableMode << 
+				(KLengthOfDeviceClass+KStartingOffsetOfDeviceClass))); 
+		numIACs = 2;
+		iacs[0] = KLIAC;
+		iacs[1] = KGIAC;
+		}
+	else
+		{
+		// turn off LIAC - could do the 1 minute GAP timer?
+		iPendingLocalDeviceSettings.SetLimitedDiscoverable(EFalse);
+		WriteClassOfDeviceL(iPendingLocalDeviceSettings.DeviceClass() & ~(EMajorServiceLimitedDiscoverableMode << 
+				(KLengthOfDeviceClass+KStartingOffsetOfDeviceClass))); 
+		numIACs = 1;
+		iacs[0] = KGIAC;
+		}
+	
+	iHCIFacade->WriteIACLAPL(numIACs, iacs);
+	}
+
+void CLinkMgrProtocol::UpdateLocalDevicePower(TBTPowerState aState)
+	{
+	LOG_FUNC
+	iLocalDeviceSettings.SetPowerSetting(static_cast<TUint8>(aState));
+	UpdateSettings();
+	}
+	
+// This is an update method for dealing with the result of asking what the device
+// name is. It is used to keep iLocalDeviceSettings.DeviceName(), the P&S device 
+// name value and the h/w value in sync
+void CLinkMgrProtocol::UpdateLocalDeviceName(const TDesC8& aName)
+   	{
+	LOG_FUNC
+  	iLocalDeviceSettings.SetDeviceName(aName);
+
+	// Update the UI with the unicode DeviceName
+	TBuf16<KHCILocalDeviceNameMaxLength> unicodeName;
+	(void) CnvUtfConverter::ConvertToUnicodeFromUtf8(unicodeName, iLocalDeviceSettings.DeviceName());
+	// The return from the above should never be > 0 since aName should have a length <= KHCILocalDeviceNameMaxLength
+	// hence we shouldn't have any unconverted chars left over. If we get another error then we just have to publish  
+	// the resulting unicode name anyway.
+		
+	(void)iProperty.Set(KPropertyUidBluetoothCategory,
+				    	KPropertyKeyBluetoothGetDeviceName,
+				    	unicodeName
+						);
+  	UpdateSettings();					
+   	}
+   	
+// This is an update method for dealing with the result of telling the h/w what the device
+// name should be. It is used to keep iLocalDeviceSettings.DeviceName(), the P&S device 
+// name value and the h/w value in sync
+void CLinkMgrProtocol::UpdateLocalDeviceName(TBool aSucceeded)
+	{
+	LOG_FUNC
+	if (aSucceeded)
+		{
+		TBool isDifferentName = 
+				(iLocalDeviceSettings.DeviceName() != iPendingLocalDeviceSettings.DeviceName());
+		iLocalDeviceSettings.SetDeviceName(iPendingLocalDeviceSettings.DeviceName());
+		if(iLocalNamePublisher && isDifferentName)
+			{
+			iLocalNamePublisher->UpdateName(iLocalDeviceSettings.DeviceName());
+			}
+		}
+		
+	// Update the UI with the unicode DeviceName
+	TBuf16<KHCILocalDeviceNameMaxLength> unicodeName;
+	(void) CnvUtfConverter::ConvertToUnicodeFromUtf8(unicodeName, iLocalDeviceSettings.DeviceName());
+	// The return from the above should never be > 0 since unicodeName is the same size as utf8Name 
+	// hence we shouldn't have any unconverted chars left over. Similarly ret should not be < 0 
+	// because when we received DeviceName in Unicode we where able to convert it to UTF-8
+	// without a problem so reversing the conversion should be okay.
+	
+	(void)iProperty.Set(KPropertyUidBluetoothCategory,
+				    	KPropertyKeyBluetoothGetDeviceName,
+				    	unicodeName
+						);
+	UpdateSettings();
+	}
+
+void CLinkMgrProtocol::UpdateLocalDeviceScanEnable(TBool aSucceeded)
+	{
+	LOG_FUNC
+	TInt scan;
+	TInt err = KErrNone;
+	
+	// Set scan to be the actual scan enable state of the hardware
+	if(aSucceeded)
+		{
+		// We've set it to the value in iLocalDeviceSettings
+		scan = iPendingLocalDeviceSettings.ScanEnable();
+		}
+	else
+		{
+		// We haven't changed it, current value is in the _get_ key
+		err = iProperty.Get(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothGetScanningStatus,
+							scan);
+		}
+	
+	if(!err)
+		{	
+		//update UI with the hardware's settings using the _get_ key
+		(void)iProperty.Set(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothGetScanningStatus,
+							scan
+							);	
+		}					
+	}
+
+void CLinkMgrProtocol::UpdateLimitedDiscoverable(TBool aSucceeded)
+	{
+	LOG_FUNC
+	if (aSucceeded)
+		{
+		iLocalDeviceSettings.SetLimitedDiscoverable(
+			iPendingLocalDeviceSettings.LimitedDiscoverable());
+		}
+	
+	//update UI
+	(void)iProperty.Set(KPropertyUidBluetoothCategory,
+						KPropertyKeyBluetoothGetLimitedDiscoverableStatus,
+						iLocalDeviceSettings.LimitedDiscoverable()
+						);
+
+	UpdateSettings();
+	}
+
+void CLinkMgrProtocol::UpdateDeviceClass(TBool aSucceeded)
+	{
+	LOG_FUNC
+	if (aSucceeded)
+		{
+		iLocalDeviceSettings.SetDeviceClass(
+			iPendingLocalDeviceSettings.DeviceClass());
+		}
+	
+	//update UI
+	(void)iProperty.Set(KPropertyUidBluetoothCategory,
+						KPropertyKeyBluetoothGetDeviceClass,
+						iLocalDeviceSettings.DeviceClass()
+						);
+
+	UpdateSettings();
+	}
+	
+void CLinkMgrProtocol::UpdateDeviceClass(TBool aSucceeded, TUint aCoD)
+	{
+	LOG_FUNC
+	if (aSucceeded)
+		{
+		iLocalDeviceSettings.SetDeviceClass(aCoD);
+		
+		//update UI
+		(void)iProperty.Set(KPropertyUidBluetoothCategory,
+							KPropertyKeyBluetoothGetDeviceClass,
+							aCoD
+							);
+							
+		UpdateSettings();							
+		}
+	}
+
+void CLinkMgrProtocol::UpdateAFHChannelAssessmentMode(TBool aSucceeded)
+	{
+	LOG_FUNC
+	if (aSucceeded)
+		{
+		iLocalDeviceSettings.SetAFHChannelAssessmentMode(
+			iPendingLocalDeviceSettings.AFHChannelAssessmentMode());
+		}
+
+	UpdateSettings();
+	}
+
+void CLinkMgrProtocol::UpdateSettings()
+	{
+	LOG_FUNC
+	//Careful! - we new'd it without ELeave
+	if (iRegistryUpdater)
+		{
+		iRegistryUpdater->Update();
+		}
+	}
+
+void CLinkMgrProtocol::UpdateInquiryResponseTxPowerLevel(TInt8 aTxPowerLevel)
+	{
+	LOG_FUNC
+	if(iTxPowerLevelPublisher)
+		{
+		iTxPowerLevelPublisher->UpdateTxPowerLevel(aTxPowerLevel);
+		}
+	}
+
+
+void CLinkMgrProtocol::SetUIConnecting(TBool aConnecting)
+	{
+	LOG_FUNC
+	(void)iProperty.Set(KPropertyUidBluetoothCategory,
+						KPropertyKeyBluetoothGetConnectingStatus,
+						aConnecting);
+	}
+
+
+void CLinkMgrProtocol::SetUINumPhysicalLinks(TUint aNum)
+	{
+	LOG_FUNC
+	(void)iProperty.Set(KPropertyUidBluetoothCategory,
+						KPropertyKeyBluetoothGetPHYCount,
+						aNum);
+	}
+
+
+void CLinkMgrProtocol::SetLocalBTAddress(const TBTDevAddr& aAddr)
+	{
+	LOG_FUNC
+	iLocalDeviceAddress = aAddr;
+
+	// publish this number - might be useful
+	const TDesC8& des = aAddr.Des();
+	(void)iProperty.Set(KPropertyUidBluetoothCategory,
+						KPropertyKeyBluetoothGetLocalDeviceAddress,
+						des);
+	}
+
+void CLinkMgrProtocol::SetUIDiscovering(TInt aDiscoveringState)
+ 	{
+	LOG_FUNC
+ 	(void)iProperty.Set(KPropertyUidBluetoothCategory,
+ 						KPropertyKeyBluetoothHostResolverActive,
+ 						aDiscoveringState);
+ 	}
+ 
+TInt CLinkMgrProtocol::ACLPacketMTU() const
+	{
+	LOG_FUNC
+	return iLinkMuxer->ACLPacketMTU();
+	}
+
+TInt CLinkMgrProtocol::ControlPlaneMessage(TBTControlPlaneMessage aMessage, TAny* aParam)
+	{
+	LOG_FUNC
+	TInt rerr = KErrNotFound;
+	CPhysicalLink* con = NULL;
+	
+	if ((aMessage == ESubscribePhysicalLink) || (aMessage == EUnsubscribePhysicalLink)) 
+		{
+		TPhysicalLinkSubscriptionInfo& subscriptionInfo = *reinterpret_cast<TPhysicalLinkSubscriptionInfo*>(aParam);
+		con = iPhysicalLinksMgr->FindPhysicalLink(subscriptionInfo.iAddr);
+		}
+	else if ((aMessage == ETryToAndThenPreventHostEncryptionKeyRefresh))
+		{
+		// For EPreventAutoEncryptionKeyRefresh we pass the address as a TBTDevAddr**
+		const TBTDevAddr& addr = **reinterpret_cast<const TBTDevAddr**>(aParam);
+		con = iPhysicalLinksMgr->FindPhysicalLink(addr);
+		}
+	else
+		{
+		const TBTDevAddr& addr = *reinterpret_cast<const TBTDevAddr*>(aParam);
+		con = iPhysicalLinksMgr->FindPhysicalLink(addr);
+		}
+
+	if (con)
+		{
+		switch (aMessage)
+			{
+			case EOverridePark:
+				rerr = con->OverridePark();
+				break;
+			case EUndoOverridePark:
+				rerr = con->UndoOverridePark();
+				break;
+			case EOverrideLPMWithTimeout:
+				rerr = con->OverrideLPMWithTimeout(iOverrideLPMTimeout);
+				break;
+			case EOverrideLPM:
+				rerr = con->OverrideLPM();
+				break;
+			case EUndoOverrideLPM:
+				rerr = con->UndoOverrideLPM();
+				break;
+			case ESubscribePhysicalLink:
+				{
+				const TPhysicalLinkSubscriptionInfo& subscriptionInfo = *reinterpret_cast<TPhysicalLinkSubscriptionInfo*>(aParam);
+				con->SubscribeLinkObserver(subscriptionInfo.iMPhysicalLinkObserver);
+				break;
+				}
+			case EUnsubscribePhysicalLink:
+				{
+				const TPhysicalLinkSubscriptionInfo& subscriptionInfo = *reinterpret_cast<TPhysicalLinkSubscriptionInfo*>(aParam);				
+				con->UnsubscribeLinkObserver(subscriptionInfo.iMPhysicalLinkObserver);
+				break;
+				}
+			case ETryToAndThenPreventHostEncryptionKeyRefresh:
+				{
+				rerr = con->TryToAndThenPreventHostEncryptionKeyRefresh(aParam);
+				break;
+				}
+			default:
+				rerr = KErrNotSupported;
+				break;
+			};
+		}
+	return rerr;
+	}
+	
+	
+void CLinkMgrProtocol::ClearPendingLocalDeviceSettingsCod()
+	{
+	LOG_FUNC
+	// If we know that the h/w has been reset, then we need to ensure that our persistent
+	// value reflects this. That way we will force the CoD re-write to the hardware.
+	iPendingLocalDeviceSettings.SetDeviceClass(KDeviceClassReset);
+	}
+
+
+
+//
+// CRegistrySession
+//
+
+CRegistrySession* CRegistrySession::NewL(CLinkMgrProtocol& aLinkMgrProtocol)
+	{
+	LOG_STATIC_FUNC
+	CRegistrySession* self = new(ELeave) CRegistrySession(aLinkMgrProtocol);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+void CRegistrySession::Open()
+	{
+	LOG_FUNC
+	if(iAccessCount++ == 0)
+		{
+		iLinkMgrProtocol.LocalOpen();
+		}
+	}
+
+void CRegistrySession::Close()
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iAccessCount > 0, Panic(ERegistrySessionClosedTooManyTimes));
+	if(--iAccessCount == 0)
+		{
+		iLinkMgrProtocol.LocalClose();
+		}
+	}
+	
+CRegistrySession::CRegistrySession(CLinkMgrProtocol& aLinkMgrProtocol)
+	: CBase()
+	, iAccessCount(0)
+	, iLinkMgrProtocol(aLinkMgrProtocol)
+	{
+	LOG_FUNC
+	}
+
+void CRegistrySession::ConstructL()
+	{
+	LOG_FUNC
+	User::LeaveIfError(iRegServ.Connect());
+	}
+
+CRegistrySession::~CRegistrySession()
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iAccessCount == 0, Panic(ERegistrySessionDeletedWhenOpen));
+	iRegServ.Close();
+	}
+
+RBTRegServ& CRegistrySession::RegServ()
+	{
+	LOG_FUNC
+	return iRegServ;
+	}
+
+
+
+//class CRegistryUpdater
+CRegistryUpdater::~CRegistryUpdater()
+	{
+	LOG_FUNC
+	Cancel();
+	}
+	
+
+CRegistryUpdater::CRegistryUpdater(RBTLocalDevice& aLocalDevice,TBTTrackedLocalDevice& aSettings) :
+CActive(CActive::EPriorityStandard),iLocalDevice(aLocalDevice),iStackSettings(aSettings),iRepeatUpdate(EFalse)
+	{
+	LOG_FUNC
+	CActiveScheduler::Add(this);
+	}
+
+void CRegistryUpdater::Update()
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iLocalDevice.SubSessionHandle(), Panic(ELocalDeviceBadHandle));
+	
+	if (!IsActive())
+		{
+		TInt err;
+		err = iLocalDevice.Get(iRegistrySettings); 
+		
+		// if we can't get settings from registry, we won't be able to update them
+		if ( err == KErrNone )
+			{
+			iStackSettings.Modify(iRegistrySettings);
+			iStackSettings.ResetChangesMask();
+			iLocalDevice.Modify(iRegistrySettings,iStatus);
+			SetActive();
+			iRepeatUpdate = EFalse;	
+			}
+		}
+	else
+		{
+		// Even if multiple requests come in while this object is active we only need to
+		// perform one update since iLocalDevice will accumulated required new settings.
+		LOG(_L(" -- CRegistryUpdaterAO already active so will repeat the update later."));
+		iRepeatUpdate = ETrue;
+		}
+	}
+
+void CRegistryUpdater::RunL()
+	{
+	LOG_FUNC
+	if (iRepeatUpdate)
+		{
+		Update();
+		}		
+	}
+	
+void CRegistryUpdater::DoCancel()
+	{
+	LOG_FUNC
+	iLocalDevice.CancelRequest(iStatus);
+	iRepeatUpdate = EFalse;	
+	}
+	
+
+//class TBTTrackedLocalDevice
+void TBTTrackedLocalDevice::SetAddress(const TBTDevAddr& aAddr)
+	{
+	LOG_FUNC
+	TBTLocalDevice::SetAddress(aAddr);
+	StoreChange(EAddress);
+	}
+	
+void TBTTrackedLocalDevice::SetDeviceClass(TUint32 aCod)
+	{
+	LOG_FUNC
+	TBTLocalDevice::SetDeviceClass(aCod);
+	StoreChange(ECoD);
+	}
+
+void TBTTrackedLocalDevice::SetDeviceName(const TDesC8& aName)
+	{
+	LOG_FUNC
+	TBTLocalDevice::SetDeviceName(aName);
+	StoreChange(EDeviceName);
+	}
+
+void TBTTrackedLocalDevice::SetScanEnable(THCIScanEnable aEnable)
+	{
+	LOG_FUNC
+	TBTLocalDevice::SetScanEnable(aEnable);
+	StoreChange(EScanEnable);
+	}
+
+void TBTTrackedLocalDevice::SetLimitedDiscoverable(TBool aOn)
+	{
+	LOG_FUNC
+	TBTLocalDevice::SetLimitedDiscoverable(aOn);
+	StoreChange(ELimitedDiscoverable);
+	}
+
+void TBTTrackedLocalDevice::SetPowerSetting(TUint8 aPowerSetting)
+	{
+	LOG_FUNC
+	TBTLocalDevice::SetPowerSetting(aPowerSetting);
+	StoreChange(EPowerSetting);
+	}
+
+void TBTTrackedLocalDevice::SetAFHChannelAssessmentMode(TBool aOn)
+	{
+	LOG_FUNC
+	TBTLocalDevice::SetAFHChannelAssessmentMode(aOn);
+	StoreChange(EAFHChannelAssessmentMode);
+	}
+
+void TBTTrackedLocalDevice::SetAcceptPairedOnlyMode(TBool aOn)
+	{
+	LOG_FUNC
+	TBTLocalDevice::SetAcceptPairedOnlyMode(aOn);
+	StoreChange(EAcceptPairedOnlyMode);
+	}
+
+void TBTTrackedLocalDevice::StoreChange(TUint8 aChange)
+	{
+	LOG_FUNC
+	iChangedSettings |= aChange;
+	}
+	
+void TBTTrackedLocalDevice::ResetChangesMask()
+	{
+	LOG_FUNC
+	iChangedSettings = 0;
+	}
+	
+void TBTTrackedLocalDevice::Modify(TBTLocalDevice& aLocalDeviceSettings)
+	{
+	LOG_FUNC
+	if ( iChangedSettings & EAddress )
+		{
+		aLocalDeviceSettings.SetAddress(Address());
+		}
+
+	if ( iChangedSettings & ECoD )
+		{
+		aLocalDeviceSettings.SetDeviceClass(DeviceClass());
+		}
+
+	if ( iChangedSettings & EDeviceName )
+		{
+		aLocalDeviceSettings.SetDeviceName(DeviceName());
+		}
+
+	if ( iChangedSettings & EPowerSetting )
+		{
+		aLocalDeviceSettings.SetPowerSetting(PowerSetting());
+		}
+
+	if ( iChangedSettings & EScanEnable )
+		{
+		aLocalDeviceSettings.SetScanEnable(ScanEnable());
+		}
+
+	if ( iChangedSettings & ELimitedDiscoverable )
+		{
+		aLocalDeviceSettings.SetLimitedDiscoverable(LimitedDiscoverable());
+		}
+
+	if ( iChangedSettings & EAFHChannelAssessmentMode )
+		{
+		aLocalDeviceSettings.SetAFHChannelAssessmentMode(AFHChannelAssessmentMode());
+		}
+
+	if ( iChangedSettings & EAcceptPairedOnlyMode )
+		{
+		aLocalDeviceSettings.SetAcceptPairedOnlyMode(AcceptPairedOnlyMode());
+		}
+	}
+