bluetooth/btstack/linkmgr/physicallinksmanager.cpp
changeset 0 29b1cd4cb562
child 14 f8503e232b0c
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Implementation of physical links manager
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <bluetooth/logger.h>
       
    19 #include "physicallinksmanager.h"
       
    20 #include "physicallinks.h"
       
    21 #include "hcifacade.h"
       
    22 #include "Basebandmodel.h"
       
    23 #include "ProxySAP.h"
       
    24 
       
    25 #include <bt_sock.h>
       
    26 #include "PhysicalLinkHelper.h"
       
    27 #include "hostresolver.h"
       
    28 
       
    29 #include <bluetooth/hci/writepagetimeoutcommand.h>
       
    30 
       
    31 #ifdef __FLOG_ACTIVE
       
    32 _LIT8(KLogComponent, LOG_COMPONENT_LINKMGR);
       
    33 #endif
       
    34 
       
    35 #ifdef _DEBUG
       
    36 PANICCATEGORY("plinkmgr");
       
    37 #endif
       
    38 
       
    39 // macro to dump invalid commands from hardware
       
    40 #define	RETURN_IF_NULL_CONNECTION(found) {if (!found) {LOG(_L("CPhysicalLinksManager: Bad event received - dropping")); return;}}
       
    41 
       
    42 
       
    43 CPhysicalLinksManager* CPhysicalLinksManager::NewL(CLinkMgrProtocol& aLinkMgrProtocol,
       
    44 												   CHCIFacade& aHCIFacade,
       
    45 												   CRegistrySession& aRegSess,
       
    46 												   CBTSecMan& aSecMan,
       
    47 												   CBTCodServiceMan& aCodMan)
       
    48 	{
       
    49 	CPhysicalLinksManager* s = new(ELeave) CPhysicalLinksManager(aLinkMgrProtocol,
       
    50 																 aHCIFacade,
       
    51 																 aRegSess,
       
    52 																 aSecMan,
       
    53 																 aCodMan);
       
    54 	CleanupStack::PushL(s);
       
    55 	s->ConstructL();
       
    56 	CleanupStack::Pop(s);
       
    57 	return s;
       
    58 	}
       
    59 
       
    60 CPhysicalLinksManager::CPhysicalLinksManager(CLinkMgrProtocol& aLinkMgrProtocol,
       
    61 											 CHCIFacade& aHCIFacade,
       
    62 											 CRegistrySession& aRegSess,
       
    63 											 CBTSecMan& aSecMan,
       
    64 											 CBTCodServiceMan& aCodMan)
       
    65 	: iPhysicalLinks(KBTBasebandConnectionArrayGranularity)
       
    66 	, iHCIRequestHandler(aHCIFacade)
       
    67 	, iRegSess(aRegSess)
       
    68 	, iSecMan(aSecMan)
       
    69 	, iCodMan(aCodMan)
       
    70 	, iLinkManagerProtocol(aLinkMgrProtocol)
       
    71 	, iTerminatingProxy(NULL)
       
    72 	, iTerminatingConnection(NULL)
       
    73 	, iRoleSwitchersQ(_FOFF(CRoleSwitcher, iQLink))
       
    74 	, iPageTimeoutController(aHCIFacade.CommandQController())
       
    75 	{
       
    76 	}
       
    77 
       
    78 void CPhysicalLinksManager::ConstructL()
       
    79 	{
       
    80 	iPairingsCache = CBTPairingsCache::NewL(*this, iRegSess.RegServ());
       
    81 	iBaseband = CBTBasebandModel::NewL(iLinkManagerProtocol);
       
    82 	iPrefetchMan = CBluetoothPrefetchManager::NewL();
       
    83 	}
       
    84 
       
    85 CPhysicalLinksManager::~CPhysicalLinksManager()
       
    86 	{
       
    87 	LOG(_L("sec\tCBTConnectionsManager destructing"));
       
    88 
       
    89 	iPageTimeoutController.Abort();
       
    90 
       
    91 	iPhysicalLinks.ResetAndDestroy();
       
    92 	iPhysicalLinks.Close();
       
    93 	__ASSERT_ALWAYS(iRoleSwitchersQ.IsEmpty(), Panic(ERoleSwitchersNotDeleted));
       
    94 	iListeners.Close();
       
    95 
       
    96 	delete iBaseband;
       
    97 	delete iRoleSwitcherStateFactory;
       
    98 	delete iPairingsCache;
       
    99 	delete iPrefetchMan;
       
   100 	}
       
   101 
       
   102 void CPhysicalLinksManager::RequireSlotSpace()
       
   103 /**
       
   104 	At present we put all those connections that are holdable into hold
       
   105 	To release baseband space for certain activities such
       
   106 	as device discovery
       
   107 
       
   108 	In future other operations may be performed here...
       
   109 **/
       
   110 	{
       
   111 	if (LinkManagerProtocol().IsModeSupportedLocally(EHoldMode))
       
   112 		{
       
   113 		CPhysicalLink* con = NULL;
       
   114 		// locally can support Hold mode - see if we can free up links that do
       
   115 		TInt count = iPhysicalLinks.Count();
       
   116 
       
   117 		for (TInt i=(count-1); i>=0; i--)
       
   118 			{
       
   119 			con = iPhysicalLinks[i];
       
   120 			static_cast<void>(con->RequestHold()); //ignore error - best effort
       
   121 			}
       
   122 		}
       
   123 	}
       
   124 
       
   125 TBasebandTime CPhysicalLinksManager::TryToChangePageTimeout(TBasebandTime aPageTimeout)
       
   126 	{
       
   127 	// First check the page timeout is suitable wrt. link supervision timeouts.
       
   128 	aPageTimeout = CheckPageTimeoutAgainstLSTO(aPageTimeout);
       
   129 	iPageTimeoutController.WritePageTimeout(aPageTimeout);
       
   130 	return aPageTimeout; // return the timeout that was tried (not necessarily set).
       
   131 	}
       
   132 
       
   133 CPhysicalLink& CPhysicalLinksManager::NewPhysicalLinkL(const TBTDevAddr& aAddr)
       
   134 	{
       
   135 	// create a PHY just knowing its address
       
   136 	TBTNamelessDevice device;
       
   137 	device.SetAddress(aAddr);
       
   138 	return NewPhysicalLinkL(device);
       
   139 	}
       
   140 
       
   141 CPhysicalLink& CPhysicalLinksManager::NewPhysicalLinkL(const TBTNamelessDevice& aDevice)
       
   142 	{
       
   143 	// create a PHY with a full Device - make sure it isn't us!
       
   144 	if (aDevice.Address() == iLinkManagerProtocol.LocalBTAddress())
       
   145 		{
       
   146 		// the app may be at fault - so don't panic
       
   147 		User::Leave(KErrReflexiveBluetoothLink);
       
   148 		}
       
   149 
       
   150 	// create role switch SM
       
   151 	// delete is in destructor of CPhysicalLinksManager
       
   152 	if (!iRoleSwitcherStateFactory)
       
   153 		{
       
   154 		iRoleSwitcherStateFactory = CRoleSwitcherStateFactory::NewL();
       
   155 		}
       
   156 	
       
   157 	CPhysicalLink* phy = CPhysicalLink::NewLC(*this, iRegSess, aDevice);
       
   158 	User::LeaveIfError(iPhysicalLinks.Append(phy)); //transfers ownership
       
   159 	
       
   160 	CleanupStack::Pop(phy);
       
   161 	LOG1(_L("CPhysicalLinksManager: Number of physical links %d"), iPhysicalLinks.Count());
       
   162 	return *phy;
       
   163 	}
       
   164 
       
   165 CPhysicalLink* CPhysicalLinksManager::FindPhysicalLink(const TBTDevAddr& aBDAddr) const
       
   166 	{
       
   167 	CPhysicalLink* con = NULL;
       
   168 	CPhysicalLink* found = NULL;
       
   169 	
       
   170 	
       
   171 	TInt count = iPhysicalLinks.Count();
       
   172 
       
   173 	for (TInt i=(count-1); i>=0; i--)
       
   174 		{
       
   175 		con = iPhysicalLinks[i];
       
   176 
       
   177 		if (con->BDAddr() == aBDAddr)
       
   178 			{
       
   179 #ifndef _DEBUG
       
   180 			found = con;
       
   181 			break;
       
   182 #else
       
   183 			if (found) //make sure there's only one
       
   184 				{
       
   185 				__DEBUGGER()
       
   186 				}
       
   187 			else
       
   188 				{
       
   189 				found = con;
       
   190 				continue; // just to show we do want to!
       
   191 				}
       
   192 #endif
       
   193 			}
       
   194 		}
       
   195 	return found;
       
   196 	}
       
   197 
       
   198 void CPhysicalLinksManager::DumpPhysicalLinks()
       
   199 	{
       
   200 #ifdef __FLOG_ACTIVE
       
   201 	TInt count = iPhysicalLinks.Count();
       
   202 
       
   203 	CPhysicalLink* con = NULL;
       
   204 	for (TInt i=(count-1); i>=0; i--)
       
   205 		{
       
   206 		con = iPhysicalLinks[i];
       
   207 		LOG(_L(" - Link: "));
       
   208 		LOGBTDEVADDR(con->BDAddr());
       
   209 		}
       
   210 #endif
       
   211 	}
       
   212 
       
   213 TBool CPhysicalLinksManager::IsAcceptPairedOnlyMode()
       
   214 	{
       
   215 	return iAcceptPairedOnlyMode;
       
   216 	}
       
   217 
       
   218 CPhysicalLink* CPhysicalLinksManager::FindPhysicalLink(THCIConnHandle aConnH) const
       
   219 /**
       
   220 	Handy for when a disconnection comes in - disconnections dont give either
       
   221 	the address or (if SCO) the 'bound' handle.
       
   222 
       
   223 	This method asks each CPhysicalLink if it knows of the handle (ACL or SCO)
       
   224 **/
       
   225 	{
       
   226 	CPhysicalLink* con = NULL;
       
   227 	CPhysicalLink* found = NULL;
       
   228 	
       
   229 	TInt count = iPhysicalLinks.Count();
       
   230 	for (TInt i=(count-1); i>=0; i--)
       
   231 		{
       
   232 		con = iPhysicalLinks[i];
       
   233 		if (con->HasHandle(aConnH))
       
   234 			{
       
   235 #ifndef _DEBUG
       
   236 			found = con;
       
   237 			break;
       
   238 #else
       
   239 			if (found) //make sure there's only one
       
   240 				{
       
   241 				__DEBUGGER()
       
   242 				}
       
   243 			else
       
   244 				{
       
   245 				found = con;
       
   246 				continue; // just to show we do want to!
       
   247 				}
       
   248 #endif
       
   249 			}
       
   250 		}
       
   251 	return found;
       
   252 	}
       
   253 
       
   254 CPhysicalLink* CPhysicalLinksManager::FindPhysicalLink() const
       
   255 /**
       
   256 	Handy for finding a random connected PHY
       
   257 **/
       
   258 	{
       
   259 	CPhysicalLink* con = NULL;
       
   260 	CPhysicalLink* found = NULL;
       
   261 
       
   262 
       
   263 	TInt count = iPhysicalLinks.Count();
       
   264 	if(!count)
       
   265 		{
       
   266 		return NULL;
       
   267 		}
       
   268 	for (TInt i=(count-1); i>=0; i--)
       
   269 		{
       
   270 		con = iPhysicalLinks[i];
       
   271 		if (con->Handle()!=KHCIBroadcastHandle)
       
   272 			{
       
   273 			found = con;
       
   274 			break;
       
   275 			}
       
   276 		}
       
   277 	return found;
       
   278 	}
       
   279 
       
   280 TLogicalLinkListener* CPhysicalLinksManager::FindListener(TPhysicalLinkPort aPort)
       
   281 	{
       
   282 	// go through listeners until we find a listener on the required port
       
   283 	TLogicalLinkListener* found = NULL;
       
   284 	TLogicalLinkListener* l = NULL;
       
   285 
       
   286 	TInt count = iListeners.Count();
       
   287 	for (TInt i=(count-1); i>=0; i--)
       
   288 		{
       
   289 		l = &iListeners[i];
       
   290 		if (l->iPort == aPort)
       
   291 			{
       
   292 			found = l;
       
   293 			break;
       
   294 			}
       
   295 		}
       
   296 
       
   297 	return found;
       
   298 	}
       
   299 
       
   300 void CPhysicalLinksManager::ClearTerminatingProxy(CBTProxySAP* aProxySAP)
       
   301 	{
       
   302 	if (aProxySAP==iTerminatingProxy)
       
   303 		{
       
   304 		iTerminatingProxy=NULL;
       
   305 		}
       
   306 	}
       
   307 	
       
   308 void CPhysicalLinksManager::UpdateTerminatingProxy(CBTProxySAP* aProxySAP)
       
   309 	{
       
   310 	// If there is an outstanding terminate request for a different Proxy SAP
       
   311 	// complete it here and deal with the new request
       
   312 	if (iTerminatingProxy && (iTerminatingProxy!=aProxySAP))
       
   313 		{
       
   314 		iTerminatingProxy->TerminatePhysicalLinksComplete();
       
   315 		}
       
   316 	iTerminatingProxy=aProxySAP;
       
   317 	}
       
   318 	
       
   319 TInt CPhysicalLinksManager::TerminateAllPhysicalLinks(CBTProxySAP* aProxySAP)
       
   320 	{
       
   321 	TInt count=iPhysicalLinks.Count();
       
   322 	TInt retVal = (count==0) ? KErrNotFound : KErrNone;
       
   323 		
       
   324 	for (TInt i=0; i<count; i++)
       
   325 		{
       
   326 		// If any one of the physical links return an error then this 
       
   327 		// function needs to return an error.
       
   328 		TInt err = iPhysicalLinks[i]->Terminate(ERemoteUserEndedConnection);
       
   329 		if (err != KErrNone)
       
   330 			{
       
   331 			retVal=err;
       
   332 			}
       
   333 		}
       
   334 		
       
   335 	// aProxy==NULL	means that the calling Proxy SAP does not want to be told when the
       
   336 	// physical link has terminated
       
   337 	if ((retVal==KErrNone) || !aProxySAP)
       
   338 		{
       
   339 		UpdateTerminatingProxy(aProxySAP);
       
   340 		}
       
   341 	
       
   342 	return retVal;
       
   343 	}
       
   344 
       
   345 TInt CPhysicalLinksManager::TerminatePhysicalLink(CPhysicalLink* aConnection, CBTProxySAP* aProxySAP)
       
   346 	{
       
   347 	TInt count = iPhysicalLinks.Count();
       
   348 	TInt retVal=KErrNotFound;
       
   349 	for (TInt i=(count-1); i>=0; i--)
       
   350 		{
       
   351 		if (iPhysicalLinks[i]==aConnection)
       
   352 			{
       
   353 			retVal=iPhysicalLinks[i]->Terminate(ERemoteUserEndedConnection);
       
   354 			break;	
       
   355 			}
       
   356 		}
       
   357 	
       
   358 	// aProxy==NULL	means that the calling Proxy SAP does not want to be told when the
       
   359 	// physical link has terminated
       
   360 	if ((retVal==KErrNone) || !aProxySAP)
       
   361 		{
       
   362 		UpdateTerminatingProxy(aProxySAP);
       
   363 		iTerminatingConnection=aConnection;
       
   364 		}
       
   365 	
       
   366 	return retVal;
       
   367 	}
       
   368 
       
   369 void CPhysicalLinksManager::UpdateRemoteDevicesDetails()
       
   370 	{
       
   371 	//Update paired device list
       
   372 	iPairingsCache->UpdateCache();
       
   373 	
       
   374 	//Update cached device info for existing PHYs
       
   375 	TInt count=iPhysicalLinks.Count();
       
   376 	for (TInt i=0; i<count; i++)
       
   377 		{
       
   378 		// try to get details of remote device
       
   379 		TRAP_IGNORE(iPhysicalLinks[i]->GetDeviceFromRegistryL());
       
   380 		// ignore error - as with other registry accessing routines
       
   381 		}
       
   382 	}
       
   383 
       
   384 void CPhysicalLinksManager::SetAcceptPairedOnlyMode(TBool aOn)
       
   385 	{
       
   386 	iAcceptPairedOnlyMode = aOn;
       
   387 	LinkManagerProtocol().SetAcceptPairedOnlyMode(aOn);
       
   388 	}
       
   389 
       
   390 
       
   391 void CPhysicalLinksManager::SetSimplePairingDebugMode(TBool aOn)
       
   392 	{
       
   393 	if(!SecMan().LocalSimplePairingMode())
       
   394 		{
       
   395 		LOG(_L("CPhysicalLinksManager: Simple pairing not supported by controller - ignoring request for debug mode"));
       
   396 		return;
       
   397 		}
       
   398 	if(aOn)
       
   399 		{
       
   400 		iSecMan.SetDebugMode(aOn);
       
   401 		}
       
   402 	}
       
   403 
       
   404 void CPhysicalLinksManager::SimplePairingDebugModeChanged(TBool aOn)
       
   405 	{
       
   406 	LinkManagerProtocol().SetSimplePairingDebugMode(aOn);
       
   407 	}
       
   408 
       
   409 void CPhysicalLinksManager::FatalError(TInt /*aErr*/)
       
   410 	{
       
   411 	// simulate a disconnection complete on all PHYs
       
   412 	TInt count=iPhysicalLinks.Count();
       
   413 
       
   414 	//The call to l.Disconnection removes an element from array iPhysicalLink, therefore invalidates 
       
   415 	//count. So it's best iterating through the array backwards because count is only used for 
       
   416 	//initialising i, and i is always valid. 
       
   417 	for (TInt i=count-1; i>=0; i--)
       
   418 		{
       
   419 		// we say remote, as this is a passive-like disconnection
       
   420 		CPhysicalLink& l = *iPhysicalLinks[i];
       
   421 		l.Disconnection(EHardwareFail, l.Handle(), EHardwareFail);
       
   422 		}
       
   423 
       
   424 	// Don't error the Listeners
       
   425 	}
       
   426 
       
   427 void CPhysicalLinksManager::NewLinkKey(const TBTDevAddr& aBDAddr, const TBTLinkKey& aLinkKey, THCILinkKeyType aLinkKeyType)
       
   428 	{
       
   429 	CPhysicalLink* found = FindPhysicalLink(aBDAddr);
       
   430 	RETURN_IF_NULL_CONNECTION(found);
       
   431 	found->NewLinkKey(aBDAddr, aLinkKey, aLinkKeyType);
       
   432 	}
       
   433 
       
   434 void CPhysicalLinksManager::RemovePhysicalLink(const CPhysicalLink& aConnection)
       
   435 /**
       
   436 	A Physical Link wants us to remove our knowledge of it
       
   437 **/
       
   438 	{
       
   439 	TInt count = iPhysicalLinks.Count();
       
   440 	TInt i;
       
   441 	for (i=(count-1); i>=0; i--)
       
   442 		{
       
   443 		if (iPhysicalLinks[i]==&aConnection)
       
   444 			{
       
   445 			iPhysicalLinks.Remove(i);
       
   446 			count--;
       
   447 			break;
       
   448 			}
       
   449 		}
       
   450 		
       
   451 	if (count!=0)
       
   452 		{
       
   453 		//compress the array if needs be
       
   454 		if (i!=count)
       
   455 			{
       
   456 			iPhysicalLinks.GranularCompress();
       
   457 			}
       
   458 
       
   459 		// A physical link has been removed. Arbitrate for role switch allowed 
       
   460 		// on the remainder of the links.
       
   461 		ArbitrateAllPhysicalLinks();
       
   462 		}
       
   463 	
       
   464 	// IF we have a Terminate request from a ProxySAP AND
       
   465 	// either it was a request to terminate all connections and we have no connections left OR
       
   466 	// it was a request for a specific connection that we have just removed THEN
       
   467 	// tell the Proxy SAP that the request is complete
       
   468 	if (iTerminatingProxy && 
       
   469 		((!iTerminatingConnection && (count==0)) || 
       
   470 		 ((iTerminatingConnection==&aConnection) && (i!=-1))))
       
   471 		{
       
   472 		iTerminatingProxy->TerminatePhysicalLinksComplete();
       
   473 		iTerminatingProxy=NULL;
       
   474 		iTerminatingConnection=NULL;
       
   475 		}
       
   476 	
       
   477 	// good time to update that UI
       
   478 	LinkManagerProtocol().SetUINumPhysicalLinks(count);
       
   479 	LOG1(_L("CPhysicalLinksManager: Number of physical links %d"), count);
       
   480 	}
       
   481 
       
   482 void CPhysicalLinksManager::ArbitrateAllPhysicalLinks()
       
   483 	{
       
   484 	TInt i;
       
   485 	for (i=(iPhysicalLinks.Count()-1); i>=0; i--)
       
   486 		{
       
   487 		iPhysicalLinks[i]->Arbitrate();
       
   488 		}
       
   489 	}
       
   490 
       
   491 void CPhysicalLinksManager::SimplePairingComplete(const TBTDevAddr& aBDAddr, THCIErrorCode /*aErr*/)
       
   492 	{
       
   493 	//find the connection and pass on the request
       
   494 	CPhysicalLink* found = FindPhysicalLink(aBDAddr);
       
   495 	RETURN_IF_NULL_CONNECTION(found);
       
   496 	found->AuthenticationComplete(ESimplePairingPending);
       
   497 	}
       
   498 
       
   499 void CPhysicalLinksManager::PinRequest(const TBTDevAddr& aBDAddr,
       
   500 										MPINCodeResponseHandler& aRequester)
       
   501 	{
       
   502 	//find the connection and pass on the request
       
   503 	CPhysicalLink* found = FindPhysicalLink(aBDAddr);
       
   504 	RETURN_IF_NULL_CONNECTION(found);
       
   505 	found->PinRequest(aBDAddr, aRequester);
       
   506 	}
       
   507 
       
   508 void CPhysicalLinksManager::LinkKeyRequest(const TBTDevAddr& aBDAddr, MLinkKeyResponseHandler& aRequester)
       
   509 	{
       
   510 	CPhysicalLink* found = FindPhysicalLink(aBDAddr);
       
   511 	RETURN_IF_NULL_CONNECTION(found);
       
   512 	found->LinkKeyRequest(aBDAddr, aRequester);
       
   513 	}
       
   514 
       
   515 void CPhysicalLinksManager::ReadRemoteSupportedFeaturesComplete(THCIErrorCode aErr, THCIConnHandle aConnH, const TBTFeatures& aBitMask)
       
   516 	{
       
   517 	CPhysicalLink* found = FindPhysicalLink(aConnH);
       
   518 	RETURN_IF_NULL_CONNECTION(found);
       
   519 	found->ReadRemoteSupportedFeaturesComplete(aErr, aConnH, aBitMask);
       
   520 	}
       
   521 
       
   522 void CPhysicalLinksManager::ReadRemoteExtendedFeaturesComplete(THCIErrorCode aErr, THCIConnHandle aConnH, TUint64 aBitMask, TUint8 aPageNumber, TUint8 aMaximumPageNumber)
       
   523 	{
       
   524 	CPhysicalLink* found = FindPhysicalLink(aConnH);
       
   525 	RETURN_IF_NULL_CONNECTION(found);
       
   526 	found->ReadRemoteExtendedFeaturesComplete(aErr, aConnH, aBitMask, aPageNumber, aMaximumPageNumber);
       
   527 	}
       
   528 
       
   529 
       
   530 void CPhysicalLinksManager::ReadRemoteVersionInfoComplete(THCIErrorCode aErr, THCIConnHandle aConnH, const TBTDevRemoteHwVersion& aVer)
       
   531 	{
       
   532 	CPhysicalLink* found = FindPhysicalLink(aConnH);
       
   533 	RETURN_IF_NULL_CONNECTION(found);
       
   534 	found->ReadRemoteVersionInfoComplete(aErr, aConnH, aVer);
       
   535 	}
       
   536 
       
   537 void CPhysicalLinksManager::PacketTypeChange(THCIErrorCode aErr, THCIConnHandle aConnH, TUint16 aNewPacket)
       
   538 	{
       
   539 	CPhysicalLink* found = FindPhysicalLink(aConnH);
       
   540 	RETURN_IF_NULL_CONNECTION(found);
       
   541 	found->PacketTypeChange(aErr, aConnH, aNewPacket);
       
   542 	}
       
   543 
       
   544 void CPhysicalLinksManager::LinkSupervisionTimeoutChange(THCIErrorCode aErr, THCIConnHandle aConnH, TUint16 aNewTimeout)
       
   545 	{
       
   546 	CPhysicalLink* found = FindPhysicalLink(aConnH);
       
   547 	RETURN_IF_NULL_CONNECTION(found);
       
   548 	found->LinkSupervisionTimeoutChange(aErr, aConnH, aNewTimeout);
       
   549 	}
       
   550 
       
   551 TBasebandTime CPhysicalLinksManager::CheckPageTimeoutAgainstLSTO(TBasebandTime aPageTimeout)
       
   552 	{
       
   553 	// Calculate the page timeout:
       
   554 	//   Iterate through all physical links, and take the minimum
       
   555 	//   LSTO of them all. This is maximum possible page timeout value
       
   556 	TInt connections = iPhysicalLinks.Count();
       
   557 	TInt newPageTimeout = aPageTimeout;
       
   558 	for(TInt i = 0; i < connections; i++)
       
   559 		{
       
   560 		// Reduce pageTimeout if greater than LSTO for any physical link
       
   561 		// LSTO could be zero if no LSTO event received; ignore zero values
       
   562 		TUint lsto = iPhysicalLinks[i]->LSTO();
       
   563 		if (lsto > 0 && newPageTimeout > lsto)
       
   564 			{
       
   565 			newPageTimeout = lsto;
       
   566 			}
       
   567 		}
       
   568 	
       
   569 	// The pageTimeout has been changed. Ensure it is 5% less
       
   570 	// than the minimum LSTO that it has already been set to.
       
   571 	if (newPageTimeout != aPageTimeout)
       
   572 		{
       
   573 		const TReal32 KNinetyFivePercentMultiplier = 0.95;
       
   574 		newPageTimeout = newPageTimeout * KNinetyFivePercentMultiplier; // Reduce by 5%
       
   575 		}
       
   576 	return newPageTimeout;
       
   577 	}
       
   578 
       
   579 void CPhysicalLinksManager::MaxSlotsChange(THCIConnHandle aConnH, TUint8 aSlots)
       
   580 	{
       
   581 	CPhysicalLink* found = FindPhysicalLink(aConnH);
       
   582 	RETURN_IF_NULL_CONNECTION(found);
       
   583 	found->MaxSlotsChange(aConnH, aSlots);
       
   584 	}
       
   585 
       
   586 void CPhysicalLinksManager::ModeChange(THCIErrorCode aErr, THCIConnHandle aConnH, TBTLinkMode aMode, TBasebandTime aInterval)
       
   587 	{
       
   588 	CPhysicalLink* found = FindPhysicalLink(aConnH);
       
   589 	RETURN_IF_NULL_CONNECTION(found);
       
   590 	found->ModeChange(aErr, aConnH, aMode, aInterval);
       
   591 	}
       
   592 
       
   593 void CPhysicalLinksManager::RoleChange(THCIErrorCode aErr, const TBTDevAddr& aAddr, TBTBasebandRole aRole)
       
   594 	{
       
   595 	// interesting that this is an address, not a Conn handle! Good old H:1.
       
   596 	CPhysicalLink* found = FindPhysicalLink(aAddr);
       
   597 	RETURN_IF_NULL_CONNECTION(found);
       
   598 	found->RoleChange(aErr, aAddr, aRole);
       
   599 	}
       
   600 
       
   601 void CPhysicalLinksManager::WriteLinkPolicySettingsCompleteEvent(THCIErrorCode aErr, THCIConnHandle aConnH)
       
   602 	{
       
   603 	CPhysicalLink* found = FindPhysicalLink(aConnH);
       
   604 	RETURN_IF_NULL_CONNECTION(found);
       
   605 	found->WriteLinkPolicySettingsCompleteEvent(aErr, aConnH);
       
   606 	}
       
   607 
       
   608 void CPhysicalLinksManager::ClockOffset(THCIErrorCode aErr, THCIConnHandle aConnH, TBasebandTime aClockOffset)
       
   609 	{
       
   610 	CPhysicalLink* found = FindPhysicalLink(aConnH);
       
   611 	RETURN_IF_NULL_CONNECTION(found);
       
   612 	found->ClockOffset(aErr, aConnH, aClockOffset);
       
   613 	}
       
   614 
       
   615 void CPhysicalLinksManager::RemoteName(THCIErrorCode aErr, const TBTDevAddr& aAddr, const TBTDeviceName8& aName)
       
   616 	{
       
   617 	CPhysicalLink* found = FindPhysicalLink(aAddr);
       
   618 	RETURN_IF_NULL_CONNECTION(found);
       
   619 	found->RemoteName(aErr, aAddr, aName);
       
   620 	}
       
   621 
       
   622 void CPhysicalLinksManager::ConnectionComplete(THCIErrorCode aErr, const TBTConnect& aConn)
       
   623 	{
       
   624 	// we at this stage demux ACL and SCO
       
   625 	CPhysicalLink* phy = FindPhysicalLink(aConn.iBdaddr);
       
   626 
       
   627 	if (!phy)
       
   628 		{
       
   629 		// to be safe we should cancel all outstanding connections of correct type
       
   630 		// since some HW leaves the address blank when errroring a connect
       
   631 		CancelPendingConnections(aErr, aConn);
       
   632 		// disconnect this weirdo link if it came up
       
   633 		if (aErr==EOK)
       
   634 			{
       
   635 			TRAP_IGNORE(HCIFacade().DisconnectL(aConn.iConnH, ERemoteUserEndedConnection));
       
   636 			// if error just have to wait for a timeout
       
   637 			}
       
   638 		}
       
   639 	else
       
   640 		{
       
   641 		phy->ConnectionComplete(aErr, aConn);
       
   642 		// good time to update that UI
       
   643 		LinkManagerProtocol().SetUINumPhysicalLinks(iPhysicalLinks.Count());
       
   644 		}
       
   645 	}
       
   646 
       
   647 void CPhysicalLinksManager::SynchronousConnectionComplete(THCIErrorCode aErr,
       
   648 													const TBTConnect& aConn,
       
   649 													const TBTSyncConnectOpts& aSyncOpts)
       
   650 	{
       
   651 	__ASSERT_DEBUG(((aConn.iLinkType == ESCOLink) || (aConn.iLinkType == EeSCOLink)), Panic(EBTNonSyncConnectInSyncConnectFunc));
       
   652 
       
   653 	if((aConn.iLinkType == ESCOLink) || (aConn.iLinkType == EeSCOLink))
       
   654 		{
       
   655 		CPhysicalLink* phy = FindPhysicalLink(aConn.iBdaddr);
       
   656 
       
   657 		if (!phy)
       
   658 			{
       
   659 			// to be safe we should cancel all outstanding connections of correct type
       
   660 			// since some HW leaves the address blank when errroring a connect
       
   661 			CancelPendingConnections(aErr, aConn);
       
   662 			// disconnect this weirdo link if it came up
       
   663 			if (aErr==EOK)
       
   664 				{
       
   665 				TRAP_IGNORE(HCIFacade().DisconnectL(aConn.iConnH, ERemoteUserEndedConnection));
       
   666 				// if error just have to wait for a timeout
       
   667 				}
       
   668 			}
       
   669 		else
       
   670 			{
       
   671 			phy->SynchronousConnectionComplete(aErr, aConn, aSyncOpts);
       
   672 			// good time to update that UI
       
   673 			LinkManagerProtocol().SetUINumPhysicalLinks(iPhysicalLinks.Count());
       
   674 			}
       
   675 		}
       
   676 	else
       
   677 		{
       
   678 		TRAP_IGNORE(HCIFacade().DisconnectL(aConn.iConnH, ERemoteUserEndedConnection));
       
   679 		}
       
   680 	}
       
   681 
       
   682 void CPhysicalLinksManager::MbpcoDeferredDecisionResolved(TInt aError)
       
   683 	{
       
   684 	// See if any connection requests are pending,
       
   685 	// having been held up whilst the stack was
       
   686 	// being updated with all paired devices
       
   687 	// in the registry.
       
   688 	for(TInt i = iPhysicalLinks.Count() - 1; i>=0; i--)
       
   689 		{
       
   690 		if(iPhysicalLinks[i]->IsConnectionRequestPending())
       
   691 			{
       
   692 			iPhysicalLinks[i]->PendingConnectionRequest(aError); //try now we have a list of paired devices
       
   693 			}
       
   694 		}
       
   695 	}
       
   696 
       
   697 TInt CPhysicalLinksManager::AddListener(MLogicalLink& aLogicalLink, TPhysicalLinkPort aPort)
       
   698 	{
       
   699 	TLogicalLinkListener l;
       
   700 	l.iObserver = &aLogicalLink;
       
   701 	l.iPort = aPort;
       
   702 
       
   703 	TInt retVal = KErrNone;
       
   704 
       
   705 	// only allowed one listener on either port at moment
       
   706 	for (TInt i=0; i<iListeners.Count(); i++)
       
   707 		{
       
   708 		if (iListeners[i].iPort == aPort)
       
   709 			{
       
   710 			retVal = KErrInUse;
       
   711 			}
       
   712 		}
       
   713 
       
   714 	if (retVal == KErrNone)
       
   715 		{
       
   716 		retVal = iListeners.Append(l);
       
   717 		if (retVal == KErrNone)
       
   718 			{
       
   719 			retVal = LinkManagerProtocol().IncrementListeners();
       
   720 			}
       
   721 		}
       
   722 	
       
   723 	return retVal;
       
   724 	}
       
   725 
       
   726 /*static*/ TBool CPhysicalLinksManager::ListenerMatch(const TLogicalLinkListener& aA,
       
   727 										   const TLogicalLinkListener& aB)
       
   728 	{
       
   729 	return (aA.iObserver == aB.iObserver);
       
   730 	}
       
   731 
       
   732 void CPhysicalLinksManager::RemoveListener(MLogicalLink& aLogicalLink)
       
   733 	{
       
   734 	__ASSERT_DEBUG(iListeners.Count(), Panic(EBTConnectionMgrCountBelowZero));
       
   735 
       
   736 	TLogicalLinkListener key;
       
   737 	key.iObserver = &aLogicalLink;
       
   738 
       
   739 	TIdentityRelation<TLogicalLinkListener> relation(ListenerMatch);
       
   740 
       
   741 	TInt result = iListeners.Find(key, relation);
       
   742 	__ASSERT_DEBUG(result!=KErrNotFound, Panic(EBTConnectionMgrBadListener));
       
   743 
       
   744 	// remove from listener queue
       
   745 	iListeners.Remove(result);
       
   746 	// and tell protocol we have one fewer
       
   747 	LinkManagerProtocol().DecrementListeners();
       
   748 	// ignore err
       
   749 	}
       
   750 
       
   751 void CPhysicalLinksManager::CancelPendingConnections(THCIErrorCode aErr, const TBTConnect& aConn)
       
   752 /**
       
   753 	When we cannot work out who to notify, we regrettably have to cancel all
       
   754 **/
       
   755 	{
       
   756 	for (TInt index = 0; index < iPhysicalLinks.Count(); index++)
       
   757 		{
       
   758 		CPhysicalLink& l = *iPhysicalLinks[index];
       
   759 		if (   (aConn.iConnH && l.HasHandle(aConn.iConnH))
       
   760 			|| ((aConn.iLinkType == EACLLink) && l.ACLConnectPending())
       
   761 			|| ((aConn.iLinkType != EACLLink) && l.SyncConnectPending())
       
   762 			)
       
   763 			{
       
   764 			l.ConnectionComplete(aErr, aConn);
       
   765 			}
       
   766 		}
       
   767 	}
       
   768 
       
   769 void CPhysicalLinksManager::ConnectionRequest(const TBTConnect& aConn)
       
   770 	{
       
   771 	// we haven't got much to go on to find a Listener
       
   772 	// we don't support directed listening on address
       
   773 	// so just go on link type
       
   774 	// this isn't too bad as Bluetooth only has one ACL listener at the moment: L2CAP
       
   775 	LOG1(_L("Connection request received, link type %d"), aConn.iLinkType);
       
   776 	
       
   777 	switch (aConn.iLinkType)
       
   778 		{
       
   779 		case EACLLink:
       
   780 			{
       
   781 			// this also (see BT1.2) implies that a new PHY is coming up
       
   782 
       
   783 			// Check that either there exist listeners or the protocol knows
       
   784 			// that it should stop listening (even if the message has evidently
       
   785 			// not yet reached the controller).
       
   786 			__ASSERT_DEBUG(iListeners.Count() || !iLinkManagerProtocol.IsListening(), Panic(EBTConnectionRequestWithNoListeners));
       
   787 			if (iListeners.Count())
       
   788 				{
       
   789 				TRAP_IGNORE(DoConnectionRequestL(aConn));
       
   790 				}
       
   791 			else
       
   792 				{
       
   793 				// should never reach here
       
   794 				// leave to timeout - not required
       
   795 				}
       
   796 			}
       
   797 			// ignore err for timeout
       
   798 			break;
       
   799 		case ESCOLink:
       
   800 		case EeSCOLink:
       
   801 			{
       
   802 			// should by a non-listening PHY already in place!
       
   803 			CPhysicalLink* c = FindPhysicalLink(aConn.iBdaddr);
       
   804 			ASSERT_DEBUG(c);
       
   805 			c->ConnectionRequest(aConn);
       
   806 			}
       
   807 		}
       
   808 	}
       
   809 
       
   810 
       
   811 void CPhysicalLinksManager::DoConnectionRequestL(const TBTConnect& aConn)
       
   812 	{
       
   813 	// Only called for ACL links
       
   814 	// ASSERT aConn.iLinkType == EACLLink
       
   815 	
       
   816 	// First check that this is not a request for a duplicate address, some hardware
       
   817 	// can be tediously erratic.
       
   818 	CPhysicalLink* reqAddr = FindPhysicalLink(aConn.iBdaddr);
       
   819 	if (!reqAddr)
       
   820 		{
       
   821 		CPhysicalLink& c = NewPhysicalLinkL(aConn.iBdaddr);
       
   822 		// introduce the first listener to the PHY
       
   823 		// IF WE SUPPORT connections distinguished on aConn then we can find the correct listener 
       
   824 		// now tell the (new) PHY
       
   825 		c.ConnectionRequest(aConn);
       
   826 		}
       
   827 	else
       
   828 		{
       
   829 		// reject incoming connection
       
   830 		LOG(_L("CPhysicalLinksManager: Duplicate address received - reject"));
       
   831 		TRAP_IGNORE(HCIFacade().RejectConnectionRequestL(aConn, EHostSecurityRejection));
       
   832 		}
       
   833 	}
       
   834 
       
   835 void CPhysicalLinksManager::Disconnection(THCIErrorCode aErr, THCIConnHandle aConnH, THCIErrorCode aResult)
       
   836 	{
       
   837 	// notify the correct connection
       
   838 	CPhysicalLink* con = FindPhysicalLink(aConnH);
       
   839 	LOG1(_L("Links manager: disconnection, phys. link 0x%08x"), con);
       
   840 	RETURN_IF_NULL_CONNECTION(con);
       
   841 	con->Disconnection(aErr, aConnH, aResult);
       
   842 	}
       
   843 
       
   844 void CPhysicalLinksManager::CompletedPackets(THCIConnHandle aConnH, TUint16 aNumPackets)
       
   845 	{
       
   846 	// forward to the connections - they can possibly unblock their sockets
       
   847 	CPhysicalLink* con = FindPhysicalLink(aConnH);
       
   848 	RETURN_IF_NULL_CONNECTION(con);
       
   849 	con->CompletedPackets(aConnH, aNumPackets);
       
   850 	
       
   851 	//now unblock all connections to prevent any deadlock
       
   852 	TInt connections = iPhysicalLinks.Count();
       
   853 	for(TInt i = 0; i < connections;i++)
       
   854 		{
       
   855 		CPhysicalLink* other_con = iPhysicalLinks[i];
       
   856 		if(other_con != con)
       
   857 			{
       
   858 			other_con->TryToSend();
       
   859 			}
       
   860 		}
       
   861 	}
       
   862 
       
   863 void CPhysicalLinksManager::AuthenticationComplete(THCIErrorCode aErr, THCIConnHandle aConnH)
       
   864 	{
       
   865 	// tell the anonymous notifiers?  could be useful for updating UI?
       
   866 	CPhysicalLink* con = FindPhysicalLink(aConnH);
       
   867 	RETURN_IF_NULL_CONNECTION(con);
       
   868 	con->AuthenticationComplete(aErr, aConnH);
       
   869 	}
       
   870 
       
   871 void CPhysicalLinksManager::EncryptionChange(THCIErrorCode aErr, THCIConnHandle aConnH,TBool aEncrypted)
       
   872 	{
       
   873 	// tell the anonymous notifiers?  could be useful for updating UI?
       
   874 	CPhysicalLink* con = FindPhysicalLink(aConnH);
       
   875 	RETURN_IF_NULL_CONNECTION(con);
       
   876 	con->EncryptionChange(aErr, aConnH, aEncrypted);
       
   877 	}
       
   878 
       
   879 void CPhysicalLinksManager::ACLDataReceived(THCIConnHandle aConnH, TUint8 aFlag, const TDesC8& aData)
       
   880 	{
       
   881 	CPhysicalLink* con = FindPhysicalLink(aConnH);
       
   882 	RETURN_IF_NULL_CONNECTION(con);
       
   883 	con->ACLDataReceived(aConnH, aFlag, aData);
       
   884 	}
       
   885 
       
   886 void CPhysicalLinksManager::SCODataReceived(THCIConnHandle aConnH, const TDesC8& aData)
       
   887 	{
       
   888 	CPhysicalLink* con = FindPhysicalLink(aConnH);
       
   889 	RETURN_IF_NULL_CONNECTION(con);
       
   890 	con->SCODataReceived(aConnH, aData);
       
   891 	}
       
   892 
       
   893 TInt CPhysicalLinksManager::ChangeMode(TBTLinkMode aMode, THCIConnHandle aConnHandle)
       
   894 	{
       
   895 	return iHCIRequestHandler.ChangeMode(aMode, aConnHandle);
       
   896 	}
       
   897 
       
   898 TInt CPhysicalLinksManager::ExitMode(TBTLinkMode aMode, THCIConnHandle aConnHandle)
       
   899 	{
       
   900 	return iHCIRequestHandler.ExitMode(aMode, aConnHandle);
       
   901 	}
       
   902 
       
   903 TInt CPhysicalLinksManager::ChangeRole(TBTBasebandRole aRole, CPhysicalLink& aPhysicalLink)
       
   904 	{
       
   905 	TRAPD(err, iHCIRequestHandler.ChangeRoleL(aRole, aPhysicalLink.BDAddr()));
       
   906 	return err;
       
   907 	}
       
   908 	
       
   909 TInt CPhysicalLinksManager::Encrypt(TBool aEnable, CPhysicalLink& aPhysicalLink)
       
   910 	{
       
   911 	TRAPD(err, iHCIRequestHandler.SetEncryptL( aPhysicalLink.Handle(), aEnable));
       
   912 	return err;
       
   913 	}
       
   914 	
       
   915 
       
   916 TBool CPhysicalLinksManager::ActiveConnectRoleSwitchAllowed() const
       
   917 	{
       
   918 	// An active connection role change will be allowed in all cases,
       
   919 	// except when there is an existing master connection from this device.
       
   920 	if(iPhysicalLinks.Count() > 1)
       
   921 		{
       
   922 		if(iPhysicalLinks[0]->Role() == EMaster)
       
   923 			{
       
   924 			return EFalse;
       
   925 			}
       
   926 		}
       
   927 	return ETrue;
       
   928 	}
       
   929 
       
   930 TBool CPhysicalLinksManager::PassiveConnectBecomeMaster() const
       
   931 	{
       
   932 	// If this device is currently working as a master for an existing
       
   933 	// connection, request a role switch to master.
       
   934 	return (iPhysicalLinks.Count() > 1 && iPhysicalLinks[0]->Role() == EMaster);
       
   935 	}
       
   936 
       
   937 TBool CPhysicalLinksManager::RoleSwitchAllowed() const
       
   938 	{
       
   939 	// By default the stack will not try and prevent this device scatterneting.
       
   940 	// If the BT hardware can't gracefully cope with requests to scatternet (i.e.,
       
   941 	// disconnects existing phy's if a new scatternet connection is attempted) then
       
   942 	// this macro should be defined.
       
   943 #ifdef HARDWARE_DOES_NOT_SUPPORT_SCATTERNET_OPERATION
       
   944 	return (iPhysicalLinks.Count() <= 1);
       
   945 #else
       
   946 	return ETrue;
       
   947 #endif	
       
   948 	}
       
   949 
       
   950 
       
   951 void CPhysicalLinksManager::EnumeratePhysicalLinks(TDes8& aPackagedArrayBuffer)
       
   952 /**
       
   953 	This method fills the memory passed from the client with a number of TBTDevAddrs.
       
   954 	Useful for control panel apps that need to see what links are present
       
   955 
       
   956 	Because the array passed to us here may be smaller than the number of active links
       
   957 	at this point, we shall return as much as possible in the array.
       
   958 
       
   959 	Also if the array has enough space for more addresses than we currently have, the
       
   960 	descriptor size will be changed to reflect reality.
       
   961 */
       
   962 	{
       
   963 	TInt connections = Min(iPhysicalLinks.Count(),
       
   964 							aPackagedArrayBuffer.MaxLength()/sizeof(TBTDevAddr));
       
   965 	aPackagedArrayBuffer.Zero(); // start from the err.. start and then append
       
   966 
       
   967 	for(TInt i=0; i<connections; i++)
       
   968 		{
       
   969 		if (iPhysicalLinks[i]->IsConnected())
       
   970 			{
       
   971 			TBTDevAddr theDevAddr=iPhysicalLinks[i]->BDAddr();
       
   972 
       
   973 			TPckg<TBTDevAddr> pckg(theDevAddr);
       
   974 			aPackagedArrayBuffer.Append(pckg);
       
   975 			}
       
   976 		}
       
   977 	}
       
   978 
       
   979 void CPhysicalLinksManager::RoleChangeRejectedByHW(THCIErrorCode aErr)
       
   980 	{	
       
   981 	// we can notify the users about Role Change failure on HW with BTBasebandEvent error	
       
   982 	// Make sure the Q is not empty before trying to access First()
       
   983 	if(!iRoleSwitchersQ.IsEmpty())
       
   984     	{
       
   985     	RoleChange(aErr, iRoleSwitchersQ.First()->BDAddr(), iRoleSwitchersQ.First()->RequestedRole());
       
   986 		}
       
   987 	
       
   988 	}
       
   989  
       
   990  void CPhysicalLinksManager::AddRoleSwitcher(CRoleSwitcher& aRoleSwitcher)
       
   991  	{
       
   992  	iRoleSwitchersQ.AddLast( aRoleSwitcher ); // ownership still remains in CPhysicalLink
       
   993  
       
   994  	if (iRoleSwitchersQ.IsFirst(&aRoleSwitcher))
       
   995  		{
       
   996  		// this the only role request, it's safe to kick off the state machine
       
   997  		// first suspend host resolver
       
   998  		LinkManagerProtocol().InquiryMgr().Suspend();
       
   999  		aRoleSwitcher.Start();
       
  1000  		}
       
  1001  	}
       
  1002  
       
  1003  void CPhysicalLinksManager::RemoveRoleSwitcher(CRoleSwitcher& aRoleSwitcher)
       
  1004  	{
       
  1005  	TBool startNextRoleSwitcher = EFalse;
       
  1006  	
       
  1007  	if (iRoleSwitchersQ.IsFirst(&aRoleSwitcher))
       
  1008  		{
       
  1009  		startNextRoleSwitcher = ETrue;
       
  1010  		}
       
  1011  
       
  1012 	if (!iRoleSwitchersQ.IsEmpty())
       
  1013 		{
       
  1014 		iRoleSwitchersQ.Remove(aRoleSwitcher);
       
  1015 		}
       
  1016  	
       
  1017  	if (startNextRoleSwitcher && !iRoleSwitchersQ.IsEmpty())
       
  1018  		{
       
  1019  		iRoleSwitchersQ.First()->Start();
       
  1020  		}
       
  1021  	else 
       
  1022  		{
       
  1023  		// resume host resolver
       
  1024  		LinkManagerProtocol().InquiryMgr().Resume();
       
  1025  		}
       
  1026  	}
       
  1027 
       
  1028 TInt CPhysicalLinksManager::GetConnectionHandles(RHCIConnHandleArray& aConnectionHandles, TLinkType aLinkType) const
       
  1029 	{
       
  1030 	aConnectionHandles.Reset(); // sub-optimal
       
  1031 
       
  1032 	const TInt phycount(iPhysicalLinks.Count());
       
  1033 	if (phycount == 0)
       
  1034 		{
       
  1035 		return KErrNone;
       
  1036 		}
       
  1037 
       
  1038 	TInt err(aConnectionHandles.Reserve(phycount));
       
  1039 
       
  1040 	if (err != KErrNone)
       
  1041 		{
       
  1042 		return err;
       
  1043 		}
       
  1044 
       
  1045 	for (TInt i(0); i < phycount; ++i)
       
  1046 		{
       
  1047 		const CPhysicalLink* const phy(iPhysicalLinks[i]);
       
  1048 		if (!phy)
       
  1049 			{
       
  1050 			return KErrNotFound;
       
  1051 			}
       
  1052 
       
  1053 		// append to aConnectionHandles
       
  1054 		err = phy->GetConnectionHandles(aConnectionHandles, aLinkType);
       
  1055 
       
  1056 		if (err != KErrNone)
       
  1057 			{
       
  1058 			return err;
       
  1059 			}
       
  1060 		}
       
  1061 
       
  1062 	return KErrNone;
       
  1063 	}
       
  1064 
       
  1065 TInt CPhysicalLinksManager::GetNumPendingHandles(TInt& aConnectionHandles, TLinkType aLinkType) const
       
  1066 	{
       
  1067 	aConnectionHandles = 0;
       
  1068 	
       
  1069 	const TInt phycount(iPhysicalLinks.Count());
       
  1070 	if (phycount == 0)
       
  1071 		{
       
  1072 		return KErrNone;
       
  1073 		}
       
  1074 
       
  1075 	for (TInt i(0); i < phycount; ++i)
       
  1076 		{
       
  1077 		const CPhysicalLink* const phy(iPhysicalLinks[i]);
       
  1078 		if (!phy)
       
  1079 			{
       
  1080 			return KErrNotFound;
       
  1081 			}
       
  1082 
       
  1083 		TInt count(0);
       
  1084 		// append to aConnectionHandles
       
  1085 		TInt err(phy->GetNumPendingHandles(count, aLinkType));
       
  1086 
       
  1087 		if (err != KErrNone)
       
  1088 			{
       
  1089 			return err;
       
  1090 			}
       
  1091 
       
  1092 		aConnectionHandles += count;
       
  1093 		}
       
  1094 
       
  1095 	return KErrNone;
       
  1096 	}
       
  1097 
       
  1098 TInt CPhysicalLinksManager::GetConnectionHandles(RHCIConnHandleArray& aConnectionHandles, TLinkType aLinkType, const TBTDevAddr& aBDAddr) const
       
  1099 	{
       
  1100 	aConnectionHandles.Reset(); // sub-optimal
       
  1101 
       
  1102 	const CPhysicalLink* const phy(FindPhysicalLink(aBDAddr));
       
  1103 
       
  1104 	if (!phy)
       
  1105 		{
       
  1106 		// In the event of an error the client should not inspect
       
  1107 		// aConnectionHandle.
       
  1108 		return KErrNotFound;
       
  1109 		}
       
  1110 
       
  1111 	return phy->GetConnectionHandles(aConnectionHandles,
       
  1112 									 aLinkType);
       
  1113 	}
       
  1114 
       
  1115 TInt CPhysicalLinksManager::GetNumPendingHandles(TInt& aConnectionHandles, TLinkType aLinkType, const TBTDevAddr& aBDAddr) const
       
  1116 	{
       
  1117 	aConnectionHandles = 0;
       
  1118 
       
  1119 	const CPhysicalLink* const phy(FindPhysicalLink(aBDAddr));
       
  1120 
       
  1121 	if (!phy)
       
  1122 		{
       
  1123 		// In the event of an error the client should not inspect
       
  1124 		// aConnectionHandle.
       
  1125 		return KErrNotFound;
       
  1126 		}
       
  1127 
       
  1128 	return phy->GetNumPendingHandles(aConnectionHandles, aLinkType);
       
  1129 	}
       
  1130 
       
  1131 TInt CPhysicalLinksManager::GetRemoteAddress(TBTDevAddr& aBDAddr, THCIConnHandle aConnectionHandle) const
       
  1132 	{
       
  1133 	const CPhysicalLink* const phy(FindPhysicalLink(aConnectionHandle));
       
  1134 
       
  1135 	if (!phy)
       
  1136 		{
       
  1137 		// In the event of an error the client should not inspect
       
  1138 		// aBDAddr.
       
  1139 		return KErrNotFound;
       
  1140 		}
       
  1141 
       
  1142 	aBDAddr = phy->BDAddr();
       
  1143 	return KErrNone;
       
  1144 	}
       
  1145 
       
  1146 TInt CPhysicalLinksManager::GetRemoteDeviceClass(TBTDeviceClass& aDeviceClass, const TBTDevAddr& aBDAddr) const
       
  1147 	{
       
  1148 	const CPhysicalLink* const phy(FindPhysicalLink(aBDAddr));
       
  1149 
       
  1150 	if (!phy)
       
  1151 		{
       
  1152 		// In the event of an error the client should not inspect
       
  1153 		// aBasebandLinkState.
       
  1154 		return KErrNotFound;
       
  1155 		}
       
  1156 
       
  1157 	aDeviceClass = phy->DeviceClass();
       
  1158 	return KErrNone;
       
  1159 	}
       
  1160 
       
  1161 TInt CPhysicalLinksManager::GetRemoteSupportedFeatures(TBTFeatures& aRemoteSupportedFeatures, const TBTDevAddr& aBDAddr) const
       
  1162 	{
       
  1163 	const CPhysicalLink* const phy(FindPhysicalLink(aBDAddr));
       
  1164 
       
  1165 	if (!phy)
       
  1166 		{
       
  1167 		// In the event of an error the client should not inspect
       
  1168 		// aRemoteSupportedFeatures.
       
  1169 		return KErrNotFound;
       
  1170 		}
       
  1171 
       
  1172 	aRemoteSupportedFeatures = phy->RemoteFeatures();
       
  1173 	return KErrNone;
       
  1174 	}
       
  1175 
       
  1176 TInt CPhysicalLinksManager::GetLinkPolicySettings(TLinkPolicy& aLinkPolicySettings, const TBTDevAddr& aBDAddr) const
       
  1177 	{
       
  1178 	const CPhysicalLink* const phy(FindPhysicalLink(aBDAddr));
       
  1179 
       
  1180 	if (!phy)
       
  1181 		{
       
  1182 		// In the event of an error the client should not inspect
       
  1183 		// aLinkPolicySettings.
       
  1184 		return KErrNotFound;
       
  1185 		}
       
  1186 
       
  1187 	aLinkPolicySettings = phy->LinkPolicy();
       
  1188 	return KErrNone;
       
  1189 	}
       
  1190 
       
  1191 TInt CPhysicalLinksManager::GetBasebandLinkState(TBTBasebandLinkState& aBasebandLinkState, const TBTDevAddr& aBDAddr) const
       
  1192 	{
       
  1193 	const CPhysicalLink* const phy(FindPhysicalLink(aBDAddr));
       
  1194 
       
  1195 	if (!phy)
       
  1196 		{
       
  1197 		// In the event of an error the client should not inspect
       
  1198 		// aBasebandLinkState.
       
  1199 		return KErrNotFound;
       
  1200 		}
       
  1201 
       
  1202 	aBasebandLinkState = phy->LinkState();
       
  1203 	return KErrNone;
       
  1204 	}
       
  1205 
       
  1206 
       
  1207 //
       
  1208 // TPageTimeoutController
       
  1209 //
       
  1210 
       
  1211 TPageTimeoutController::TPageTimeoutController(MHCICommandQueue& aCommandQueue)
       
  1212 	: iCommandQueue(aCommandQueue)
       
  1213 	, iOutstandingCommands(0)
       
  1214 	{
       
  1215 	}
       
  1216 
       
  1217 void TPageTimeoutController::Abort()
       
  1218 	{
       
  1219 	iCommandQueue.MhcqRemoveAllCommands(*this);
       
  1220 	}
       
  1221 
       
  1222 void TPageTimeoutController::WritePageTimeout(TBasebandTime aPageTimeout)
       
  1223 	{
       
  1224 	// Setting the page-timeout is typically best effort, hence this non-erroring
       
  1225 	// API.
       
  1226 	TRAP_IGNORE(WritePageTimeoutL(aPageTimeout));
       
  1227 	}
       
  1228 
       
  1229 void TPageTimeoutController::MhcqcCommandEventReceived(const THCIEventBase& /*aEvent*/, const CHCICommandBase* /*aRelatedCommand*/)
       
  1230 	{
       
  1231 	// Nothing else needs to be done.
       
  1232 	--iOutstandingCommands;
       
  1233 	}
       
  1234 
       
  1235 void TPageTimeoutController::MhcqcCommandErrored(TInt /*aErrorCode*/, const CHCICommandBase* /*aCommand*/)
       
  1236 	{
       
  1237 	// This is a best effort service so errors are just dropped.
       
  1238 	--iOutstandingCommands;
       
  1239 	}
       
  1240 
       
  1241 void TPageTimeoutController::WritePageTimeoutL(TBasebandTime aPageTimeout)
       
  1242 	{
       
  1243 	if(iOutstandingCommands)
       
  1244 		{
       
  1245 		// best effort removal of any existing command on the queue.
       
  1246 		static_cast<void>(iCommandQueue.MhcqRemoveCommand(iLastCommandId, *this));
       
  1247 		}
       
  1248 	CWritePageTimeoutCommand* cmd = CWritePageTimeoutCommand::NewL(aPageTimeout);
       
  1249 	// ownership of cmd is taken by command queue.
       
  1250 	iLastCommandId = iCommandQueue.MhcqAddCommandL(cmd, *this); // "leak" any previous command id.
       
  1251 	++iOutstandingCommands;
       
  1252 	}
       
  1253 
       
  1254 
       
  1255 
       
  1256 CBluetoothPrefetchManager* CBluetoothPrefetchManager::NewL()
       
  1257 	{
       
  1258 	CBluetoothPrefetchManager* self = new(ELeave) CBluetoothPrefetchManager;
       
  1259 	return self;
       
  1260 	}
       
  1261 
       
  1262 CBluetoothPrefetchManager::CBluetoothPrefetchManager()
       
  1263 	{
       
  1264 	}
       
  1265 
       
  1266 CBluetoothPrefetchManager::~CBluetoothPrefetchManager()
       
  1267 	{
       
  1268 	while(iPinRequesters.Count() > 0)
       
  1269 		{
       
  1270 		iPinRequesters[0].CompleteRequest(KErrCancel);
       
  1271 		iPinRequesters.Remove(0);
       
  1272 		}
       
  1273 	iPinRequesters.Close();
       
  1274 	}
       
  1275 
       
  1276 TBool CBluetoothPrefetchManager::CompareAddressInRequest(const TBTDevAddr* aDevAddr, const RPinRequest& aRequest)
       
  1277 	{
       
  1278 	return aDevAddr && *aDevAddr == aRequest.iAddr;
       
  1279 	}
       
  1280 
       
  1281 TBool CBluetoothPrefetchManager::CompareAddressInStore(const TBTDevAddr* aDevAddr, const TPrefetchedPin& aPin)
       
  1282 	{
       
  1283 	return aDevAddr && *aDevAddr == aPin.iAddr;
       
  1284 	}
       
  1285 
       
  1286 TInt CBluetoothPrefetchManager::HandleOverPinRequester(const TBTDevAddr& aAddr, CBTPinRequester* aPinRequester)
       
  1287 	{
       
  1288 	RPinRequest req;
       
  1289 	TInt err = req.Create(aAddr, aPinRequester);
       
  1290 	if(err == KErrNone)
       
  1291 		{
       
  1292 		err = iPinRequesters.Append(req);
       
  1293 		}
       
  1294 	if(err == KErrNone)
       
  1295 		{
       
  1296 		aPinRequester->UpdateHandler(*this);
       
  1297 		}
       
  1298 	return err;
       
  1299 	}
       
  1300 
       
  1301 TInt CBluetoothPrefetchManager::RegisterForPrefetching(const TBTDevAddr& aAddr, MBluetoothPrefetchNotifier& aNotifier)
       
  1302 	{
       
  1303 	TInt ix = iPinRequesters.Find(aAddr, CompareAddressInRequest);
       
  1304 	if (ix < 0)
       
  1305 		{
       
  1306 		return ix;
       
  1307 		}
       
  1308 	iPinRequesters[ix].AddNotifier(aNotifier);
       
  1309 	return KErrNone;
       
  1310 	}
       
  1311 
       
  1312 TBool CBluetoothPrefetchManager::IsPrefetchAvailable(const TBTDevAddr& aAddr, TBTPinCode& aPinCode)
       
  1313 	{
       
  1314 	TInt ix = iPrefetchedPins.Find(aAddr, CompareAddressInStore);
       
  1315 	if (ix < 0)
       
  1316 		{
       
  1317 		return EFalse;
       
  1318 		}
       
  1319 	aPinCode.Copy(iPrefetchedPins[ix].iPin);
       
  1320 	iPrefetchedPins.Remove(ix);
       
  1321 	return ETrue;
       
  1322 	}
       
  1323 
       
  1324 TInt CBluetoothPrefetchManager::PINCodeRequestReply(const TBTDevAddr& aDevAddr, const TDesC8& aPin) const
       
  1325 	{
       
  1326 	TInt ix = iPinRequesters.Find(aDevAddr, CompareAddressInRequest);
       
  1327 	__ASSERT_DEBUG(ix >= 0, Panic(EBTPrefetchManagerReplyForNoRequest));
       
  1328 
       
  1329 	// Always check if someone is prefetching before storing a prefetch result.
       
  1330 	TInt result = EBTSecManAccessDenied;
       
  1331 	if(iPinRequesters[ix].NotifiersWaiting())
       
  1332 		{
       
  1333 		TPrefetchedPin pin;
       
  1334 		pin.iAddr = aDevAddr;
       
  1335 		pin.iPin.Copy(aPin);
       
  1336 		result = iPrefetchedPins.Append(pin);
       
  1337 		}
       
  1338 	iPinRequesters[ix].CompleteRequest(result);
       
  1339 	iPinRequesters.Remove(ix);
       
  1340 	return KErrNone;
       
  1341 	}
       
  1342 
       
  1343 TInt CBluetoothPrefetchManager::PINCodeRequestNegativeReply(const TBTDevAddr& aDevAddr) const
       
  1344 	{
       
  1345 	TInt ix = iPinRequesters.Find(aDevAddr, CompareAddressInRequest);
       
  1346 	__ASSERT_DEBUG(ix >= 0, Panic(EBTPrefetchManagerReplyForNoRequest));
       
  1347 	iPinRequesters[ix].CompleteRequest(EBTSecManAccessDenied);
       
  1348 	iPinRequesters.Remove(ix);
       
  1349 	return KErrNone;
       
  1350 	}
       
  1351 
       
  1352 CBluetoothPrefetchManager::RPinRequest::RPinRequest()
       
  1353 	: iNotifiers(NULL)
       
  1354 	{
       
  1355 	}
       
  1356 
       
  1357 TInt CBluetoothPrefetchManager::RPinRequest::Create(const TBTDevAddr& aAddr, CBTPinRequester* aPinRequester)
       
  1358 	{
       
  1359 	iAddr = aAddr;
       
  1360 	iPinRequester = aPinRequester;
       
  1361 	iNotifiers = new TDblQue<TPrefetchNotifierQLink>();
       
  1362 	return iNotifiers ? KErrNone : KErrNoMemory;
       
  1363 	}
       
  1364 
       
  1365 void CBluetoothPrefetchManager::RPinRequest::AddNotifier(MBluetoothPrefetchNotifier& aNotifier)
       
  1366 	{
       
  1367 	iNotifiers->AddLast(aNotifier.MbpnQueLink());
       
  1368 	}
       
  1369 
       
  1370 TBool CBluetoothPrefetchManager::RPinRequest::NotifiersWaiting() const
       
  1371 	{
       
  1372 	return !iNotifiers->IsEmpty();
       
  1373 	}
       
  1374 
       
  1375 void CBluetoothPrefetchManager::RPinRequest::CompleteRequest(TInt aError)
       
  1376 	{
       
  1377 	while(!iNotifiers->IsEmpty())
       
  1378 		{
       
  1379 		MBluetoothPrefetchNotifier* notifier = iNotifiers->First()->Item();
       
  1380 		ASSERT_DEBUG(notifier);
       
  1381 		notifier->MbpnQueLink().Deque();
       
  1382 		notifier->MbpnPrefetchComplete(aError);
       
  1383 		}
       
  1384 	delete iPinRequester;
       
  1385 	iPinRequester = NULL;
       
  1386 	delete iNotifiers;
       
  1387 	iNotifiers = NULL;
       
  1388 	}
       
  1389 
       
  1390