--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/linkmgr/physicallinksmanager.cpp Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1390 @@
+// Copyright (c) 2006-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:
+// Implementation of physical links manager
+//
+//
+
+#include <bluetooth/logger.h>
+#include "physicallinksmanager.h"
+#include "physicallinks.h"
+#include "hcifacade.h"
+#include "Basebandmodel.h"
+#include "ProxySAP.h"
+
+#include <bt_sock.h>
+#include "PhysicalLinkHelper.h"
+#include "hostresolver.h"
+
+#include <bluetooth/hci/writepagetimeoutcommand.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_LINKMGR);
+#endif
+
+#ifdef _DEBUG
+PANICCATEGORY("plinkmgr");
+#endif
+
+// macro to dump invalid commands from hardware
+#define RETURN_IF_NULL_CONNECTION(found) {if (!found) {LOG(_L("CPhysicalLinksManager: Bad event received - dropping")); return;}}
+
+
+CPhysicalLinksManager* CPhysicalLinksManager::NewL(CLinkMgrProtocol& aLinkMgrProtocol,
+ CHCIFacade& aHCIFacade,
+ CRegistrySession& aRegSess,
+ CBTSecMan& aSecMan,
+ CBTCodServiceMan& aCodMan)
+ {
+ CPhysicalLinksManager* s = new(ELeave) CPhysicalLinksManager(aLinkMgrProtocol,
+ aHCIFacade,
+ aRegSess,
+ aSecMan,
+ aCodMan);
+ CleanupStack::PushL(s);
+ s->ConstructL();
+ CleanupStack::Pop(s);
+ return s;
+ }
+
+CPhysicalLinksManager::CPhysicalLinksManager(CLinkMgrProtocol& aLinkMgrProtocol,
+ CHCIFacade& aHCIFacade,
+ CRegistrySession& aRegSess,
+ CBTSecMan& aSecMan,
+ CBTCodServiceMan& aCodMan)
+ : iPhysicalLinks(KBTBasebandConnectionArrayGranularity)
+ , iHCIRequestHandler(aHCIFacade)
+ , iRegSess(aRegSess)
+ , iSecMan(aSecMan)
+ , iCodMan(aCodMan)
+ , iLinkManagerProtocol(aLinkMgrProtocol)
+ , iTerminatingProxy(NULL)
+ , iTerminatingConnection(NULL)
+ , iRoleSwitchersQ(_FOFF(CRoleSwitcher, iQLink))
+ , iPageTimeoutController(aHCIFacade.CommandQController())
+ {
+ }
+
+void CPhysicalLinksManager::ConstructL()
+ {
+ iPairingsCache = CBTPairingsCache::NewL(*this, iRegSess.RegServ());
+ iBaseband = CBTBasebandModel::NewL(iLinkManagerProtocol);
+ iPrefetchMan = CBluetoothPrefetchManager::NewL();
+ }
+
+CPhysicalLinksManager::~CPhysicalLinksManager()
+ {
+ LOG(_L("sec\tCBTConnectionsManager destructing"));
+
+ iPageTimeoutController.Abort();
+
+ iPhysicalLinks.ResetAndDestroy();
+ iPhysicalLinks.Close();
+ __ASSERT_ALWAYS(iRoleSwitchersQ.IsEmpty(), Panic(ERoleSwitchersNotDeleted));
+ iListeners.Close();
+
+ delete iBaseband;
+ delete iRoleSwitcherStateFactory;
+ delete iPairingsCache;
+ delete iPrefetchMan;
+ }
+
+void CPhysicalLinksManager::RequireSlotSpace()
+/**
+ At present we put all those connections that are holdable into hold
+ To release baseband space for certain activities such
+ as device discovery
+
+ In future other operations may be performed here...
+**/
+ {
+ if (LinkManagerProtocol().IsModeSupportedLocally(EHoldMode))
+ {
+ CPhysicalLink* con = NULL;
+ // locally can support Hold mode - see if we can free up links that do
+ TInt count = iPhysicalLinks.Count();
+
+ for (TInt i=(count-1); i>=0; i--)
+ {
+ con = iPhysicalLinks[i];
+ static_cast<void>(con->RequestHold()); //ignore error - best effort
+ }
+ }
+ }
+
+TBasebandTime CPhysicalLinksManager::TryToChangePageTimeout(TBasebandTime aPageTimeout)
+ {
+ // First check the page timeout is suitable wrt. link supervision timeouts.
+ aPageTimeout = CheckPageTimeoutAgainstLSTO(aPageTimeout);
+ iPageTimeoutController.WritePageTimeout(aPageTimeout);
+ return aPageTimeout; // return the timeout that was tried (not necessarily set).
+ }
+
+CPhysicalLink& CPhysicalLinksManager::NewPhysicalLinkL(const TBTDevAddr& aAddr)
+ {
+ // create a PHY just knowing its address
+ TBTNamelessDevice device;
+ device.SetAddress(aAddr);
+ return NewPhysicalLinkL(device);
+ }
+
+CPhysicalLink& CPhysicalLinksManager::NewPhysicalLinkL(const TBTNamelessDevice& aDevice)
+ {
+ // create a PHY with a full Device - make sure it isn't us!
+ if (aDevice.Address() == iLinkManagerProtocol.LocalBTAddress())
+ {
+ // the app may be at fault - so don't panic
+ User::Leave(KErrReflexiveBluetoothLink);
+ }
+
+ // create role switch SM
+ // delete is in destructor of CPhysicalLinksManager
+ if (!iRoleSwitcherStateFactory)
+ {
+ iRoleSwitcherStateFactory = CRoleSwitcherStateFactory::NewL();
+ }
+
+ CPhysicalLink* phy = CPhysicalLink::NewLC(*this, iRegSess, aDevice);
+ User::LeaveIfError(iPhysicalLinks.Append(phy)); //transfers ownership
+
+ CleanupStack::Pop(phy);
+ LOG1(_L("CPhysicalLinksManager: Number of physical links %d"), iPhysicalLinks.Count());
+ return *phy;
+ }
+
+CPhysicalLink* CPhysicalLinksManager::FindPhysicalLink(const TBTDevAddr& aBDAddr) const
+ {
+ CPhysicalLink* con = NULL;
+ CPhysicalLink* found = NULL;
+
+
+ TInt count = iPhysicalLinks.Count();
+
+ for (TInt i=(count-1); i>=0; i--)
+ {
+ con = iPhysicalLinks[i];
+
+ if (con->BDAddr() == aBDAddr)
+ {
+#ifndef _DEBUG
+ found = con;
+ break;
+#else
+ if (found) //make sure there's only one
+ {
+ __DEBUGGER()
+ }
+ else
+ {
+ found = con;
+ continue; // just to show we do want to!
+ }
+#endif
+ }
+ }
+ return found;
+ }
+
+void CPhysicalLinksManager::DumpPhysicalLinks()
+ {
+#ifdef __FLOG_ACTIVE
+ TInt count = iPhysicalLinks.Count();
+
+ CPhysicalLink* con = NULL;
+ for (TInt i=(count-1); i>=0; i--)
+ {
+ con = iPhysicalLinks[i];
+ LOG(_L(" - Link: "));
+ LOGBTDEVADDR(con->BDAddr());
+ }
+#endif
+ }
+
+TBool CPhysicalLinksManager::IsAcceptPairedOnlyMode()
+ {
+ return iAcceptPairedOnlyMode;
+ }
+
+CPhysicalLink* CPhysicalLinksManager::FindPhysicalLink(THCIConnHandle aConnH) const
+/**
+ Handy for when a disconnection comes in - disconnections dont give either
+ the address or (if SCO) the 'bound' handle.
+
+ This method asks each CPhysicalLink if it knows of the handle (ACL or SCO)
+**/
+ {
+ CPhysicalLink* con = NULL;
+ CPhysicalLink* found = NULL;
+
+ TInt count = iPhysicalLinks.Count();
+ for (TInt i=(count-1); i>=0; i--)
+ {
+ con = iPhysicalLinks[i];
+ if (con->HasHandle(aConnH))
+ {
+#ifndef _DEBUG
+ found = con;
+ break;
+#else
+ if (found) //make sure there's only one
+ {
+ __DEBUGGER()
+ }
+ else
+ {
+ found = con;
+ continue; // just to show we do want to!
+ }
+#endif
+ }
+ }
+ return found;
+ }
+
+CPhysicalLink* CPhysicalLinksManager::FindPhysicalLink() const
+/**
+ Handy for finding a random connected PHY
+**/
+ {
+ CPhysicalLink* con = NULL;
+ CPhysicalLink* found = NULL;
+
+
+ TInt count = iPhysicalLinks.Count();
+ if(!count)
+ {
+ return NULL;
+ }
+ for (TInt i=(count-1); i>=0; i--)
+ {
+ con = iPhysicalLinks[i];
+ if (con->Handle()!=KHCIBroadcastHandle)
+ {
+ found = con;
+ break;
+ }
+ }
+ return found;
+ }
+
+TLogicalLinkListener* CPhysicalLinksManager::FindListener(TPhysicalLinkPort aPort)
+ {
+ // go through listeners until we find a listener on the required port
+ TLogicalLinkListener* found = NULL;
+ TLogicalLinkListener* l = NULL;
+
+ TInt count = iListeners.Count();
+ for (TInt i=(count-1); i>=0; i--)
+ {
+ l = &iListeners[i];
+ if (l->iPort == aPort)
+ {
+ found = l;
+ break;
+ }
+ }
+
+ return found;
+ }
+
+void CPhysicalLinksManager::ClearTerminatingProxy(CBTProxySAP* aProxySAP)
+ {
+ if (aProxySAP==iTerminatingProxy)
+ {
+ iTerminatingProxy=NULL;
+ }
+ }
+
+void CPhysicalLinksManager::UpdateTerminatingProxy(CBTProxySAP* aProxySAP)
+ {
+ // If there is an outstanding terminate request for a different Proxy SAP
+ // complete it here and deal with the new request
+ if (iTerminatingProxy && (iTerminatingProxy!=aProxySAP))
+ {
+ iTerminatingProxy->TerminatePhysicalLinksComplete();
+ }
+ iTerminatingProxy=aProxySAP;
+ }
+
+TInt CPhysicalLinksManager::TerminateAllPhysicalLinks(CBTProxySAP* aProxySAP)
+ {
+ TInt count=iPhysicalLinks.Count();
+ TInt retVal = (count==0) ? KErrNotFound : KErrNone;
+
+ for (TInt i=0; i<count; i++)
+ {
+ // If any one of the physical links return an error then this
+ // function needs to return an error.
+ TInt err = iPhysicalLinks[i]->Terminate(ERemoteUserEndedConnection);
+ if (err != KErrNone)
+ {
+ retVal=err;
+ }
+ }
+
+ // aProxy==NULL means that the calling Proxy SAP does not want to be told when the
+ // physical link has terminated
+ if ((retVal==KErrNone) || !aProxySAP)
+ {
+ UpdateTerminatingProxy(aProxySAP);
+ }
+
+ return retVal;
+ }
+
+TInt CPhysicalLinksManager::TerminatePhysicalLink(CPhysicalLink* aConnection, CBTProxySAP* aProxySAP)
+ {
+ TInt count = iPhysicalLinks.Count();
+ TInt retVal=KErrNotFound;
+ for (TInt i=(count-1); i>=0; i--)
+ {
+ if (iPhysicalLinks[i]==aConnection)
+ {
+ retVal=iPhysicalLinks[i]->Terminate(ERemoteUserEndedConnection);
+ break;
+ }
+ }
+
+ // aProxy==NULL means that the calling Proxy SAP does not want to be told when the
+ // physical link has terminated
+ if ((retVal==KErrNone) || !aProxySAP)
+ {
+ UpdateTerminatingProxy(aProxySAP);
+ iTerminatingConnection=aConnection;
+ }
+
+ return retVal;
+ }
+
+void CPhysicalLinksManager::UpdateRemoteDevicesDetails()
+ {
+ //Update paired device list
+ iPairingsCache->UpdateCache();
+
+ //Update cached device info for existing PHYs
+ TInt count=iPhysicalLinks.Count();
+ for (TInt i=0; i<count; i++)
+ {
+ // try to get details of remote device
+ TRAP_IGNORE(iPhysicalLinks[i]->GetDeviceFromRegistryL());
+ // ignore error - as with other registry accessing routines
+ }
+ }
+
+void CPhysicalLinksManager::SetAcceptPairedOnlyMode(TBool aOn)
+ {
+ iAcceptPairedOnlyMode = aOn;
+ LinkManagerProtocol().SetAcceptPairedOnlyMode(aOn);
+ }
+
+
+void CPhysicalLinksManager::SetSimplePairingDebugMode(TBool aOn)
+ {
+ if(!SecMan().LocalSimplePairingMode())
+ {
+ LOG(_L("CPhysicalLinksManager: Simple pairing not supported by controller - ignoring request for debug mode"));
+ return;
+ }
+ if(aOn)
+ {
+ iSecMan.SetDebugMode(aOn);
+ }
+ }
+
+void CPhysicalLinksManager::SimplePairingDebugModeChanged(TBool aOn)
+ {
+ LinkManagerProtocol().SetSimplePairingDebugMode(aOn);
+ }
+
+void CPhysicalLinksManager::FatalError(TInt /*aErr*/)
+ {
+ // simulate a disconnection complete on all PHYs
+ TInt count=iPhysicalLinks.Count();
+
+ //The call to l.Disconnection removes an element from array iPhysicalLink, therefore invalidates
+ //count. So it's best iterating through the array backwards because count is only used for
+ //initialising i, and i is always valid.
+ for (TInt i=count-1; i>=0; i--)
+ {
+ // we say remote, as this is a passive-like disconnection
+ CPhysicalLink& l = *iPhysicalLinks[i];
+ l.Disconnection(EHardwareFail, l.Handle(), EHardwareFail);
+ }
+
+ // Don't error the Listeners
+ }
+
+void CPhysicalLinksManager::NewLinkKey(const TBTDevAddr& aBDAddr, const TBTLinkKey& aLinkKey, THCILinkKeyType aLinkKeyType)
+ {
+ CPhysicalLink* found = FindPhysicalLink(aBDAddr);
+ RETURN_IF_NULL_CONNECTION(found);
+ found->NewLinkKey(aBDAddr, aLinkKey, aLinkKeyType);
+ }
+
+void CPhysicalLinksManager::RemovePhysicalLink(const CPhysicalLink& aConnection)
+/**
+ A Physical Link wants us to remove our knowledge of it
+**/
+ {
+ TInt count = iPhysicalLinks.Count();
+ TInt i;
+ for (i=(count-1); i>=0; i--)
+ {
+ if (iPhysicalLinks[i]==&aConnection)
+ {
+ iPhysicalLinks.Remove(i);
+ count--;
+ break;
+ }
+ }
+
+ if (count!=0)
+ {
+ //compress the array if needs be
+ if (i!=count)
+ {
+ iPhysicalLinks.GranularCompress();
+ }
+
+ // A physical link has been removed. Arbitrate for role switch allowed
+ // on the remainder of the links.
+ ArbitrateAllPhysicalLinks();
+ }
+
+ // IF we have a Terminate request from a ProxySAP AND
+ // either it was a request to terminate all connections and we have no connections left OR
+ // it was a request for a specific connection that we have just removed THEN
+ // tell the Proxy SAP that the request is complete
+ if (iTerminatingProxy &&
+ ((!iTerminatingConnection && (count==0)) ||
+ ((iTerminatingConnection==&aConnection) && (i!=-1))))
+ {
+ iTerminatingProxy->TerminatePhysicalLinksComplete();
+ iTerminatingProxy=NULL;
+ iTerminatingConnection=NULL;
+ }
+
+ // good time to update that UI
+ LinkManagerProtocol().SetUINumPhysicalLinks(count);
+ LOG1(_L("CPhysicalLinksManager: Number of physical links %d"), count);
+ }
+
+void CPhysicalLinksManager::ArbitrateAllPhysicalLinks()
+ {
+ TInt i;
+ for (i=(iPhysicalLinks.Count()-1); i>=0; i--)
+ {
+ iPhysicalLinks[i]->Arbitrate();
+ }
+ }
+
+void CPhysicalLinksManager::SimplePairingComplete(const TBTDevAddr& aBDAddr, THCIErrorCode /*aErr*/)
+ {
+ //find the connection and pass on the request
+ CPhysicalLink* found = FindPhysicalLink(aBDAddr);
+ RETURN_IF_NULL_CONNECTION(found);
+ found->AuthenticationComplete(ESimplePairingPending);
+ }
+
+void CPhysicalLinksManager::PinRequest(const TBTDevAddr& aBDAddr,
+ MPINCodeResponseHandler& aRequester)
+ {
+ //find the connection and pass on the request
+ CPhysicalLink* found = FindPhysicalLink(aBDAddr);
+ RETURN_IF_NULL_CONNECTION(found);
+ found->PinRequest(aBDAddr, aRequester);
+ }
+
+void CPhysicalLinksManager::LinkKeyRequest(const TBTDevAddr& aBDAddr, MLinkKeyResponseHandler& aRequester)
+ {
+ CPhysicalLink* found = FindPhysicalLink(aBDAddr);
+ RETURN_IF_NULL_CONNECTION(found);
+ found->LinkKeyRequest(aBDAddr, aRequester);
+ }
+
+void CPhysicalLinksManager::ReadRemoteSupportedFeaturesComplete(THCIErrorCode aErr, THCIConnHandle aConnH, const TBTFeatures& aBitMask)
+ {
+ CPhysicalLink* found = FindPhysicalLink(aConnH);
+ RETURN_IF_NULL_CONNECTION(found);
+ found->ReadRemoteSupportedFeaturesComplete(aErr, aConnH, aBitMask);
+ }
+
+void CPhysicalLinksManager::ReadRemoteExtendedFeaturesComplete(THCIErrorCode aErr, THCIConnHandle aConnH, TUint64 aBitMask, TUint8 aPageNumber, TUint8 aMaximumPageNumber)
+ {
+ CPhysicalLink* found = FindPhysicalLink(aConnH);
+ RETURN_IF_NULL_CONNECTION(found);
+ found->ReadRemoteExtendedFeaturesComplete(aErr, aConnH, aBitMask, aPageNumber, aMaximumPageNumber);
+ }
+
+
+void CPhysicalLinksManager::ReadRemoteVersionInfoComplete(THCIErrorCode aErr, THCIConnHandle aConnH, const TBTDevRemoteHwVersion& aVer)
+ {
+ CPhysicalLink* found = FindPhysicalLink(aConnH);
+ RETURN_IF_NULL_CONNECTION(found);
+ found->ReadRemoteVersionInfoComplete(aErr, aConnH, aVer);
+ }
+
+void CPhysicalLinksManager::PacketTypeChange(THCIErrorCode aErr, THCIConnHandle aConnH, TUint16 aNewPacket)
+ {
+ CPhysicalLink* found = FindPhysicalLink(aConnH);
+ RETURN_IF_NULL_CONNECTION(found);
+ found->PacketTypeChange(aErr, aConnH, aNewPacket);
+ }
+
+void CPhysicalLinksManager::LinkSupervisionTimeoutChange(THCIErrorCode aErr, THCIConnHandle aConnH, TUint16 aNewTimeout)
+ {
+ CPhysicalLink* found = FindPhysicalLink(aConnH);
+ RETURN_IF_NULL_CONNECTION(found);
+ found->LinkSupervisionTimeoutChange(aErr, aConnH, aNewTimeout);
+ }
+
+TBasebandTime CPhysicalLinksManager::CheckPageTimeoutAgainstLSTO(TBasebandTime aPageTimeout)
+ {
+ // Calculate the page timeout:
+ // Iterate through all physical links, and take the minimum
+ // LSTO of them all. This is maximum possible page timeout value
+ TInt connections = iPhysicalLinks.Count();
+ TInt newPageTimeout = aPageTimeout;
+ for(TInt i = 0; i < connections; i++)
+ {
+ // Reduce pageTimeout if greater than LSTO for any physical link
+ // LSTO could be zero if no LSTO event received; ignore zero values
+ TUint lsto = iPhysicalLinks[i]->LSTO();
+ if (lsto > 0 && newPageTimeout > lsto)
+ {
+ newPageTimeout = lsto;
+ }
+ }
+
+ // The pageTimeout has been changed. Ensure it is 5% less
+ // than the minimum LSTO that it has already been set to.
+ if (newPageTimeout != aPageTimeout)
+ {
+ const TReal32 KNinetyFivePercentMultiplier = 0.95;
+ newPageTimeout = newPageTimeout * KNinetyFivePercentMultiplier; // Reduce by 5%
+ }
+ return newPageTimeout;
+ }
+
+void CPhysicalLinksManager::MaxSlotsChange(THCIConnHandle aConnH, TUint8 aSlots)
+ {
+ CPhysicalLink* found = FindPhysicalLink(aConnH);
+ RETURN_IF_NULL_CONNECTION(found);
+ found->MaxSlotsChange(aConnH, aSlots);
+ }
+
+void CPhysicalLinksManager::ModeChange(THCIErrorCode aErr, THCIConnHandle aConnH, TBTLinkMode aMode, TBasebandTime aInterval)
+ {
+ CPhysicalLink* found = FindPhysicalLink(aConnH);
+ RETURN_IF_NULL_CONNECTION(found);
+ found->ModeChange(aErr, aConnH, aMode, aInterval);
+ }
+
+void CPhysicalLinksManager::RoleChange(THCIErrorCode aErr, const TBTDevAddr& aAddr, TBTBasebandRole aRole)
+ {
+ // interesting that this is an address, not a Conn handle! Good old H:1.
+ CPhysicalLink* found = FindPhysicalLink(aAddr);
+ RETURN_IF_NULL_CONNECTION(found);
+ found->RoleChange(aErr, aAddr, aRole);
+ }
+
+void CPhysicalLinksManager::WriteLinkPolicySettingsCompleteEvent(THCIErrorCode aErr, THCIConnHandle aConnH)
+ {
+ CPhysicalLink* found = FindPhysicalLink(aConnH);
+ RETURN_IF_NULL_CONNECTION(found);
+ found->WriteLinkPolicySettingsCompleteEvent(aErr, aConnH);
+ }
+
+void CPhysicalLinksManager::ClockOffset(THCIErrorCode aErr, THCIConnHandle aConnH, TBasebandTime aClockOffset)
+ {
+ CPhysicalLink* found = FindPhysicalLink(aConnH);
+ RETURN_IF_NULL_CONNECTION(found);
+ found->ClockOffset(aErr, aConnH, aClockOffset);
+ }
+
+void CPhysicalLinksManager::RemoteName(THCIErrorCode aErr, const TBTDevAddr& aAddr, const TBTDeviceName8& aName)
+ {
+ CPhysicalLink* found = FindPhysicalLink(aAddr);
+ RETURN_IF_NULL_CONNECTION(found);
+ found->RemoteName(aErr, aAddr, aName);
+ }
+
+void CPhysicalLinksManager::ConnectionComplete(THCIErrorCode aErr, const TBTConnect& aConn)
+ {
+ // we at this stage demux ACL and SCO
+ CPhysicalLink* phy = FindPhysicalLink(aConn.iBdaddr);
+
+ if (!phy)
+ {
+ // to be safe we should cancel all outstanding connections of correct type
+ // since some HW leaves the address blank when errroring a connect
+ CancelPendingConnections(aErr, aConn);
+ // disconnect this weirdo link if it came up
+ if (aErr==EOK)
+ {
+ TRAP_IGNORE(HCIFacade().DisconnectL(aConn.iConnH, ERemoteUserEndedConnection));
+ // if error just have to wait for a timeout
+ }
+ }
+ else
+ {
+ phy->ConnectionComplete(aErr, aConn);
+ // good time to update that UI
+ LinkManagerProtocol().SetUINumPhysicalLinks(iPhysicalLinks.Count());
+ }
+ }
+
+void CPhysicalLinksManager::SynchronousConnectionComplete(THCIErrorCode aErr,
+ const TBTConnect& aConn,
+ const TBTSyncConnectOpts& aSyncOpts)
+ {
+ __ASSERT_DEBUG(((aConn.iLinkType == ESCOLink) || (aConn.iLinkType == EeSCOLink)), Panic(EBTNonSyncConnectInSyncConnectFunc));
+
+ if((aConn.iLinkType == ESCOLink) || (aConn.iLinkType == EeSCOLink))
+ {
+ CPhysicalLink* phy = FindPhysicalLink(aConn.iBdaddr);
+
+ if (!phy)
+ {
+ // to be safe we should cancel all outstanding connections of correct type
+ // since some HW leaves the address blank when errroring a connect
+ CancelPendingConnections(aErr, aConn);
+ // disconnect this weirdo link if it came up
+ if (aErr==EOK)
+ {
+ TRAP_IGNORE(HCIFacade().DisconnectL(aConn.iConnH, ERemoteUserEndedConnection));
+ // if error just have to wait for a timeout
+ }
+ }
+ else
+ {
+ phy->SynchronousConnectionComplete(aErr, aConn, aSyncOpts);
+ // good time to update that UI
+ LinkManagerProtocol().SetUINumPhysicalLinks(iPhysicalLinks.Count());
+ }
+ }
+ else
+ {
+ TRAP_IGNORE(HCIFacade().DisconnectL(aConn.iConnH, ERemoteUserEndedConnection));
+ }
+ }
+
+void CPhysicalLinksManager::MbpcoDeferredDecisionResolved(TInt aError)
+ {
+ // See if any connection requests are pending,
+ // having been held up whilst the stack was
+ // being updated with all paired devices
+ // in the registry.
+ for(TInt i = iPhysicalLinks.Count() - 1; i>=0; i--)
+ {
+ if(iPhysicalLinks[i]->IsConnectionRequestPending())
+ {
+ iPhysicalLinks[i]->PendingConnectionRequest(aError); //try now we have a list of paired devices
+ }
+ }
+ }
+
+TInt CPhysicalLinksManager::AddListener(MLogicalLink& aLogicalLink, TPhysicalLinkPort aPort)
+ {
+ TLogicalLinkListener l;
+ l.iObserver = &aLogicalLink;
+ l.iPort = aPort;
+
+ TInt retVal = KErrNone;
+
+ // only allowed one listener on either port at moment
+ for (TInt i=0; i<iListeners.Count(); i++)
+ {
+ if (iListeners[i].iPort == aPort)
+ {
+ retVal = KErrInUse;
+ }
+ }
+
+ if (retVal == KErrNone)
+ {
+ retVal = iListeners.Append(l);
+ if (retVal == KErrNone)
+ {
+ retVal = LinkManagerProtocol().IncrementListeners();
+ }
+ }
+
+ return retVal;
+ }
+
+/*static*/ TBool CPhysicalLinksManager::ListenerMatch(const TLogicalLinkListener& aA,
+ const TLogicalLinkListener& aB)
+ {
+ return (aA.iObserver == aB.iObserver);
+ }
+
+void CPhysicalLinksManager::RemoveListener(MLogicalLink& aLogicalLink)
+ {
+ __ASSERT_DEBUG(iListeners.Count(), Panic(EBTConnectionMgrCountBelowZero));
+
+ TLogicalLinkListener key;
+ key.iObserver = &aLogicalLink;
+
+ TIdentityRelation<TLogicalLinkListener> relation(ListenerMatch);
+
+ TInt result = iListeners.Find(key, relation);
+ __ASSERT_DEBUG(result!=KErrNotFound, Panic(EBTConnectionMgrBadListener));
+
+ // remove from listener queue
+ iListeners.Remove(result);
+ // and tell protocol we have one fewer
+ LinkManagerProtocol().DecrementListeners();
+ // ignore err
+ }
+
+void CPhysicalLinksManager::CancelPendingConnections(THCIErrorCode aErr, const TBTConnect& aConn)
+/**
+ When we cannot work out who to notify, we regrettably have to cancel all
+**/
+ {
+ for (TInt index = 0; index < iPhysicalLinks.Count(); index++)
+ {
+ CPhysicalLink& l = *iPhysicalLinks[index];
+ if ( (aConn.iConnH && l.HasHandle(aConn.iConnH))
+ || ((aConn.iLinkType == EACLLink) && l.ACLConnectPending())
+ || ((aConn.iLinkType != EACLLink) && l.SyncConnectPending())
+ )
+ {
+ l.ConnectionComplete(aErr, aConn);
+ }
+ }
+ }
+
+void CPhysicalLinksManager::ConnectionRequest(const TBTConnect& aConn)
+ {
+ // we haven't got much to go on to find a Listener
+ // we don't support directed listening on address
+ // so just go on link type
+ // this isn't too bad as Bluetooth only has one ACL listener at the moment: L2CAP
+ LOG1(_L("Connection request received, link type %d"), aConn.iLinkType);
+
+ switch (aConn.iLinkType)
+ {
+ case EACLLink:
+ {
+ // this also (see BT1.2) implies that a new PHY is coming up
+
+ // Check that either there exist listeners or the protocol knows
+ // that it should stop listening (even if the message has evidently
+ // not yet reached the controller).
+ __ASSERT_DEBUG(iListeners.Count() || !iLinkManagerProtocol.IsListening(), Panic(EBTConnectionRequestWithNoListeners));
+ if (iListeners.Count())
+ {
+ TRAP_IGNORE(DoConnectionRequestL(aConn));
+ }
+ else
+ {
+ // should never reach here
+ // leave to timeout - not required
+ }
+ }
+ // ignore err for timeout
+ break;
+ case ESCOLink:
+ case EeSCOLink:
+ {
+ // should by a non-listening PHY already in place!
+ CPhysicalLink* c = FindPhysicalLink(aConn.iBdaddr);
+ ASSERT_DEBUG(c);
+ c->ConnectionRequest(aConn);
+ }
+ }
+ }
+
+
+void CPhysicalLinksManager::DoConnectionRequestL(const TBTConnect& aConn)
+ {
+ // Only called for ACL links
+ // ASSERT aConn.iLinkType == EACLLink
+
+ // First check that this is not a request for a duplicate address, some hardware
+ // can be tediously erratic.
+ CPhysicalLink* reqAddr = FindPhysicalLink(aConn.iBdaddr);
+ if (!reqAddr)
+ {
+ CPhysicalLink& c = NewPhysicalLinkL(aConn.iBdaddr);
+ // introduce the first listener to the PHY
+ // IF WE SUPPORT connections distinguished on aConn then we can find the correct listener
+ // now tell the (new) PHY
+ c.ConnectionRequest(aConn);
+ }
+ else
+ {
+ // reject incoming connection
+ LOG(_L("CPhysicalLinksManager: Duplicate address received - reject"));
+ TRAP_IGNORE(HCIFacade().RejectConnectionRequestL(aConn, EHostSecurityRejection));
+ }
+ }
+
+void CPhysicalLinksManager::Disconnection(THCIErrorCode aErr, THCIConnHandle aConnH, THCIErrorCode aResult)
+ {
+ // notify the correct connection
+ CPhysicalLink* con = FindPhysicalLink(aConnH);
+ LOG1(_L("Links manager: disconnection, phys. link 0x%08x"), con);
+ RETURN_IF_NULL_CONNECTION(con);
+ con->Disconnection(aErr, aConnH, aResult);
+ }
+
+void CPhysicalLinksManager::CompletedPackets(THCIConnHandle aConnH, TUint16 aNumPackets)
+ {
+ // forward to the connections - they can possibly unblock their sockets
+ CPhysicalLink* con = FindPhysicalLink(aConnH);
+ RETURN_IF_NULL_CONNECTION(con);
+ con->CompletedPackets(aConnH, aNumPackets);
+
+ //now unblock all connections to prevent any deadlock
+ TInt connections = iPhysicalLinks.Count();
+ for(TInt i = 0; i < connections;i++)
+ {
+ CPhysicalLink* other_con = iPhysicalLinks[i];
+ if(other_con != con)
+ {
+ other_con->TryToSend();
+ }
+ }
+ }
+
+void CPhysicalLinksManager::AuthenticationComplete(THCIErrorCode aErr, THCIConnHandle aConnH)
+ {
+ // tell the anonymous notifiers? could be useful for updating UI?
+ CPhysicalLink* con = FindPhysicalLink(aConnH);
+ RETURN_IF_NULL_CONNECTION(con);
+ con->AuthenticationComplete(aErr, aConnH);
+ }
+
+void CPhysicalLinksManager::EncryptionChange(THCIErrorCode aErr, THCIConnHandle aConnH,TBool aEncrypted)
+ {
+ // tell the anonymous notifiers? could be useful for updating UI?
+ CPhysicalLink* con = FindPhysicalLink(aConnH);
+ RETURN_IF_NULL_CONNECTION(con);
+ con->EncryptionChange(aErr, aConnH, aEncrypted);
+ }
+
+void CPhysicalLinksManager::ACLDataReceived(THCIConnHandle aConnH, TUint8 aFlag, const TDesC8& aData)
+ {
+ CPhysicalLink* con = FindPhysicalLink(aConnH);
+ RETURN_IF_NULL_CONNECTION(con);
+ con->ACLDataReceived(aConnH, aFlag, aData);
+ }
+
+void CPhysicalLinksManager::SCODataReceived(THCIConnHandle aConnH, const TDesC8& aData)
+ {
+ CPhysicalLink* con = FindPhysicalLink(aConnH);
+ RETURN_IF_NULL_CONNECTION(con);
+ con->SCODataReceived(aConnH, aData);
+ }
+
+TInt CPhysicalLinksManager::ChangeMode(TBTLinkMode aMode, THCIConnHandle aConnHandle)
+ {
+ return iHCIRequestHandler.ChangeMode(aMode, aConnHandle);
+ }
+
+TInt CPhysicalLinksManager::ExitMode(TBTLinkMode aMode, THCIConnHandle aConnHandle)
+ {
+ return iHCIRequestHandler.ExitMode(aMode, aConnHandle);
+ }
+
+TInt CPhysicalLinksManager::ChangeRole(TBTBasebandRole aRole, CPhysicalLink& aPhysicalLink)
+ {
+ TRAPD(err, iHCIRequestHandler.ChangeRoleL(aRole, aPhysicalLink.BDAddr()));
+ return err;
+ }
+
+TInt CPhysicalLinksManager::Encrypt(TBool aEnable, CPhysicalLink& aPhysicalLink)
+ {
+ TRAPD(err, iHCIRequestHandler.SetEncryptL( aPhysicalLink.Handle(), aEnable));
+ return err;
+ }
+
+
+TBool CPhysicalLinksManager::ActiveConnectRoleSwitchAllowed() const
+ {
+ // An active connection role change will be allowed in all cases,
+ // except when there is an existing master connection from this device.
+ if(iPhysicalLinks.Count() > 1)
+ {
+ if(iPhysicalLinks[0]->Role() == EMaster)
+ {
+ return EFalse;
+ }
+ }
+ return ETrue;
+ }
+
+TBool CPhysicalLinksManager::PassiveConnectBecomeMaster() const
+ {
+ // If this device is currently working as a master for an existing
+ // connection, request a role switch to master.
+ return (iPhysicalLinks.Count() > 1 && iPhysicalLinks[0]->Role() == EMaster);
+ }
+
+TBool CPhysicalLinksManager::RoleSwitchAllowed() const
+ {
+ // By default the stack will not try and prevent this device scatterneting.
+ // If the BT hardware can't gracefully cope with requests to scatternet (i.e.,
+ // disconnects existing phy's if a new scatternet connection is attempted) then
+ // this macro should be defined.
+#ifdef HARDWARE_DOES_NOT_SUPPORT_SCATTERNET_OPERATION
+ return (iPhysicalLinks.Count() <= 1);
+#else
+ return ETrue;
+#endif
+ }
+
+
+void CPhysicalLinksManager::EnumeratePhysicalLinks(TDes8& aPackagedArrayBuffer)
+/**
+ This method fills the memory passed from the client with a number of TBTDevAddrs.
+ Useful for control panel apps that need to see what links are present
+
+ Because the array passed to us here may be smaller than the number of active links
+ at this point, we shall return as much as possible in the array.
+
+ Also if the array has enough space for more addresses than we currently have, the
+ descriptor size will be changed to reflect reality.
+*/
+ {
+ TInt connections = Min(iPhysicalLinks.Count(),
+ aPackagedArrayBuffer.MaxLength()/sizeof(TBTDevAddr));
+ aPackagedArrayBuffer.Zero(); // start from the err.. start and then append
+
+ for(TInt i=0; i<connections; i++)
+ {
+ if (iPhysicalLinks[i]->IsConnected())
+ {
+ TBTDevAddr theDevAddr=iPhysicalLinks[i]->BDAddr();
+
+ TPckg<TBTDevAddr> pckg(theDevAddr);
+ aPackagedArrayBuffer.Append(pckg);
+ }
+ }
+ }
+
+void CPhysicalLinksManager::RoleChangeRejectedByHW(THCIErrorCode aErr)
+ {
+ // we can notify the users about Role Change failure on HW with BTBasebandEvent error
+ // Make sure the Q is not empty before trying to access First()
+ if(!iRoleSwitchersQ.IsEmpty())
+ {
+ RoleChange(aErr, iRoleSwitchersQ.First()->BDAddr(), iRoleSwitchersQ.First()->RequestedRole());
+ }
+
+ }
+
+ void CPhysicalLinksManager::AddRoleSwitcher(CRoleSwitcher& aRoleSwitcher)
+ {
+ iRoleSwitchersQ.AddLast( aRoleSwitcher ); // ownership still remains in CPhysicalLink
+
+ if (iRoleSwitchersQ.IsFirst(&aRoleSwitcher))
+ {
+ // this the only role request, it's safe to kick off the state machine
+ // first suspend host resolver
+ LinkManagerProtocol().InquiryMgr().Suspend();
+ aRoleSwitcher.Start();
+ }
+ }
+
+ void CPhysicalLinksManager::RemoveRoleSwitcher(CRoleSwitcher& aRoleSwitcher)
+ {
+ TBool startNextRoleSwitcher = EFalse;
+
+ if (iRoleSwitchersQ.IsFirst(&aRoleSwitcher))
+ {
+ startNextRoleSwitcher = ETrue;
+ }
+
+ if (!iRoleSwitchersQ.IsEmpty())
+ {
+ iRoleSwitchersQ.Remove(aRoleSwitcher);
+ }
+
+ if (startNextRoleSwitcher && !iRoleSwitchersQ.IsEmpty())
+ {
+ iRoleSwitchersQ.First()->Start();
+ }
+ else
+ {
+ // resume host resolver
+ LinkManagerProtocol().InquiryMgr().Resume();
+ }
+ }
+
+TInt CPhysicalLinksManager::GetConnectionHandles(RHCIConnHandleArray& aConnectionHandles, TLinkType aLinkType) const
+ {
+ aConnectionHandles.Reset(); // sub-optimal
+
+ const TInt phycount(iPhysicalLinks.Count());
+ if (phycount == 0)
+ {
+ return KErrNone;
+ }
+
+ TInt err(aConnectionHandles.Reserve(phycount));
+
+ if (err != KErrNone)
+ {
+ return err;
+ }
+
+ for (TInt i(0); i < phycount; ++i)
+ {
+ const CPhysicalLink* const phy(iPhysicalLinks[i]);
+ if (!phy)
+ {
+ return KErrNotFound;
+ }
+
+ // append to aConnectionHandles
+ err = phy->GetConnectionHandles(aConnectionHandles, aLinkType);
+
+ if (err != KErrNone)
+ {
+ return err;
+ }
+ }
+
+ return KErrNone;
+ }
+
+TInt CPhysicalLinksManager::GetNumPendingHandles(TInt& aConnectionHandles, TLinkType aLinkType) const
+ {
+ aConnectionHandles = 0;
+
+ const TInt phycount(iPhysicalLinks.Count());
+ if (phycount == 0)
+ {
+ return KErrNone;
+ }
+
+ for (TInt i(0); i < phycount; ++i)
+ {
+ const CPhysicalLink* const phy(iPhysicalLinks[i]);
+ if (!phy)
+ {
+ return KErrNotFound;
+ }
+
+ TInt count(0);
+ // append to aConnectionHandles
+ TInt err(phy->GetNumPendingHandles(count, aLinkType));
+
+ if (err != KErrNone)
+ {
+ return err;
+ }
+
+ aConnectionHandles += count;
+ }
+
+ return KErrNone;
+ }
+
+TInt CPhysicalLinksManager::GetConnectionHandles(RHCIConnHandleArray& aConnectionHandles, TLinkType aLinkType, const TBTDevAddr& aBDAddr) const
+ {
+ aConnectionHandles.Reset(); // sub-optimal
+
+ const CPhysicalLink* const phy(FindPhysicalLink(aBDAddr));
+
+ if (!phy)
+ {
+ // In the event of an error the client should not inspect
+ // aConnectionHandle.
+ return KErrNotFound;
+ }
+
+ return phy->GetConnectionHandles(aConnectionHandles,
+ aLinkType);
+ }
+
+TInt CPhysicalLinksManager::GetNumPendingHandles(TInt& aConnectionHandles, TLinkType aLinkType, const TBTDevAddr& aBDAddr) const
+ {
+ aConnectionHandles = 0;
+
+ const CPhysicalLink* const phy(FindPhysicalLink(aBDAddr));
+
+ if (!phy)
+ {
+ // In the event of an error the client should not inspect
+ // aConnectionHandle.
+ return KErrNotFound;
+ }
+
+ return phy->GetNumPendingHandles(aConnectionHandles, aLinkType);
+ }
+
+TInt CPhysicalLinksManager::GetRemoteAddress(TBTDevAddr& aBDAddr, THCIConnHandle aConnectionHandle) const
+ {
+ const CPhysicalLink* const phy(FindPhysicalLink(aConnectionHandle));
+
+ if (!phy)
+ {
+ // In the event of an error the client should not inspect
+ // aBDAddr.
+ return KErrNotFound;
+ }
+
+ aBDAddr = phy->BDAddr();
+ return KErrNone;
+ }
+
+TInt CPhysicalLinksManager::GetRemoteDeviceClass(TBTDeviceClass& aDeviceClass, const TBTDevAddr& aBDAddr) const
+ {
+ const CPhysicalLink* const phy(FindPhysicalLink(aBDAddr));
+
+ if (!phy)
+ {
+ // In the event of an error the client should not inspect
+ // aBasebandLinkState.
+ return KErrNotFound;
+ }
+
+ aDeviceClass = phy->DeviceClass();
+ return KErrNone;
+ }
+
+TInt CPhysicalLinksManager::GetRemoteSupportedFeatures(TBTFeatures& aRemoteSupportedFeatures, const TBTDevAddr& aBDAddr) const
+ {
+ const CPhysicalLink* const phy(FindPhysicalLink(aBDAddr));
+
+ if (!phy)
+ {
+ // In the event of an error the client should not inspect
+ // aRemoteSupportedFeatures.
+ return KErrNotFound;
+ }
+
+ aRemoteSupportedFeatures = phy->RemoteFeatures();
+ return KErrNone;
+ }
+
+TInt CPhysicalLinksManager::GetLinkPolicySettings(TLinkPolicy& aLinkPolicySettings, const TBTDevAddr& aBDAddr) const
+ {
+ const CPhysicalLink* const phy(FindPhysicalLink(aBDAddr));
+
+ if (!phy)
+ {
+ // In the event of an error the client should not inspect
+ // aLinkPolicySettings.
+ return KErrNotFound;
+ }
+
+ aLinkPolicySettings = phy->LinkPolicy();
+ return KErrNone;
+ }
+
+TInt CPhysicalLinksManager::GetBasebandLinkState(TBTBasebandLinkState& aBasebandLinkState, const TBTDevAddr& aBDAddr) const
+ {
+ const CPhysicalLink* const phy(FindPhysicalLink(aBDAddr));
+
+ if (!phy)
+ {
+ // In the event of an error the client should not inspect
+ // aBasebandLinkState.
+ return KErrNotFound;
+ }
+
+ aBasebandLinkState = phy->LinkState();
+ return KErrNone;
+ }
+
+
+//
+// TPageTimeoutController
+//
+
+TPageTimeoutController::TPageTimeoutController(MHCICommandQueue& aCommandQueue)
+ : iCommandQueue(aCommandQueue)
+ , iOutstandingCommands(0)
+ {
+ }
+
+void TPageTimeoutController::Abort()
+ {
+ iCommandQueue.MhcqRemoveAllCommands(*this);
+ }
+
+void TPageTimeoutController::WritePageTimeout(TBasebandTime aPageTimeout)
+ {
+ // Setting the page-timeout is typically best effort, hence this non-erroring
+ // API.
+ TRAP_IGNORE(WritePageTimeoutL(aPageTimeout));
+ }
+
+void TPageTimeoutController::MhcqcCommandEventReceived(const THCIEventBase& /*aEvent*/, const CHCICommandBase* /*aRelatedCommand*/)
+ {
+ // Nothing else needs to be done.
+ --iOutstandingCommands;
+ }
+
+void TPageTimeoutController::MhcqcCommandErrored(TInt /*aErrorCode*/, const CHCICommandBase* /*aCommand*/)
+ {
+ // This is a best effort service so errors are just dropped.
+ --iOutstandingCommands;
+ }
+
+void TPageTimeoutController::WritePageTimeoutL(TBasebandTime aPageTimeout)
+ {
+ if(iOutstandingCommands)
+ {
+ // best effort removal of any existing command on the queue.
+ static_cast<void>(iCommandQueue.MhcqRemoveCommand(iLastCommandId, *this));
+ }
+ CWritePageTimeoutCommand* cmd = CWritePageTimeoutCommand::NewL(aPageTimeout);
+ // ownership of cmd is taken by command queue.
+ iLastCommandId = iCommandQueue.MhcqAddCommandL(cmd, *this); // "leak" any previous command id.
+ ++iOutstandingCommands;
+ }
+
+
+
+CBluetoothPrefetchManager* CBluetoothPrefetchManager::NewL()
+ {
+ CBluetoothPrefetchManager* self = new(ELeave) CBluetoothPrefetchManager;
+ return self;
+ }
+
+CBluetoothPrefetchManager::CBluetoothPrefetchManager()
+ {
+ }
+
+CBluetoothPrefetchManager::~CBluetoothPrefetchManager()
+ {
+ while(iPinRequesters.Count() > 0)
+ {
+ iPinRequesters[0].CompleteRequest(KErrCancel);
+ iPinRequesters.Remove(0);
+ }
+ iPinRequesters.Close();
+ }
+
+TBool CBluetoothPrefetchManager::CompareAddressInRequest(const TBTDevAddr* aDevAddr, const RPinRequest& aRequest)
+ {
+ return aDevAddr && *aDevAddr == aRequest.iAddr;
+ }
+
+TBool CBluetoothPrefetchManager::CompareAddressInStore(const TBTDevAddr* aDevAddr, const TPrefetchedPin& aPin)
+ {
+ return aDevAddr && *aDevAddr == aPin.iAddr;
+ }
+
+TInt CBluetoothPrefetchManager::HandleOverPinRequester(const TBTDevAddr& aAddr, CBTPinRequester* aPinRequester)
+ {
+ RPinRequest req;
+ TInt err = req.Create(aAddr, aPinRequester);
+ if(err == KErrNone)
+ {
+ err = iPinRequesters.Append(req);
+ }
+ if(err == KErrNone)
+ {
+ aPinRequester->UpdateHandler(*this);
+ }
+ return err;
+ }
+
+TInt CBluetoothPrefetchManager::RegisterForPrefetching(const TBTDevAddr& aAddr, MBluetoothPrefetchNotifier& aNotifier)
+ {
+ TInt ix = iPinRequesters.Find(aAddr, CompareAddressInRequest);
+ if (ix < 0)
+ {
+ return ix;
+ }
+ iPinRequesters[ix].AddNotifier(aNotifier);
+ return KErrNone;
+ }
+
+TBool CBluetoothPrefetchManager::IsPrefetchAvailable(const TBTDevAddr& aAddr, TBTPinCode& aPinCode)
+ {
+ TInt ix = iPrefetchedPins.Find(aAddr, CompareAddressInStore);
+ if (ix < 0)
+ {
+ return EFalse;
+ }
+ aPinCode.Copy(iPrefetchedPins[ix].iPin);
+ iPrefetchedPins.Remove(ix);
+ return ETrue;
+ }
+
+TInt CBluetoothPrefetchManager::PINCodeRequestReply(const TBTDevAddr& aDevAddr, const TDesC8& aPin) const
+ {
+ TInt ix = iPinRequesters.Find(aDevAddr, CompareAddressInRequest);
+ __ASSERT_DEBUG(ix >= 0, Panic(EBTPrefetchManagerReplyForNoRequest));
+
+ // Always check if someone is prefetching before storing a prefetch result.
+ TInt result = EBTSecManAccessDenied;
+ if(iPinRequesters[ix].NotifiersWaiting())
+ {
+ TPrefetchedPin pin;
+ pin.iAddr = aDevAddr;
+ pin.iPin.Copy(aPin);
+ result = iPrefetchedPins.Append(pin);
+ }
+ iPinRequesters[ix].CompleteRequest(result);
+ iPinRequesters.Remove(ix);
+ return KErrNone;
+ }
+
+TInt CBluetoothPrefetchManager::PINCodeRequestNegativeReply(const TBTDevAddr& aDevAddr) const
+ {
+ TInt ix = iPinRequesters.Find(aDevAddr, CompareAddressInRequest);
+ __ASSERT_DEBUG(ix >= 0, Panic(EBTPrefetchManagerReplyForNoRequest));
+ iPinRequesters[ix].CompleteRequest(EBTSecManAccessDenied);
+ iPinRequesters.Remove(ix);
+ return KErrNone;
+ }
+
+CBluetoothPrefetchManager::RPinRequest::RPinRequest()
+ : iNotifiers(NULL)
+ {
+ }
+
+TInt CBluetoothPrefetchManager::RPinRequest::Create(const TBTDevAddr& aAddr, CBTPinRequester* aPinRequester)
+ {
+ iAddr = aAddr;
+ iPinRequester = aPinRequester;
+ iNotifiers = new TDblQue<TPrefetchNotifierQLink>();
+ return iNotifiers ? KErrNone : KErrNoMemory;
+ }
+
+void CBluetoothPrefetchManager::RPinRequest::AddNotifier(MBluetoothPrefetchNotifier& aNotifier)
+ {
+ iNotifiers->AddLast(aNotifier.MbpnQueLink());
+ }
+
+TBool CBluetoothPrefetchManager::RPinRequest::NotifiersWaiting() const
+ {
+ return !iNotifiers->IsEmpty();
+ }
+
+void CBluetoothPrefetchManager::RPinRequest::CompleteRequest(TInt aError)
+ {
+ while(!iNotifiers->IsEmpty())
+ {
+ MBluetoothPrefetchNotifier* notifier = iNotifiers->First()->Item();
+ ASSERT_DEBUG(notifier);
+ notifier->MbpnQueLink().Deque();
+ notifier->MbpnPrefetchComplete(aError);
+ }
+ delete iPinRequester;
+ iPinRequester = NULL;
+ delete iNotifiers;
+ iNotifiers = NULL;
+ }
+
+