diff -r 000000000000 -r 29b1cd4cb562 bluetooth/btstack/secman/secman.cpp --- /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 + +#include + +#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; iDeviceAddress() == 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(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(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; iIsAuthenticationReqPending(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; iAuthenticationRequired() && !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(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 + (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::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::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::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 +CSecNotifierUpdateAO* CSecNotifierUpdateAO::NewL(RNotifier& aNotifier, TUid aNotifierUid) + { + LOG_STATIC_FUNC + CSecNotifierUpdateAO* s = CSecNotifierUpdateAO::NewLC(aNotifier, aNotifierUid); + CleanupStack::Pop(s); + return s; + } + +template +CSecNotifierUpdateAO* CSecNotifierUpdateAO::NewLC(RNotifier& aNotifier, TUid aNotifierUid) + { + LOG_STATIC_FUNC + CSecNotifierUpdateAO* s = new(ELeave) CSecNotifierUpdateAO(); + CleanupStack::PushL(s); + s->ConstructL(aNotifier, aNotifierUid); + return s; + } + +template +CSecNotifierUpdateAO::CSecNotifierUpdateAO() + : CActive(EPriorityStandard) + { + LOG_FUNC + CActiveScheduler::Add(this); + } + +template +CSecNotifierUpdateAO::~CSecNotifierUpdateAO() + { + LOG_FUNC + Cancel(); + } + +template +void CSecNotifierUpdateAO::ConstructL(RNotifier& aNotifier, TUid aNotifierUid) + { + LOG_FUNC + iNotifier = aNotifier; + iNotifierUid = aNotifierUid; + } + + +template +void CSecNotifierUpdateAO::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 +void CSecNotifierUpdateAO::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 +void CSecNotifierUpdateAO::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 +void CSecNotifierUpdateAO::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 +TInt CSecNotifierUpdateAO::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::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::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::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; + } +