--- /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;
+ }
+