bluetooth/btstack/secman/secman.cpp
changeset 0 29b1cd4cb562
child 8 2b6718f05bdb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/secman/secman.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1931 @@
+// 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:
+//
+
+
+#include <bluetooth/logger.h>
+
+#include <bluetooth/hci/hciutil.h>
+
+#include "secman.h"
+#include "secevent.h"
+#include "hostresolver.h"
+#include "pairingserver.h"
+#include "oobdata.h"
+#include "simplepairingresult.h"
+#include "btaccessrequesterstatemachine.h"
+
+#ifdef BT_LINKMGR_V2
+#include "physicallinks.h"
+#include "physicallinksmanager.h"
+#else
+#include "PhysicalLinks.h"
+#include "PhysicalLinksManager.h"
+#endif
+
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_SECMAN);
+#endif
+
+#ifdef _DEBUG
+PANICCATEGORY("secman");
+#endif
+
+static const TInt KBTSecManAccessRequesterArrayGranularity = 4;
+static const TInt KBTSecManNotifierRequesterArrayGranularity = 4;
+
+
+//------------------------------------------------------------------------//
+//class CBTSecMan
+//------------------------------------------------------------------------//
+
+CBTSecMan* CBTSecMan::NewL()
+	{
+	LOG_STATIC_FUNC
+	CBTSecMan* self = CBTSecMan::NewLC();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CBTSecMan* CBTSecMan::NewLC()
+	{
+	LOG_STATIC_FUNC
+	CBTSecMan* self = new(ELeave) CBTSecMan();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+CBTSecMan::CBTSecMan()
+	: iAccessRequesters(KBTSecManAccessRequesterArrayGranularity)
+	, iPendingAccessRequesters(KBTSecManAccessRequesterArrayGranularity)
+	, iNotifierRequesters(KBTSecManNotifierRequesterArrayGranularity)
+	, iLocalSimplePairingMode(EFalse)
+	, iDebugMode (EFalse)
+	{
+	LOG_FUNC
+	}
+
+void CBTSecMan::ConstructL()
+	{
+	LOG_FUNC
+	iStateMachine = CBTAccessRequesterStateFactory::NewL();
+	iCommandController = CSecManCommandController::NewL(*this);
+	
+	iOobDataManager = COobDataManager::NewL(*this);
+	iSimplePairingResultList = CSimplePairingResultList::NewL();
+	iAuthenticationResultList = CAuthenticationResultList::NewL();
+	iPairingServer = CPairingServer::NewL(*iOobDataManager, *iSimplePairingResultList, *iAuthenticationResultList);
+	}
+
+void CBTSecMan::SetLocalSimplePairingMode(TBool aEnabled)
+	{
+	LOG_FUNC
+	iLocalSimplePairingMode=aEnabled;
+	}
+
+TBool CBTSecMan::LocalSimplePairingMode() const
+	{
+	LOG_FUNC
+	return iLocalSimplePairingMode;
+	}
+
+void CBTSecMan::SimplePairingSupportDetermined(const TBTDevAddr& aBDAddr)
+	{
+	LOG_FUNC
+
+	// Pending requesters must be notified first than the active requester. 
+	// Otherwise it wouldn't work properly and pending requesters would not be notified at all.
+	for (TInt i=0; i<iPendingAccessRequesters.Count(); i++)
+		{
+		CBTAccessRequester* requester = iPendingAccessRequesters[i];
+		if (requester->DeviceAddress() == aBDAddr && requester->BasebandConnected())
+			{
+			TBTSecEvent event(TBTSecEvent::EPhysicalLinkUp);
+			requester->SendEvent(event);
+			}	
+		}
+
+	CBTAccessRequester* requester = this->FindActiveAccessRequester(aBDAddr);
+	// There should only be one active access requester
+	if (requester && requester->BasebandConnected())
+		{
+		TBTSecEvent event(TBTSecEvent::EPhysicalLinkUp);
+		requester->SendEvent(event);
+		}
+	}
+
+void CBTSecMan::SetPhysicalLinksMgr(const CPhysicalLinksManager& aConnectionsMgr)
+	{
+	LOG_FUNC
+	iPhysicalLinksManager = &const_cast<CPhysicalLinksManager&>(aConnectionsMgr);
+	iPairingServer->SetPhysicalLinksManager(*iPhysicalLinksManager);
+	}
+
+void CBTSecMan::ClearPhysicalLinksMgr()
+	{
+	LOG_FUNC
+	iPhysicalLinksManager = NULL;
+	iPairingServer->ClearPhysicalLinkMgr();
+	}
+
+// Passes a reference to the LinksMgrProtocol ultimately to the PairingServer 
+void CBTSecMan::SetLinksMgrProtocol(CLinkMgrProtocol& aLinkMgrProtocol)
+	{
+	LOG_FUNC
+	iPairingServer->SetLinksMgrProtocol(aLinkMgrProtocol);
+	}
+
+void CBTSecMan::ClearLinksMgrProtocol()
+	{
+	LOG_FUNC
+	iPairingServer->ClearLinksMgrProtocol();
+	}
+
+void CBTSecMan::SetHCICommandQueue(MHCICommandQueue& aCommandQueue)
+	{
+	LOG_FUNC
+	iCommandController->SetHCICommandQueue(aCommandQueue);
+	iOobDataManager->SetHCICommandQueue(aCommandQueue);
+	}
+
+void CBTSecMan::ClearHCICommandQueue()
+	{
+	LOG_FUNC
+	iCommandController->ClearHCICommandQueue();
+	iOobDataManager->ClearHCICommandQueue();
+	}
+
+CPhysicalLinksManager& CBTSecMan::ConnectionsManager() const
+	{
+	LOG_FUNC
+	__ASSERT_ALWAYS(iPhysicalLinksManager, PANIC(KBTSecPanic,EBTSecNullPhysicalLinksManager));
+	return *iPhysicalLinksManager;
+	}
+
+COobDataManager& CBTSecMan::OobDataManager() const
+	{
+	LOG_FUNC
+	return *iOobDataManager;
+	}
+
+TBool CBTSecMan::DebugMode() const
+	{
+	LOG_FUNC
+	return iDebugMode;
+	}
+
+void CBTSecMan::SetDebugMode(TBool aOn)
+	{
+	LOG_FUNC
+	// SecMan owns the policy about simple pairing debug mode - here we only allow it to be 
+	// turned on.  So ignore any "off" requests.  (Stack must be unloaded for debug mode to be
+	// turned off).
+	if(aOn && !iDebugMode)
+		{
+		// First try to set debug mode. If we fail to send the command then we will just be
+		// stuck in non-debug mode...
+		static const TUint8 KSimplePairingDebugModeEnabled = 0x01;
+		TRAP_IGNORE(iCommandController->WriteSimplePairingDebugModeL(KSimplePairingDebugModeEnabled));
+		}
+	}
+
+void CBTSecMan::ClearDebugMode()
+	{
+	LOG_FUNC
+	// Used to clear debug mode when the stack is reset
+	iDebugMode = EFalse;
+	ConnectionsManager().SimplePairingDebugModeChanged(EFalse);
+	}
+
+void CBTSecMan::DebugModeChanged(TBool aOn)
+	{
+	__ASSERT_DEBUG(aOn, PANIC(KBTSecPanic, EBTSecDebugModeTurnedOff));
+	iDebugMode = aOn;
+	ConnectionsManager().SimplePairingDebugModeChanged(aOn);
+	}
+
+CBTSecMan::~CBTSecMan()
+	{
+	LOG_FUNC
+	
+	iAccessRequesters.ResetAndDestroy();
+	iAccessRequesters.Close();
+
+	iPendingAccessRequesters.ResetAndDestroy();
+	iPendingAccessRequesters.Close();
+	
+	iNotifierRequesters.ResetAndDestroy();
+	iNotifierRequesters.Close();
+	
+	delete iStateMachine;
+	delete iCommandController;
+	delete iPairingServer;
+	delete iOobDataManager;
+	delete iSimplePairingResultList;
+	delete iAuthenticationResultList;
+	}
+
+CBTAccessRequester* CBTSecMan::FindActiveAccessRequester(const TBTDevAddr& aAddr) const
+	{
+	LOG_FUNC
+	CBTAccessRequester* ret = NULL;
+	TInt ix = iAccessRequesters.Find(aAddr, CompareAccessRequesterByBDAddr);
+	if(ix >= 0)
+		{
+		ret = iAccessRequesters[ix];
+		}
+	return ret;
+	}
+
+TBool CBTSecMan::CompareAccessRequesterByBDAddr(const TBTDevAddr* aKey, const CBTAccessRequester& aAccessRequester)
+	{
+	LOG_STATIC_FUNC
+	return (!aKey || (*aKey) == aAccessRequester.DeviceAddress());
+	}
+
+TBool CBTSecMan::CompareAccessRequesterByRequester(const MAccessRequestResponseHandler* aKey, const CBTAccessRequester& aAccessRequester)
+	{
+	LOG_STATIC_FUNC
+	return aKey == &aAccessRequester.ServiceRequester();
+	}
+
+void CBTSecMan::AccessRequestL(const TBTServiceSecurity& aSecurity,
+							   const TBTServiceSecurityPerDevice* const aOverride,
+							   const TBTDevAddr& aBDAddr,
+							   TAccessType aAccessType,
+							   MAccessRequestResponseHandler& aRequester)
+/**
+Handle an access request...
+Create a new CBTAccessRequester object to handle the request.
+**/
+	{
+	LOG_FUNC
+
+#ifdef _DEBUG
+	// Check that a service isn't queuing multiple access requesters.
+	TInt ix = iAccessRequesters.Find(aRequester, CompareAccessRequesterByRequester);
+	__ASSERT_DEBUG(ix == KErrNotFound, PANIC(KBTSecPanic, EBTSecServiceTryingToQueueMultipleAccessRequesters));
+	ix = iPendingAccessRequesters.Find(aRequester, CompareAccessRequesterByRequester);
+	__ASSERT_DEBUG(ix == KErrNotFound, PANIC(KBTSecPanic, EBTSecServiceTryingToQueueMultipleAccessRequesters));
+#endif // _DEBUG
+
+	// find the baseband this SAP is running on
+	CPhysicalLink& con = *iPhysicalLinksManager->FindPhysicalLink(aBDAddr);
+	CBTAccessRequester* p = CBTAccessRequester::NewLC(con, aSecurity,
+													  aOverride,
+													  aRequester,
+													  aAccessType,
+													  *this);
+	
+	CBTAccessRequester* requester = FindActiveAccessRequester(aBDAddr);
+	if(requester)
+		{
+		User::LeaveIfError(iPendingAccessRequesters.Append(p));
+		CleanupStack::Pop(p); //clean up of p now handled by iPendingAccessRequesters
+		}
+	else
+		{
+		User::LeaveIfError(iAccessRequesters.Append(p));
+		CleanupStack::Pop(p); //clean up of p now handled by iAccessRequesters
+		// Try to start- it may not happen (depends on if device retrieved from registry)
+		p->Start();
+		}
+	
+	}
+
+void CBTSecMan::CancelRequest(MAccessRequestResponseHandler& aRequester)
+	{
+	LOG_FUNC
+	// search through access requesters to find correct one
+	LOG1(_L8("\tCBTSecMan::CancelRequest from SAP 0x%08x"), &aRequester)
+
+	CBTAccessRequester* request = NULL;
+	
+	TInt ix = iAccessRequesters.Find(aRequester, CompareAccessRequesterByRequester);
+	if(ix >= 0)
+		{
+		request = iAccessRequesters[ix];
+		}
+	else
+		{
+		ix = iPendingAccessRequesters.Find(aRequester, CompareAccessRequesterByRequester);
+		if(ix >= 0)
+			{
+			request = iPendingAccessRequesters[ix];
+			}
+		}
+	
+	if(request)
+		{
+		static_cast<void>(FinishAccessRequest(request)); // don't need to call back to requester...
+		}
+	
+#ifdef _DEBUG
+	// Do a sanity test to check that there aren't multiple access requesters per service
+	ix = iAccessRequesters.Find(aRequester, CompareAccessRequesterByRequester);
+	__ASSERT_DEBUG(ix == KErrNotFound, PANIC(KBTSecPanic, EBTSecMultipleActiveAccessRequestersForService));
+	ix = iPendingAccessRequesters.Find(aRequester, CompareAccessRequesterByRequester);
+	__ASSERT_DEBUG(ix == KErrNotFound, PANIC(KBTSecPanic, EBTSecMultiplePendingAccessRequestersForService));
+#endif // _DEBUG
+	}
+
+void CBTSecMan::GetPassKeyLengthAndOriginator(const TBTDevAddr& aAddr, TUint& aPasskeyMinLength,
+											  TBool& aLocallyInitiatedAuthentication,
+											  TBool& aStrongKeyRequired)
+
+/**
+If authorisation request was initiated locally it will return true and will
+return the passkey minimal length requred by user
+**/
+	{
+	LOG_FUNC
+	TUint tmpPasskeyLength = 0;
+	TBluetoothMitmProtection mitmReqs = EMitmNotRequired;
+	TBool locallyInitiated = EFalse;
+	TInt count = iAccessRequesters.Count();
+	aStrongKeyRequired = EFalse;
+
+	// find all pending AccessRequesters for given BTAddr and find maximum of PasskeyMinLength
+	if(count != 0)
+		{
+		for (TInt i=0; i<count;i++)
+			{
+			CBTAccessRequester* requester = iAccessRequesters[i];
+			if (requester->IsAuthenticationReqPending(aAddr, tmpPasskeyLength, mitmReqs))
+				{
+				locallyInitiated = ETrue;
+				if (aPasskeyMinLength < tmpPasskeyLength)
+					{
+					aPasskeyMinLength = tmpPasskeyLength;
+					}
+				if(mitmReqs == EMitmRequired)
+					{
+					aStrongKeyRequired = ETrue;
+					}
+				}
+			}
+		}
+	aLocallyInitiatedAuthentication = locallyInitiated;
+	}
+
+
+
+TBool CBTSecMan::IsDedicatedBondingAttempted(const TBTDevAddr& aAddr)
+	{
+	LOG_FUNC
+
+	CBTAccessRequester* requester = FindActiveAccessRequester(aAddr);
+
+	if(requester && (requester->AccessType() == EDedicatedBonding) )
+		{
+		return ETrue;
+		}
+	else
+		{
+		return EFalse;
+		}
+	}
+
+TBool CBTSecMan::IsOutboundAccessRequest(const TBTDevAddr& aAddr)
+	{
+	LOG_FUNC
+	// For now the only outbound access request is for dedicated bonding
+	// attempts (so we share the code).
+	return IsDedicatedBondingAttempted(aAddr);
+	}
+
+
+void CBTSecMan::AuthenticationInProgress()
+/**
+When authentication request was sent to HW, HCI will notify SecMan
+**/
+	{
+	LOG_FUNC
+	// find first pending AccessRequesters and set AuthenticationInProgress flag
+	for (TInt i=0; i<iAccessRequesters.Count(); i++)
+		{
+		CBTAccessRequester* requester = iAccessRequesters[i];
+
+		if (requester->AuthenticationRequired() && !requester->AuthenticationInProgress())
+			{
+			TBTSecEvent event(TBTSecEvent::EAuthenticationRequested);
+			requester->SendEvent(event);
+			break;
+			}
+		}
+	}
+
+void CBTSecMan::IOCapabilityRequestFromRemote(const TBTDevAddr& aAddr)
+	{
+	LOG_FUNC
+	CBTAccessRequester* requester = FindActiveAccessRequester(aAddr);
+	if(requester)
+		{
+		LOG(_L8("\tCBTAccessRequester FOUND!\n"));
+		TBTSecEvent event(TBTSecEvent::EIOCapsRequested);
+		requester->SendEvent(event);
+		}
+	else
+		{
+		LOG(_L8("\tCBTAccessRequester NOT FOUND!\n"));
+		CPhysicalLink* link = iPhysicalLinksManager->FindPhysicalLink(aAddr);
+		__ASSERT_ALWAYS(link, PANIC(KBTSecPanic, EBTSecPhysicalLinkMissing)); // If we've got an IO Capability Response we should have a link
+
+		if(link->IsPairable())
+			{
+			link->SetAuthenticationPending(ESimplePairingPending);
+			THCIOobDataPresence oobPresence = EOOBDataNotPresent;
+			if (link->HasRemoteOobData())
+				{
+				oobPresence = EOOBDataPresent;
+				}
+			THCIAuthenticationRequirement authReq = link->AuthenticationRequirement();
+			if(ConnectionsManager().IsAcceptPairedOnlyMode())
+				{
+				// in paired only mode, only MITM pairings are acceptable.
+				switch(authReq)
+					{
+				case EMitmNotReqNoBonding:
+				case EMitmReqNoBonding:
+					authReq = EMitmReqNoBonding;
+					break;
+				case EMitmNotReqDedicatedBonding:
+				case EMitmReqDedicatedBonding:
+					authReq = EMitmReqDedicatedBonding;
+					break;
+				case EMitmNotReqGeneralBonding:
+				case EMitmReqGeneralBonding:
+					authReq = EMitmReqGeneralBonding;
+					break;
+	            default:
+	                PANIC(KBTSecPanic, EBTSecUnexpectedIoCapability);
+	                break;
+					}
+				link->SetLocalMITM(ETrue);
+				}
+			else
+				{
+				link->SetLocalMITM(EFalse);
+				}
+		
+			TRAP_IGNORE(iCommandController->IOCapabilityRequestReplyL(aAddr, EIOCapsDisplayYesNo, oobPresence, authReq));
+			}
+		else
+			{
+			TRAP_IGNORE(iCommandController->IOCapabilityRequestNegativeReplyL(aAddr, EPairingNotAllowed));
+			}
+		}
+	}
+
+
+void CBTSecMan::IOCapabilityAskForResponse(const TBTDevAddr& aAddr,
+										THCIIoCapability aIOCapability,
+										THCIOobDataPresence aOOBDataPresent,
+										THCIAuthenticationRequirement aAuthenticationRequirements)
+	{
+	LOG_FUNC
+	
+	CPhysicalLink* link = iPhysicalLinksManager->FindPhysicalLink(aAddr);
+	__ASSERT_ALWAYS(link, PANIC(KBTSecPanic, EBTSecPhysicalLinkMissing)); // If we've got an IO Capability Response we should have a link
+	link->IOCapabilityAskForResponse(aIOCapability, aOOBDataPresent, aAuthenticationRequirements);
+	
+	CBTAccessRequester* requester = FindActiveAccessRequester(aAddr);
+	if(requester)
+		{
+		LOG(_L8("\tCBTAccessRequester FOUND!\n"));
+		TBTSecEventIoCapabilityResponse event(aIOCapability, aOOBDataPresent, aAuthenticationRequirements);
+		requester->SendEvent(event);
+		}
+	}
+
+void CBTSecMan::RemoteOOBDataRequest(const TBTDevAddr& aAddr)
+	{
+	LOG_FUNC
+	CBTAccessRequester* requester = FindActiveAccessRequester(aAddr);
+	if(requester)
+		{
+		LOG(_L8("\tCBTAccessRequester FOUND!\n"));
+		TBTSecEvent event(TBTSecEvent::ERemoteOOBDataRequested);
+		requester->SendEvent(event);
+		}
+
+	TBluetoothSimplePairingHash hashC;
+	TBluetoothSimplePairingRandomizer randomizerR;
+	if(OobDataManager().GetRemoteOobData(aAddr, hashC, randomizerR))
+		{
+		TRAP_IGNORE(iCommandController->RemoteOOBDataRequestReplyL(aAddr, hashC, randomizerR));
+		}
+	else
+		{
+		TRAP_IGNORE(iCommandController->RemoteOOBDataRequestNegativeReplyL(aAddr));
+		}
+	}
+
+void CBTSecMan::RemoteOOBDataRequestComplete(const TBTDevAddr& aAddr)
+	{
+	LOG_FUNC
+	CBTAccessRequester* requester = FindActiveAccessRequester(aAddr);
+	if(requester)
+		{
+		LOG(_L8("\tCBTAccessRequester FOUND!\n"));
+		TBTSecEvent event(TBTSecEvent::ERemoteOOBDataRequestComplete);
+		requester->SendEvent(event);
+		}
+	}
+
+void CBTSecMan::UserConfirmationRequest(const TBTDevAddr& aAddr, TUint32 aNumericValue)
+	{
+	LOG_FUNC
+	CBTAccessRequester* requester = FindActiveAccessRequester(aAddr);
+	if(requester)
+		{
+		LOG(_L8("\tCBTAccessRequester FOUND!\n"));
+		TBTSecEventUserConfirmationRequest event(aNumericValue);
+		requester->SendEvent(event);
+		}
+
+	if(requester != FindActiveAccessRequester(aAddr))
+		{
+		// The previous requester has been completed so move on.
+		TRAP_IGNORE(iCommandController->UserConfirmationRequestNegativeReplyL(aAddr));
+		return; // No passkey or comparison dialogs; disconnect instead
+		}
+
+	CPhysicalLink* link = iPhysicalLinksManager->FindPhysicalLink(aAddr);
+	__ASSERT_ALWAYS(link, PANIC(KBTSecPanic, EBTSecPhysicalLinkMissing));
+	__ASSERT_DEBUG(!link->InstanceNumericComparator(), PANIC(KBTSecPanic, EBTSecConnectionNumericComparisonTwice));
+	if(link->InstanceNumericComparator())
+		{
+		return;
+		}
+
+	if(link->AuthWithMITM())
+		{
+		TBool locallyInitiated; //Authentication
+		TBool strongKeyRequired;
+		TUint minPasskeyLength=0;
+
+		GetPassKeyLengthAndOriginator(aAddr, minPasskeyLength, locallyInitiated, strongKeyRequired);
+		TRAPD(err,link->NewNumericComparatorL(aAddr, *this, aNumericValue, locallyInitiated));
+		if(err)
+			{
+			if(requester)
+				{
+				requester->CompleteRequest(EBTSecManAccessDenied);
+				}
+			else
+				{
+				TRAP_IGNORE(iCommandController->UserConfirmationRequestNegativeReplyL(aAddr));
+				return;// No passkey or comparison dialogs; disconnect instead
+				}
+			}
+		}
+	else
+		{
+		// Just Work...
+		if(requester)
+			{
+			LOG(_L8("\tCBTAccessRequester FOUND!\n"));
+			TBTSecEventUserConfirmationComplete event(ETrue);
+			requester->SendEvent(event);
+			}
+
+		// note: -- check errors here
+		TRAP_IGNORE(iCommandController->UserConfirmationRequestReplyL(aAddr));
+		}
+	}
+
+void CBTSecMan::UserConfirmationComplete(const TBTDevAddr& aAddr, TBool aResult, TInt aError)
+	{
+	LOG_FUNC
+	CBTAccessRequester* requester = FindActiveAccessRequester(aAddr);
+	if (requester)
+		{
+		LOG(_L8("\tCBTAccessRequester FOUND!\n"));
+		if (aError == KErrNone)
+			{
+			TBTSecEventUserConfirmationComplete event(aResult);
+			requester->SendEvent(event);
+			}
+		else
+			{
+			TBTSecEventUserConfirmationComplete event(EFalse);  // Failed, so send EFalse
+			requester->SendEvent(event);
+			}
+		}
+
+	CPhysicalLink* link = iPhysicalLinksManager->FindPhysicalLink(aAddr);
+	__ASSERT_ALWAYS(link, PANIC(KBTSecPanic, EBTSecPhysicalLinkMissing));
+
+	if (aError!=KErrNone)
+		{
+		// there was an error somewhere a long the way so respond negatively
+		// note: -- check errors here
+		TRAP_IGNORE(iCommandController->UserConfirmationRequestNegativeReplyL(aAddr));
+		}
+	else
+		{
+		// got a result
+		if(aResult)
+			{
+			link->PinRequestSent();
+			// note: -- check errors here
+			TRAP_IGNORE(iCommandController->UserConfirmationRequestReplyL(aAddr));
+			}
+		else
+			{
+			// note: -- check errors here
+			TRAP_IGNORE(iCommandController->UserConfirmationRequestNegativeReplyL(aAddr));
+			}
+		}
+	link->DeleteNumericComparator();
+	}
+
+void CBTSecMan::PasskeyNotification(const TBTDevAddr& aAddr, TUint32 aPasskey)
+	{
+	LOG_FUNC
+	CBTAccessRequester* requester = FindActiveAccessRequester(aAddr);
+	if (requester)
+		{
+		LOG(_L8("\tCBTAccessRequester FOUND!\n"));
+		TBTSecEventPasskeyNotification event(aPasskey);
+		requester->SendEvent(event);
+		}
+
+	if(requester != FindActiveAccessRequester(aAddr))
+		{
+		// the previous requester has been completed so move on.
+		return;
+		}
+
+	CPhysicalLink* link = iPhysicalLinksManager->FindPhysicalLink(aAddr);
+	__ASSERT_ALWAYS(link, PANIC(KBTSecPanic, EBTSecPhysicalLinkMissing));
+
+	__ASSERT_DEBUG(!link->InstancePasskeyEntry(), PANIC(KBTSecPanic, EBTSecConnectionPasskeyNotificationTwice));
+
+	if(link->InstancePasskeyEntry())
+		{
+		return;
+		}
+
+	TBool locallyInitiated; //Authentication
+	TBool strongKeyRequired;
+	TUint minPasskeyLength=0;
+
+	GetPassKeyLengthAndOriginator(aAddr, minPasskeyLength, locallyInitiated, strongKeyRequired);
+	TRAPD(err, link->NewPasskeyEntryL(aAddr, *this,aPasskey, locallyInitiated));
+	if(err != KErrNone)
+		{
+		if(requester)
+			{
+			requester->CompleteRequest(EBTSecManAccessDenied);
+			}
+		}
+	}
+
+void CBTSecMan::KeypressNotification(const TBTDevAddr& aAddr, TUint8 aNotificationType)
+	{
+	LOG_FUNC
+	CBTAccessRequester* requester = FindActiveAccessRequester(aAddr);
+	if (requester)
+		{
+		LOG(_L8("\tCBTAccessRequester FOUND!\n"));
+		TBTSecEventKeypressEntry event(aNotificationType);
+		requester->SendEvent(event);
+		}
+
+	CPhysicalLink* link = iPhysicalLinksManager->FindPhysicalLink(aAddr);
+	__ASSERT_ALWAYS(link, PANIC(KBTSecPanic, EBTSecPhysicalLinkMissing));
+
+	if (link->InstancePasskeyEntry())
+		{
+		THCIPasskeyEntryNotificationType keyType = static_cast<THCIPasskeyEntryNotificationType>(aNotificationType);
+		link->PasskeyEntryKeyPressed(keyType);
+		}
+	}
+
+void CBTSecMan::PasskeyNotificationComplete(const TBTDevAddr& aAddr, TInt aError)
+	{
+	LOG_FUNC
+	CBTAccessRequester* requester = FindActiveAccessRequester(aAddr);
+	if (requester)
+		{
+		LOG(_L8("\tCBTAccessRequester FOUND!\n"));
+		TBTSecEvent event(TBTSecEvent::EKeypressComplete, aError);
+		requester->SendEvent(event);
+		}
+
+	CPhysicalLink* link = iPhysicalLinksManager->FindPhysicalLink(aAddr);
+	__ASSERT_ALWAYS(link, PANIC(KBTSecPanic, EBTSecPhysicalLinkMissing));
+	link->DeletePasskeyEntry();
+	}
+
+void CBTSecMan::AccessRequestComplete(CBTAccessRequester* aAccessRequester, TInt aResult)
+/**
+The access request has been fully completed.
+Delete the CBTAccessRequester that was handling the request.
+**/
+	{
+	LOG_FUNC
+	MAccessRequestResponseHandler& service = FinishAccessRequest(aAccessRequester);
+	// now tell the service
+	service.AccessRequestComplete(aResult);
+	}
+	
+MAccessRequestResponseHandler& CBTSecMan::FinishAccessRequest(CBTAccessRequester* aAccessRequester)
+	{
+	LOG_FUNC
+	TBTDevAddr addr = aAccessRequester->DeviceAddress();
+
+	// find the originating service *now*
+	MAccessRequestResponseHandler& service = const_cast<MAccessRequestResponseHandler&>
+											(aAccessRequester->ServiceRequester());
+
+	CBTAccessRequester* newRequester = NULL;
+	// Determine if this is an active access requester.
+	TInt ix = iAccessRequesters.Find(aAccessRequester);
+	if(ix >= 0)
+		{
+		// We need to replace this requester with a new one.
+		// Find the new access requester
+		ix = iPendingAccessRequesters.Find(addr, CompareAccessRequesterByBDAddr);
+		if(ix >= 0)
+			{
+			newRequester = iPendingAccessRequesters[ix];
+			iPendingAccessRequesters.Remove(ix);
+			iPendingAccessRequesters.GranularCompress();
+			}
+		// Remove bindings for the completed access requester (and substitute with new one if neccessary)
+		ix = iAccessRequesters.Find(aAccessRequester);
+		__ASSERT_DEBUG(ix >= 0, PANIC(KBTSecPanic, EBTSecAccessRequesterCompletedWhenNotActive));
+		if(newRequester)
+			{
+			iAccessRequesters[ix] = newRequester;
+			}
+		else
+			{
+			iAccessRequesters.Remove(ix);
+			}
+		}
+	else
+		{
+		// This must be a pending requester - in which case we just complete it.
+		__ASSERT_DEBUG(ix == KErrNotFound, PANIC(KBTSecPanic, EBTSecAccessRequesterShouldHaveNotBeenFound));
+		ix = iPendingAccessRequesters.Find(aAccessRequester);
+		__ASSERT_DEBUG(ix >= 0, PANIC(KBTSecPanic, EBTSecAccessRequesterShouldHaveBeenFound));
+		iPendingAccessRequesters.Remove(ix);
+		iPendingAccessRequesters.GranularCompress();
+		}
+
+	// Cleanup the access requester
+	delete aAccessRequester, aAccessRequester = NULL;
+
+	// Start the new requester if there is one.
+	if(newRequester)
+		{
+		newRequester->Start();
+		}
+	
+	return service;
+	}
+
+void CBTSecMan::SimplePairingComplete(const TBTDevAddr& aAddr, THCIErrorCode aError)
+	{
+	LOG_FUNC
+	TInt err = CHciUtil::SymbianErrorCode(aError);
+
+	CPhysicalLink* link = iPhysicalLinksManager->FindPhysicalLink(aAddr);
+	__ASSERT_ALWAYS(link, PANIC(KBTSecPanic, EBTSecPhysicalLinkMissing));
+
+	if (link->InstancePasskeyEntry() && link->IsPasskeyEntryActive())
+		{
+		link->CancelPasskeyEntry();
+		PasskeyNotificationComplete(aAddr, err);
+		}
+	if (link->InstanceNumericComparator() && link->IsNumericComparatorActive())
+		{
+		link->CancelNumericComparator();
+		UserConfirmationComplete(aAddr, EFalse, err);
+		}
+
+	iPhysicalLinksManager->SimplePairingComplete(aAddr, aError);
+
+ 	// Add result to list (always with HCI error code).
+ 	// Pairing results will be added only if pairing that involved numeric Comparison or passkey entry.
+ 	// It should not be added if the pairing completed using Just Works
+ 	if(link->AuthWithMITM())
+ 		{
+ 		iSimplePairingResultList->NewResult(aAddr, (KHCIErrorBase - aError));
+ 		}
+	}
+
+void CBTSecMan::AuthenticationComplete(const TBTDevAddr& aAddr, THCIErrorCode aError)
+	{
+	LOG_FUNC
+	iAuthenticationResultList->NewResult(aAddr, (KHCIErrorBase - aError));
+	}
+
+void CBTSecMan::AddNotifierRequestToQueL(CSecNotifierRequester& aRequest)
+/**
+Add notifier request to front of queue.  If there are no other requests already in the queue,
+initiate this request.
+**/
+	{
+	LOG_FUNC
+	TInt count = iNotifierRequesters.Count();
+	User::LeaveIfError(iNotifierRequesters.Insert(&aRequest,0));	//add to front of queue since requests are taken from the back
+	if(count == 0)	// ok since count was calculated before we inserted the new element
+		{
+		iActiveNotifierRequester = &aRequest;
+		aRequest.DoRequest();
+		}
+	else
+		{
+		LOG(_L8("\tSecman: Request queued, should start later..."));
+		}
+	}
+
+void CBTSecMan::RemoveNotifierRequestFromQue(CSecNotifierRequester& aRequest)
+/**
+Remove the request from the queue.  If aRequest is the currently active request then we can activate
+the next one in the queue.  Otherwise, aRequest is being deleted prematurely and we must simply
+remove it from the array.
+**/
+	{
+	LOG_FUNC
+	TInt count = iNotifierRequesters.Count();
+	TInt found = 0;
+	for (TInt i=(count-1); i>=0; i--)
+		{
+		if (iNotifierRequesters[i] == &aRequest)
+			{
+			found++;
+			iNotifierRequesters.Remove(i);
+			}
+		}
+	__ASSERT_DEBUG(found, PANIC(KBTSecPanic, EBTSecBadNotifierArray));
+
+	if(&aRequest == iActiveNotifierRequester)
+		{
+		//start the next request if there is one...
+		count = iNotifierRequesters.Count();
+		if (count > 0)
+			{
+			LOG(_L8("\tCBTSecMan - auto-starting next notifier request from queue"));
+			iActiveNotifierRequester = iNotifierRequesters[count-1];
+			iActiveNotifierRequester->DoRequest();
+			}
+		else
+			{
+			iActiveNotifierRequester = NULL;
+			}
+		}
+	}
+
+CBTAccessRequesterStateFactory* CBTSecMan::StateMachine()
+	{
+	LOG_FUNC
+	return iStateMachine;
+	}
+
+CSecNotifierRequester::CSecNotifierRequester(CBTSecMan& aSecMan)
+	: CActive(EPriorityStandard)
+	, iInquiryMgr(aSecMan.ConnectionsManager().LinkManagerProtocol().InquiryMgr())
+	, iSecMgr(aSecMan)
+	{
+	LOG_FUNC
+	}
+
+void CSecNotifierRequester::ConstructL(const TBTDevAddr& aAddr)
+	{
+	LOG_FUNC
+	LEAVEIFERRORL(iNotifier.Connect());
+
+	// find the name at this stage for this device - may not be there yet
+	iDeviceName = iInquiryMgr.DeviceNameFromCache(aAddr);
+
+	if (!iDeviceName || iDeviceName->Length() ==0)
+		{
+		// cache didn't have name - so we'll ask for it as a HR action
+		TRAP_IGNORE(iHR = iInquiryMgr.NewHostResolverL());
+		iHRNameRecord = new TNameRecord;
+
+		// ignore error - only an optimisation - don't want to leave if there's
+		// a problem doing this optimisation
+		if (iHR && iHRNameRecord)
+			{
+			iHR->SetNotify(this);
+
+			TInquirySockAddr i;
+			i.SetAction(KHostResName);
+			i.SetBTAddr(aAddr);
+			iHRNameRecord->iAddr = i;
+			iHR->GetByAddress(*iHRNameRecord);
+			}
+		}
+
+	iDevAddr = aAddr;
+
+	iSecMgr.AddNotifierRequestToQueL(*this);
+	iIsAddedToNotifierQue = ETrue;
+	}
+
+void CSecNotifierRequester::RemoveMyselfFromQue()
+	{
+	LOG_FUNC
+	iSecMgr.RemoveNotifierRequestFromQue(*this);
+	}
+
+CSecNotifierRequester::~CSecNotifierRequester()
+	{
+	LOG_FUNC
+	Cancel();
+
+	//remove ourself from the notifier que if we're still on it.
+	if (iIsAddedToNotifierQue)
+		{
+		RemoveMyselfFromQue();
+		iIsAddedToNotifierQue = EFalse;
+		}
+
+	delete iHR;
+	delete iHRNameRecord;
+
+	iNotifier.Close();
+	}
+
+void CSecNotifierRequester::QueryComplete(TInt aErr)
+	{
+	LOG_FUNC
+	if (aErr==KErrNone && iHRNameRecord)
+		{
+		// now have device name - update notifiers
+		// we do have a copy of the name - but it is now wide :-|
+		// and also we have iDeviceName that is still NULL, so best bet is
+		// to just set our pointer and use the cache one (which we *know* is there!)
+		TBTDevAddr a = TBTSockAddr::Cast(iHRNameRecord->iAddr).BTAddr();
+		iDeviceName = iInquiryMgr.DeviceNameFromCache(a);
+		DoUpdateNotifier();
+		}
+
+	delete iHRNameRecord;
+	iHRNameRecord = NULL;
+	}
+
+void CSecNotifierRequester::HandleTimeout()
+	{
+	LOG_FUNC
+	// A timer user should implement this function
+	__ASSERT_DEBUG(EFalse, PANIC(KBTSecPanic, EBTSecNotifierRequesterUsingTimerWithoutHandling));
+	}
+
+
+
+CSecNotifierRequesterTimer* CSecNotifierRequesterTimer::NewL(CSecNotifierRequester& aObserver)
+	{
+	LOG_STATIC_FUNC
+	CSecNotifierRequesterTimer* self = new(ELeave) CSecNotifierRequesterTimer(aObserver);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CSecNotifierRequesterTimer::CSecNotifierRequesterTimer(CSecNotifierRequester& aObserver)
+	: CTimer(EPriorityStandard)
+	, iObserver(aObserver)
+	{
+	LOG_FUNC
+	CActiveScheduler::Add(this);
+	}
+
+CSecNotifierRequesterTimer::~CSecNotifierRequesterTimer()
+	{
+	LOG_FUNC
+	Cancel();
+	}
+
+void CSecNotifierRequesterTimer::Start(TTimeIntervalMicroSeconds32 aTimeout)
+	{
+	LOG_FUNC
+	After(aTimeout);
+	}
+
+void CSecNotifierRequesterTimer::ConstructL()
+	{
+	LOG_FUNC
+	CTimer::ConstructL();
+	}
+
+void CSecNotifierRequesterTimer::RunL()
+	{
+	LOG_FUNC
+	iObserver.HandleTimeout();
+	}
+
+
+//------------------------------------------------------------------------//
+//class CBTPinRequester
+//------------------------------------------------------------------------//
+
+
+CBTPinRequester* CBTPinRequester::NewL(const TBTDevAddr& aAddr,
+									   MPINCodeResponseHandler& aRequester,
+									   CBTSecMan& aSecMan,
+									   TUint aPasskeyMinLength,
+									   TBool aInternallyInitiated,
+									   TBool aStrongKeyRequired,
+									   TUint aRecommendedPasskeyMinLength)
+	{
+	LOG_STATIC_FUNC
+	CBTPinRequester* s = CBTPinRequester::NewLC(aAddr, aRequester, aSecMan,
+	                                            aPasskeyMinLength, aInternallyInitiated, aStrongKeyRequired, aRecommendedPasskeyMinLength);
+	CleanupStack::Pop(s);
+	return s;
+	}
+
+CBTPinRequester* CBTPinRequester::NewLC(const TBTDevAddr& aAddr,
+										MPINCodeResponseHandler& aRequester,
+										CBTSecMan& aSecMan,
+										TUint aPasskeyMinLength,
+										TBool aInternallyInitiated,
+										TBool aStrongKeyRequired,
+										TUint aRecommendedPasskeyMinLength)
+	{
+	LOG_STATIC_FUNC
+	CBTPinRequester* s = new(ELeave) CBTPinRequester(aRequester, aSecMan,
+	                                                 aPasskeyMinLength, aInternallyInitiated, aStrongKeyRequired, aRecommendedPasskeyMinLength);
+	CleanupStack::PushL(s);
+	s->ConstructL(aAddr);
+	return s;
+	}
+
+CBTPinRequester::CBTPinRequester(MPINCodeResponseHandler& aHandler,
+								 CBTSecMan& aSecMan,
+								 TUint aPasskeyMinLength,
+								 TBool aInternallyInitiated,
+								 TBool aStrongKeyRequired,
+								 TUint aRecommendedPasskeyMinLength)
+	: CSecNotifierRequester(aSecMan)
+	, iHandler(&aHandler)
+	, iSecMan(aSecMan)
+	, iPasskeyMinLength(aPasskeyMinLength)
+	, iInternallyInitiated(aInternallyInitiated)
+	, iStrongKeyRequired(aStrongKeyRequired)
+	, iRecommendedPasskeyMinLength(aRecommendedPasskeyMinLength)
+	{
+	LOG_FUNC
+	CActiveScheduler::Add(this);
+	}
+
+void CBTPinRequester::ConstructL(const TBTDevAddr& aAddr)
+	{
+	LOG_FUNC
+	iTimer = CSecNotifierRequesterTimer::NewL(*this);
+	CSecNotifierRequester::ConstructL(aAddr);
+	}
+
+CBTPinRequester::~CBTPinRequester()
+	{
+	LOG_FUNC
+	delete iTimer;
+	Cancel();
+	CBase::Delete(iUpdateNotifier.iNameUpdater); // Delete through the CBase virtual destructor.
+	}
+
+
+void CBTPinRequester::UpdateHandler(MPINCodeResponseHandler& aNewHandler)
+	{
+	LOG_FUNC
+	iHandler = &aNewHandler;
+	}
+
+
+void CBTPinRequester::DoUpdateNotifier()
+	{
+	LOG_FUNC
+ 	if(IsActive())
+ 		{
+ 		switch(iNotifierType)
+	 		{
+	 	case ESspAwareNotifier:
+	 		UpdateSspAwareNotifier();
+	 		break;
+	 	case ELegacyNotifier:
+	 		UpdateLegacyNotifier();
+	 		break;
+	 	default:
+			DEBUG_PANIC_LINENUM
+	 		break;
+	 		}
+		}
+	}
+
+void CBTPinRequester::UpdateSspAwareNotifier()
+	{
+	LOG_FUNC
+	if(!iUpdateNotifier.iNameUpdater)
+		{
+		//Create a new CSecNotifierUpdateAO object
+		TRAP_IGNORE(iUpdateNotifier.iNameUpdater = CSecNotifierUpdateAO<TBTDeviceNameUpdateParamsPckg>::NewL(iNotifier, KBTPinCodeEntryNotifierUid));
+		}
+	if(iUpdateNotifier.iNameUpdater)
+		{
+		TBTDeviceName deviceName(KNullDesC);
+		TInt err = KErrNotFound;
+		if(iDeviceName)
+			{
+			TRAP(err, deviceName = BTDeviceNameConverter::ToUnicodeL(*iDeviceName)); // Best effort attempt.
+			}
+		TBTDeviceNameUpdateParamsPckg pckg = TBTDeviceNameUpdateParams(deviceName, err);
+		iUpdateNotifier.iNameUpdater->DoUpdate(pckg);
+		}
+	}
+
+void CBTPinRequester::UpdateLegacyNotifier()
+	{
+	LOG_FUNC
+	if(!iUpdateNotifier.iLegacyUpdater)
+		{
+		//Create a new CSecNotifierUpdateAO object
+		TRAP_IGNORE(iUpdateNotifier.iLegacyUpdater = CSecNotifierUpdateAO<TBTNotifierUpdateParamsPckg>::NewL(iNotifier, KBTManPinNotifierUid));
+		}
+	if(iUpdateNotifier.iLegacyUpdater)
+		{
+		TBTNotifierUpdateParamsPckg pckg;
+		if(iDeviceName)
+			{
+			TRAPD(err, pckg().iName = BTDeviceNameConverter::ToUnicodeL(*iDeviceName));
+			pckg().iResult = err; 	// Error code can be KErrNone
+			if(err != KErrNone)
+				{
+				pckg().iName = KNullDesC;
+				}
+			}
+		else
+			{
+			pckg().iName = KNullDesC;
+			pckg().iResult = KErrNotFound;
+			}
+
+		iUpdateNotifier.iLegacyUpdater->DoUpdate(pckg);
+		}
+	}
+
+void CBTPinRequester::DoRequest()
+	{
+	LOG_FUNC
+	// The initial request for a PIN code entry dialog (that is SSP aware).  If this fails
+	// we will attempt to use the legacy notifier.
+
+	TBTDeviceName deviceName(KNullDesC);
+	if(iDeviceName)
+		{
+		TRAP_IGNORE(deviceName = BTDeviceNameConverter::ToUnicodeL(*iDeviceName)); // Best effort attempt.
+		}
+
+	iPinCodeEntryParamsPckg
+		= TBTPinCodeEntryNotifierParams(iDevAddr, deviceName, iPasskeyMinLength, iInternallyInitiated, iStrongKeyRequired, iRecommendedPasskeyMinLength);
+
+	iNotifierType = ESspAwareNotifier;
+	iNotifier.StartNotifierAndGetResponse(iStatus, KBTPinCodeEntryNotifierUid, iPinCodeEntryParamsPckg, iPassKey);
+	iTimer->Start(KPinRequesterTimeout);
+	SetActive();
+	}
+
+void CBTPinRequester::FriendlyNameRetrieved(const TDesC& /*aName*/, TInt /*aResult*/)
+	{
+	LOG_FUNC
+	// do nothing for now as it is not used anywhere
+	__ASSERT_DEBUG(0, PANIC(KBTSecPanic, EBTSecNotImplemented));
+	}
+
+
+void CBTPinRequester::DoCancel()
+	{
+	LOG_FUNC
+	iTimer->Cancel();
+	// Cancel the appropriate notifier.
+	switch(iNotifierType)
+		{
+	case ESspAwareNotifier:
+		iNotifier.CancelNotifier(KBTPinCodeEntryNotifierUid);
+		if(iUpdateNotifier.iNameUpdater)
+			{
+			iUpdateNotifier.iNameUpdater->Cancel();
+			}
+		break;
+	case ELegacyNotifier:
+		iNotifier.CancelNotifier(KBTManPinNotifierUid);
+		if(iUpdateNotifier.iLegacyUpdater)
+			{
+			iUpdateNotifier.iNameUpdater->Cancel();
+			}
+		break;
+	default:
+		DEBUG_PANIC_LINENUM
+		break;
+		}
+	iNotifierType = EInvalid;
+	}
+
+void CBTPinRequester::RunL()
+	{
+	LOG_FUNC
+	iTimer->Cancel();
+	switch(iNotifierType)
+		{
+	case ESspAwareNotifier:
+		HandleSspAwareNotifierL();
+		break;
+	case ELegacyNotifier:
+		HandleLegacyNotifierL();
+		break;
+	default:
+		DEBUG_PANIC_LINENUM
+		break;
+		}
+	}
+
+
+void CBTPinRequester::HandleSspAwareNotifierL()
+	{
+	LOG_FUNC
+	ASSERT_DEBUG(iNotifierType == ESspAwareNotifier);
+
+	//got a PIN or error, so we are finished with this notifier.
+	iNotifier.CancelNotifier(KBTPinCodeEntryNotifierUid);
+
+	TInt err = iStatus.Int();
+
+	if(err == KErrNotFound)
+		{
+		// Failed to find the SSP aware notifier, as such we should attempt to use
+		// the legacy notifier.
+
+		// First we prevent any updaters to the new notifier type.
+		delete iUpdateNotifier.iNameUpdater;
+		iUpdateNotifier.iNameUpdater = NULL;
+
+		// Next we notify using the legacy notifier.
+		iLegacyPinCodeParamsPckg().iBDAddr = iDevAddr;
+		if(iDeviceName)
+			{
+			TRAPD(err, iLegacyPinCodeParamsPckg().iName = BTDeviceNameConverter::ToUnicodeL(*iDeviceName));
+			if(err != KErrNone)
+				{
+				iLegacyPinCodeParamsPckg().iName = KNullDesC;
+				}
+			}
+		else
+			{
+			iLegacyPinCodeParamsPckg().iName = KNullDesC;
+			}
+		if(iStrongKeyRequired)
+			{
+			// As we cannot signal this any other way if a strong key is required, then we must
+			// force a long passkey length.  This has potential IOP issues.
+			iLegacyPinCodeParamsPckg().iPasskeyMinLength = KHCIPINCodeSize;
+			}
+		else
+			{
+			iLegacyPinCodeParamsPckg().iPasskeyMinLength = iPasskeyMinLength;
+			}
+		iLegacyPinCodeParamsPckg().iLocallyInitiated = iInternallyInitiated;
+
+		iNotifierType = ELegacyNotifier;
+		iNotifier.StartNotifierAndGetResponse(iStatus, KBTManPinNotifierUid, iLegacyPinCodeParamsPckg, iPassKey);
+		iTimer->Start(KPinRequesterTimeout); // restart
+		SetActive();
+		}
+	else
+		{
+		// The SSP aware PIN code entry notifier was found...
+
+		//remove ourself from the notifier que, allowing the next notifier to be activated
+		iSecMan.RemoveNotifierRequestFromQue(*this);
+		iIsAddedToNotifierQue = EFalse;
+
+		iNotifierType = EInvalid; // whatever happened we're done.
+		if(err != KErrNone)
+			{
+			// The notifier signalled some other error - so be unpairable.
+			iHandler->PINCodeRequestNegativeReply(iDevAddr);
+			}
+		else
+			{
+			// got a PIN
+			iHandler->PINCodeRequestReply(iDevAddr, iPassKey);
+			}
+		}
+	}
+
+
+void CBTPinRequester::HandleLegacyNotifierL()
+	{
+	LOG_FUNC
+	ASSERT_DEBUG(iNotifierType == ELegacyNotifier);
+
+	//got a PIN or error, so finish off: unload the plugin
+	iNotifier.CancelNotifier(KBTManPinNotifierUid);
+
+	//remove ourself from the notifier que, allowing the next notifier to be activated
+	RemoveMyselfFromQue();
+	iIsAddedToNotifierQue = EFalse;
+
+	iNotifierType = EInvalid; // whatever happened we're done.
+	if (iStatus.Int())
+		{
+		// it failed - be unpairable
+		iHandler->PINCodeRequestNegativeReply(iDevAddr);
+		}
+	else
+		{
+		// got a PIN
+		iHandler->PINCodeRequestReply(iDevAddr, iPassKey);
+		}
+	}
+
+
+TInt CBTPinRequester::RunError(TInt IF_FLOGGING(aError))
+	{
+	LOG_FUNC
+	LOG1(_L8("\tCBTPinRequester::RunError(%d)\n"), aError);
+
+	switch(iNotifierType)
+		{
+	case ESspAwareNotifier:
+	case ELegacyNotifier:
+		break;
+	default:
+		DEBUG_PANIC_LINENUM
+		break;
+		}
+
+	iNotifierType = EInvalid;
+	iHandler->PINCodeRequestNegativeReply(iDevAddr);
+	return KErrNone;
+	}
+
+void CBTPinRequester::HandleTimeout()
+	{
+	LOG_FUNC
+	// Cancel the request...
+	Cancel();
+	// Complete with a -ve reply
+	iHandler->PINCodeRequestNegativeReply(iDevAddr);
+	}
+
+//------------------------------------------------------------------------//
+//class CBTAuthorisor
+//------------------------------------------------------------------------//
+
+CBTAuthorisor* CBTAuthorisor::NewL(CBTAccessRequester& aParent, CBTSecMan& aSecMan, TUid aServiceUID)
+	{
+	LOG_STATIC_FUNC
+	CBTAuthorisor* s = CBTAuthorisor::NewLC(aParent, aSecMan, aServiceUID);
+	CleanupStack::Pop(s);
+	return s;
+	}
+
+CBTAuthorisor* CBTAuthorisor::NewLC(CBTAccessRequester& aParent, CBTSecMan& aSecMan, TUid aServiceUID)
+	{
+	LOG_STATIC_FUNC
+	CBTAuthorisor* s = new(ELeave) CBTAuthorisor(aParent, aSecMan, aServiceUID);
+	CleanupStack::PushL(s);
+	s->ConstructL(aParent.DeviceAddress());
+	return s;
+	}
+
+CBTAuthorisor::CBTAuthorisor(CBTAccessRequester& aAccessRequester, CBTSecMan& aSecMan, TUid aServiceUID) :
+	CSecNotifierRequester(aSecMan),iAccessRequester(aAccessRequester)
+	{
+	LOG_FUNC
+	iAuthorisationParamsPckg().iUid = aServiceUID;
+	CActiveScheduler::Add(this);
+	}
+
+CBTAuthorisor::~CBTAuthorisor()
+	{
+	LOG_FUNC
+	Cancel();
+	delete iUpdateNotifierAO;
+	}
+
+
+void CBTAuthorisor::DoUpdateNotifier()
+	{
+	LOG_FUNC
+	if(IsActive())
+		{
+		if(!iUpdateNotifierAO)
+			{
+			//Create a new CSecNotifierUpdateAO object
+			TRAP_IGNORE(iUpdateNotifierAO = CSecNotifierUpdateAO<TBTNotifierUpdateParamsPckg>::NewL(iNotifier, KBTManAuthNotifierUid));
+			}
+
+		if( (iUpdateNotifierAO) && (!iUpdateNotifierAO->IsActive()) )
+			{
+			TBTNotifierUpdateParamsPckg pckg;
+			if(iDeviceName)
+				{
+				TRAPD(err, pckg().iName = BTDeviceNameConverter::ToUnicodeL(*iDeviceName));
+				pckg().iResult = err; 	// Error code can be KErrNone
+				if (err!=KErrNone)
+					{
+					pckg().iName = KNullDesC;
+					}
+				}
+			else
+				{
+				pckg().iName = KNullDesC;
+				pckg().iResult = KErrNotFound;
+				}
+
+			iUpdateNotifierAO->DoUpdate(pckg);
+			}
+		}
+	}
+
+void CBTAuthorisor::DoRequest()
+/**
+Start the RNotifier plugin that deals with authorisation.
+**/
+	{
+	LOG_FUNC
+	TInt err(KErrNone);
+
+	if (iDeviceName)
+		{
+		TRAP(err, iAuthorisationParamsPckg().iName = BTDeviceNameConverter::ToUnicodeL(*iDeviceName));
+		if (err!=KErrNone)
+			{
+			iAuthorisationParamsPckg().iName = KNullDesC;
+			}
+		}
+	else
+		{
+		iAuthorisationParamsPckg().iName = KNullDesC;
+		}
+	iAuthorisationParamsPckg().iBDAddr  = iDevAddr;
+
+	TBTSecEvent event(TBTSecEvent::EAuthorisationRequested);
+	iAccessRequester.SendEvent(event);
+
+	iNotifier.StartNotifierAndGetResponse(iStatus, KBTManAuthNotifierUid, iAuthorisationParamsPckg, iResultPckg);
+	SetActive();
+	}
+
+
+void CBTAuthorisor::DoCancel()
+	{
+	LOG_FUNC
+	iNotifier.CancelNotifier(KBTManAuthNotifierUid);
+	}
+
+void CBTAuthorisor::RunL()
+	{
+	LOG_FUNC
+
+	// unload the plugin
+	iNotifier.CancelNotifier(KBTManAuthNotifierUid);
+
+	// remove ourself from the notifier queue, allowing the next notifier to be activated
+	RemoveMyselfFromQue();
+	iIsAddedToNotifierQue = EFalse;
+
+	// notify owner of completion
+	LOG1(_L8("\tCBTAuthorisor::RunL(): iStatus = %d\n"), iStatus.Int());
+	if (iStatus.Int() != KErrNone)
+		{
+		// If anything went wrong, then deny access
+		TBTSecEventAuthorisationComplete event(EFalse);
+		iAccessRequester.SendEvent(event);
+		}
+	else
+		{
+		// otherwise allow/deny depends on the notifier
+		TBTSecEventAuthorisationComplete event(iResultPckg());
+		iAccessRequester.SendEvent(event);
+		}
+	}
+
+TInt CBTAuthorisor::RunError(TInt aError)
+	{
+	LOG_FUNC
+	//will never get called as our RunL doesn't leave.
+	LOG1(_L8("\tCBTAuthorisor::RunError(%d)\n"), aError);
+	return aError;
+	}
+
+
+//------------------------------------------------------------------------//
+//class CSecNotifierUpdateAO
+//------------------------------------------------------------------------//
+
+template <class T>
+CSecNotifierUpdateAO<T>* CSecNotifierUpdateAO<T>::NewL(RNotifier& aNotifier, TUid aNotifierUid)
+	{
+	LOG_STATIC_FUNC
+	CSecNotifierUpdateAO* s = CSecNotifierUpdateAO::NewLC(aNotifier, aNotifierUid);
+	CleanupStack::Pop(s);
+	return s;
+	}
+
+template <class T>
+CSecNotifierUpdateAO<T>* CSecNotifierUpdateAO<T>::NewLC(RNotifier& aNotifier, TUid aNotifierUid)
+	{
+	LOG_STATIC_FUNC
+	CSecNotifierUpdateAO* s = new(ELeave) CSecNotifierUpdateAO();
+	CleanupStack::PushL(s);
+	s->ConstructL(aNotifier, aNotifierUid);
+	return s;
+	}
+
+template <class T>
+CSecNotifierUpdateAO<T>::CSecNotifierUpdateAO()
+	: CActive(EPriorityStandard)
+	{
+	LOG_FUNC
+	CActiveScheduler::Add(this);
+	}
+
+template <class T>
+CSecNotifierUpdateAO<T>::~CSecNotifierUpdateAO()
+	{
+	LOG_FUNC
+	Cancel();
+	}
+
+template <class T>
+void CSecNotifierUpdateAO<T>::ConstructL(RNotifier& aNotifier, TUid aNotifierUid)
+	{
+	LOG_FUNC
+	iNotifier = aNotifier;
+	iNotifierUid = aNotifierUid;
+	}
+
+
+template <class T>
+void CSecNotifierUpdateAO<T>::DoUpdate(const T& aPckg)
+	{
+	LOG_FUNC
+	if (IsActive())
+		{
+		TRAP_IGNORE(iPckgQueue.AppendL(aPckg));  // An update will be missed if OOM
+		}
+	else
+		{
+		//Retain a copy so that it does not go out of memory scope
+		iPckg = aPckg;
+
+		// We're not expecting an answer... but we want to use an asynchronous API
+		// and so we need to "get a response"
+		iNotifier.UpdateNotifierAndGetResponse(iStatus, iNotifierUid, iPckg, iAnswer);
+		SetActive();
+		}
+	}
+
+template <class T>
+void CSecNotifierUpdateAO<T>::DoUpdateSynchronous(const T& aPckg)
+	{
+	LOG_FUNC
+	//we're not expecting an answer so discard error as well...
+	TInt err = iNotifier.UpdateNotifier(iNotifierUid, aPckg, iAnswer);
+	LOG1(_L8("\tCSecNotifierUpdateAO::DoUpdateSynchronous error (%d)\n"), err);
+	}
+
+
+template <class T>
+void CSecNotifierUpdateAO<T>::RunL()
+	{
+	LOG_FUNC
+	//We can't do anything if an error is returned - just make sure we haven't done anything stupid...
+	__ASSERT_DEBUG((iStatus==KErrNone)||(iStatus==KErrNoMemory)||(iStatus==KErrNotReady), PANIC(KBTSecPanic, EBTSecBadNotifierUpdate));
+	if (iPckgQueue.Count() != 0)
+		{
+		iPckg = iPckgQueue[0];
+		iPckgQueue.Remove(0);
+		iNotifier.UpdateNotifierAndGetResponse(iStatus, iNotifierUid, iPckg, iAnswer);
+		SetActive();
+		}
+	}
+
+template <class T>
+void CSecNotifierUpdateAO<T>::DoCancel()
+	{
+	LOG_FUNC
+	iPckgQueue.Close();
+	iNotifier.CancelNotifier(iNotifierUid); // no other API on Notifier to just cancel the update; but typically we'll want to cancel the whole notifier at this point(?)
+	}
+
+template <class T>
+TInt CSecNotifierUpdateAO<T>::RunError(TInt IF_FLOGGING(aError))
+	{
+	LOG_FUNC
+	LOG1(_L8("\tCSecNotifierUpdateAO::RunError(%d)\n"), aError);
+	return KErrNone;
+	}
+
+
+
+//------------------------------------------------------------------------//
+//class CBTNumericComparator
+//------------------------------------------------------------------------//
+CBTNumericComparator* CBTNumericComparator::NewL(const TBTDevAddr aAddr,
+												 CBTSecMan& aSecMan,
+												 TUint32 aNumericValue,
+												 TBTNumericComparisonParams::TComparisonScenario aComparisonScenario, 
+												 TBool aInternallyInitiated)
+	{
+	LOG_STATIC_FUNC
+	CBTNumericComparator* s = CBTNumericComparator::NewLC(aAddr, aSecMan, aNumericValue, aComparisonScenario, aInternallyInitiated);
+	CleanupStack::Pop(s);
+	return s;
+	}
+
+CBTNumericComparator* CBTNumericComparator::NewLC(const TBTDevAddr aAddr,
+												  CBTSecMan& aSecMan,
+												  TUint32 aNumericValue,
+												  TBTNumericComparisonParams::TComparisonScenario aComparisonScenario, 
+												  TBool aInternallyInitiated)
+	{
+	LOG_STATIC_FUNC
+	CBTNumericComparator* s = new(ELeave) CBTNumericComparator(aSecMan, aNumericValue, aComparisonScenario, aInternallyInitiated);
+	CleanupStack::PushL(s);
+	s->ConstructL(aAddr);
+	return s;
+	}
+
+CBTNumericComparator::CBTNumericComparator(CBTSecMan& aSecMan, TUint32 aNumericValue, TBTNumericComparisonParams::TComparisonScenario aComparisonScenario, TBool aInternallyInitiated)
+	: CSecNotifierRequester(aSecMan)
+	, iSecMan(aSecMan)
+	, iNumericValue(aNumericValue)
+	, iComparisonScenario(aComparisonScenario)
+	, iInternallyInitiated(aInternallyInitiated)
+	{
+	LOG_FUNC
+	CActiveScheduler::Add(this);
+	}
+
+CBTNumericComparator::~CBTNumericComparator()
+	{
+	LOG_FUNC
+	Cancel();
+	delete iNameUpdater;
+	}
+
+
+void CBTNumericComparator::DoUpdateNotifier()
+	{
+	LOG_FUNC
+	if(IsActive())
+		{
+		if(!iNameUpdater)
+			{
+			//Create a new CSecNotifierUpdateAO object
+			TRAP_IGNORE(iNameUpdater = CSecNotifierUpdateAO<TBTDeviceNameUpdateParamsPckg>::NewL(iNotifier, KBTNumericComparisonNotifierUid));
+			}
+		if(iNameUpdater)
+			{
+			TBTDeviceName deviceName(KNullDesC);
+			TInt err = KErrNotFound;
+			if(iDeviceName)
+				{
+				TRAP(err, deviceName = BTDeviceNameConverter::ToUnicodeL(*iDeviceName)); // Best effort attempt.
+				}
+
+			TBTDeviceNameUpdateParamsPckg pckg = TBTDeviceNameUpdateParams(deviceName, err);
+			iNameUpdater->DoUpdate(pckg);
+			}
+		}
+	}
+
+void CBTNumericComparator::DoRequest()
+/**
+Start the RNotifier plugin that deals with authorisation.
+**/
+	{
+	LOG_FUNC
+	TInt err(KErrNone);
+
+	TBTDeviceName deviceName;
+
+	if (iDeviceName)
+		{
+		TRAP(err, deviceName = BTDeviceNameConverter::ToUnicodeL(*iDeviceName));
+		if (err!=KErrNone)
+			{
+			deviceName = KNullDesC;
+			}
+		}
+	else
+		{
+		deviceName = KNullDesC;
+		}
+	iNumericComparisonParamsPckg = TBTNumericComparisonParams(iDevAddr, deviceName, iNumericValue, iComparisonScenario, iInternallyInitiated);
+
+	iNotifier.StartNotifierAndGetResponse(iStatus, KBTNumericComparisonNotifierUid, iNumericComparisonParamsPckg, iResultPckg);
+	SetActive();
+	}
+
+
+void CBTNumericComparator::DoCancel()
+	{
+	LOG_FUNC
+	iNotifier.CancelNotifier(KBTNumericComparisonNotifierUid);
+	if(iNameUpdater)
+		{
+		iNameUpdater->Cancel();
+		}
+	}
+
+void CBTNumericComparator::RunL()
+	{
+	LOG_FUNC
+	// got an answer so unload the notifier
+	iNotifier.CancelNotifier(KBTNumericComparisonNotifierUid);
+
+	//remove ourself from the notifier que, allowing the next notifier to be activated
+	RemoveMyselfFromQue();
+	iIsAddedToNotifierQue = EFalse;
+
+	__ASSERT_DEBUG(iNumericComparisonParamsPckg().DeviceAddress() == iDevAddr, PANIC(KBTSecPanic, EBTSecBadDeviceAddress));
+
+	iSecMan.UserConfirmationComplete(iDevAddr, iResultPckg(), iStatus.Int());
+	}
+
+TInt CBTNumericComparator::RunError(TInt aError)
+	{
+	LOG_FUNC
+	//will never get called as our RunL doesn't leave.
+	LOG1(_L8("\tCBTNumericComparator::RunError(%d)\n"), aError);
+	return aError;
+	}
+
+
+//------------------------------------------------------------------------//
+//class CBTPasskeyEntry
+//------------------------------------------------------------------------//
+CBTPasskeyEntry* CBTPasskeyEntry::NewL(const TBTDevAddr aAddr,
+												 CBTSecMan& aSecMan,
+												 TUint32 aNumericValue,
+												 TBool aInternallyInitiated)
+	{
+	LOG_STATIC_FUNC
+	CBTPasskeyEntry* s = CBTPasskeyEntry::NewLC(aAddr, aSecMan, /*aAccessRequester,*/ aNumericValue, aInternallyInitiated);
+	CleanupStack::Pop(s);
+	return s;
+	}
+
+CBTPasskeyEntry* CBTPasskeyEntry::NewLC(const TBTDevAddr aAddr,
+												  CBTSecMan& aSecMan,
+												  TUint32 aNumericValue,
+												  TBool aInternallyInitiated)
+	{
+	LOG_STATIC_FUNC
+	CBTPasskeyEntry* s = new(ELeave) CBTPasskeyEntry(aSecMan, /*aAccessRequester,*/ aNumericValue, aInternallyInitiated);
+	CleanupStack::PushL(s);
+	s->ConstructL(aAddr);
+	return s;
+	}
+
+CBTPasskeyEntry::CBTPasskeyEntry(CBTSecMan& aSecMan,
+								 TUint32 aNumericValue,
+								 TBool aInternallyInitiated)
+	: CSecNotifierRequester(aSecMan)
+	, iSecMan(aSecMan)
+	, iNumericValue(aNumericValue)
+	, iInternallyInitiated(aInternallyInitiated)
+	{
+	LOG_FUNC
+	CActiveScheduler::Add(this);
+	}
+
+CBTPasskeyEntry::~CBTPasskeyEntry()
+	{
+	LOG_FUNC
+	Cancel();
+	delete iKeypressUpdater;
+	delete iNameUpdater;
+	}
+
+void CBTPasskeyEntry::KeyPressed(THCIPasskeyEntryNotificationType aKeyType)
+	{
+	LOG_FUNC
+	if(IsActive())
+		{
+		if(!iKeypressUpdater)
+			{
+			//Create a new CSecNotifierUpdateAO object
+			TRAP_IGNORE(iKeypressUpdater = CSecNotifierUpdateAO<TBTPasskeyDisplayUpdateParamsPckg>::NewL(iNotifier, KBTPasskeyDisplayNotifierUid));
+			}
+		if (iKeypressUpdater)
+			{
+			TBTPasskeyDisplayUpdateParamsPckg pckg = TBTPasskeyDisplayUpdateParams(aKeyType);
+			iKeypressUpdater->DoUpdate(pckg);
+			}
+		}
+	}
+
+void CBTPasskeyEntry::DoUpdateNotifier()
+	{
+	LOG_FUNC
+	if(IsActive())
+		{
+		if(!iNameUpdater)
+			{
+			//Create a new CSecNotifierUpdateAO object
+			TRAP_IGNORE(iNameUpdater = CSecNotifierUpdateAO<TBTDeviceNameUpdateParamsPckg>::NewL(iNotifier, KBTPasskeyDisplayNotifierUid));
+			}
+		if(iNameUpdater)
+			{
+			TBTDeviceName deviceName(KNullDesC);
+			TInt err = KErrNotFound;
+			if(iDeviceName)
+				{
+				TRAP(err, deviceName = BTDeviceNameConverter::ToUnicodeL(*iDeviceName)); // Best effort attempt.
+				}
+			TBTDeviceNameUpdateParamsPckg pckg = TBTDeviceNameUpdateParams(deviceName, err);
+			iNameUpdater->DoUpdate(pckg);
+			}
+		}
+	}
+
+void CBTPasskeyEntry::DoRequest()
+/**
+Start the RNotifier plugin that deals with authorisation.
+**/
+	{
+	LOG_FUNC
+	TBTDeviceName deviceName;
+
+	if (iDeviceName)
+		{
+		TRAPD(err, deviceName = BTDeviceNameConverter::ToUnicodeL(*iDeviceName));
+		if (err!=KErrNone)
+			{
+			deviceName = KNullDesC;
+			}
+		}
+	else
+		{
+		deviceName = KNullDesC;
+		}
+	iPasskeyDisplayParamsPckg = TBTPasskeyDisplayParams(iDevAddr, deviceName, iNumericValue, iInternallyInitiated);
+
+	iNotifier.StartNotifierAndGetResponse(iStatus, KBTPasskeyDisplayNotifierUid, iPasskeyDisplayParamsPckg, iResultPckg);
+	SetActive();
+	}
+
+
+void CBTPasskeyEntry::DoCancel()
+	{
+	LOG_FUNC
+	iNotifier.CancelNotifier(KBTPasskeyDisplayNotifierUid);
+	if(iKeypressUpdater)
+		{
+		iKeypressUpdater->Cancel();
+		}
+	if(iNameUpdater)
+		{
+		iNameUpdater->Cancel();
+		}
+	}
+
+void CBTPasskeyEntry::RunL()
+	{
+	LOG_FUNC
+	//got a PIN or error, so finish off: unload the plugin
+	iNotifier.CancelNotifier(KBTPasskeyDisplayNotifierUid);
+
+	//remove ourself from the notifier que, allowing the next notifier to be activated
+	RemoveMyselfFromQue();
+	iIsAddedToNotifierQue = EFalse;
+
+	__ASSERT_DEBUG(iPasskeyDisplayParamsPckg().DeviceAddress() == iDevAddr, PANIC(KBTSecPanic, EBTSecBadDeviceAddress));
+
+	iSecMan.PasskeyNotificationComplete(iDevAddr, iStatus.Int());
+	}
+
+TInt CBTPasskeyEntry::RunError(TInt aError)
+	{
+	LOG_FUNC
+	//will never get called as our RunL doesn't leave.
+	LOG1(_L8("\tCBTPasskeyEntry::RunError(%d)\n"), aError);
+	return aError;
+	}
+