bluetooth/btstack/linkmgr/hostresolver.cpp
changeset 0 29b1cd4cb562
child 22 786b94c6f0a4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/linkmgr/hostresolver.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,2745 @@
+// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// L2CAP Host resolver.
+// Implements Inquiry and Name lookup
+// 
+//
+
+#include "hostresolver.h"
+#include <bluetooth/logger.h>
+#include <bluetooth/hci/event.h>
+#include <bluetooth/hci/hciutil.h>
+#include <bluetooth/hci/hciconsts.h>
+#include <bluetooth/hci/inquirycommand.h>
+#include <bluetooth/hci/inquirycancelcommand.h>
+#include <bluetooth/hci/writeinquirymodecommand.h>
+#include <bluetooth/hci/writeextendedinquiryresponsecommand.h>
+#include <bluetooth/hci/readextendedinquiryresponsecommand.h>
+#include <bluetooth/hci/remotenamerequestcommand.h>
+#include <bluetooth/hci/remotenamereqcompleteevent.h>
+#include <bluetooth/hci/remotenamerequestcancelcommand.h>
+#include <bluetooth/hci/remotehostsupportedfeaturesnotificationevent.h>
+#include <bluetooth/hci/readlocalnamecommand.h>
+
+// Command Events
+#include <bluetooth/hci/inquiryresultevent.h>
+#include <bluetooth/hci/inquiryresultwithrssievent.h>
+#include <bluetooth/hci/extendedinquiryresultevent.h>
+
+// Command Complete Events
+#include <bluetooth/hci/readlocalnamecompleteevent.h>
+#include <bluetooth/hci/commandcompleteevent.h>
+#include <bluetooth/hci/commandstatusevent.h>
+
+#include <e32std.h>
+#include <s32mem.h>
+#include <bt_sock.h>
+#include <utf.h>
+#include "debug.h"
+#include "linkutil.h"
+#include "physicallinksmanager.h"	// to get baseband freed up for inquiries
+#include "BTSec.h"
+
+//Diagnostic string for security check failures, in builds without platsec
+//diagnostics this will be NULL.
+const char* const KBT_HOSTRESOLVER_NAME_DIAG = __PLATSEC_DIAGNOSTIC_STRING("Bluetooth Host Resolver");
+
+const static TUint KHostResDontBlock = 4;
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_HOSTRESOLVER);
+#endif
+
+
+
+//
+//	BT Inquiry Result record.
+//
+
+CBTInqResultRecord::CBTInqResultRecord(const TBTDevAddr& aAddr)
+	: iCodec(iEntry.iExtendedInquiryResponse)
+	{
+	LOG_FUNC
+	iEntry.iBdaddr = aAddr;
+	// Default to page scan repetition mode R2 as recommended by Bray to give best
+	// chance of success for host resolver needs.
+	// Also allow other default values to be entered here
+	iEntry.iPageScanRepetitionMode = KDefaultBluetoothPageScanRepMode;
+	iEntry.iPageScanMode = KDefaultBluetoothPageScanMode;
+	iEntry.iClockOffset = KDefaultBluetoothClockOffset;
+	iEntry.iCoD = KDefaultBluetoothClassOfDevice;
+	
+	if(aAddr!=TBTDevAddr())
+		{
+		iJuiceFromHCIMask = EBluetoothAddr;
+		}
+	//else 0 cos 'C' class
+	
+	SetNameValid(EFalse);
+	}
+
+CBTInqResultRecord::~CBTInqResultRecord()
+	{
+	LOG_FUNC
+	iIACs.Close();
+	}
+
+inline void CBTInqResultRecord::Open()
+/**
+	Some reference is now pointing at us.
+	Inc the ref count.
+**/
+	{
+	LOG_FUNC
+	++iRefCount;
+	}
+
+void CBTInqResultRecord::Close()
+/**
+	Reference closing.
+	Auto delete if this was the last reference pointing to us.
+**/
+	{
+	LOG_FUNC
+	--iRefCount;
+	if (iRefCount <= 0)
+		delete this;
+	}
+
+TInquiryLogEntry& CBTInqResultRecord::LogEntry()
+/**
+	The inquiry result.
+	This is stored as it was returned from the HCI.
+	The host resolver will convert it into an InquirySockAddr
+	when a client actually wants to retreve it.
+**/
+	{
+	LOG_FUNC
+	return iEntry;
+	}
+
+inline void CBTInqResultRecord::SetName(const TDesC8& aName)
+	{
+	LOG_FUNC
+	iName = aName;
+	}
+
+inline const TDesC8& CBTInqResultRecord::Name() const
+/**
+	The UTF name of the remote device.
+	This is stored as it comes in off the wire, the host resolver
+	converts to Unicode if & when a client actually requires it.
+**/
+	{
+	LOG_FUNC
+	return iName;
+	}
+
+inline TInt CBTInqResultRecord::IncFlushes()
+/**
+	Age the result record
+	Returns it's new age.
+**/
+	{
+	LOG_FUNC
+	return ++iFlushes;
+	}
+
+inline TBool CBTInqResultRecord::IsNameValid() const
+	{
+	LOG_FUNC
+	return iNameLookupResultCode == KErrNone;
+	}
+
+inline void CBTInqResultRecord::SetNameValid(TBool aBool)
+	{
+	LOG_FUNC
+	if(aBool)
+		iNameLookupResultCode = KErrNone;
+	else
+		iNameLookupResultCode = 1;
+	}
+
+void CBTInqResultRecord::SetNameLookupResultCode(TInt aResultCode)
+	{// Only record error, if we don't have a valid name already
+	LOG_FUNC
+	if(!IsNameValid())
+		iNameLookupResultCode = aResultCode;
+	}
+
+inline TBool CBTInqResultRecord::IsNameRequestPending() const
+	{
+	LOG_FUNC
+	return iNameStatus & ENamePending;
+	}
+
+inline void CBTInqResultRecord::SetNamePending(TBool aBool)
+	{
+	LOG_FUNC
+	if(aBool)
+		iNameStatus |= ENamePending;
+	else
+		iNameStatus &= ~ENamePending;
+	}
+
+inline TBool CBTInqResultRecord::IsNameRefreshRequested() const
+	{
+	LOG_FUNC
+	return iNameStatus & ENameRefreshRequested;
+	}
+
+inline void CBTInqResultRecord::SetNameRefreshRequested(TBool aBool)
+	{
+	LOG_FUNC
+	if(aBool)
+		iNameStatus |= ENameRefreshRequested;
+	else
+		iNameStatus &= ~ENameRefreshRequested;
+	}
+
+inline TBool CBTInqResultRecord::IsNameComplete() const
+	{
+	LOG_FUNC
+	return iNameStatus & ENameComplete;
+	}
+
+inline void CBTInqResultRecord::SetNameComplete(TBool aBool)
+	{
+	LOG_FUNC
+	if(aBool)
+		iNameStatus |= ENameComplete;
+	else
+		iNameStatus &= ~ENameComplete;
+	}
+
+inline TBool CBTInqResultRecord::IsExplicitNameRequest() const
+	{
+	LOG_FUNC
+	return iNameStatus & ENameExplicitRequest;
+	}
+
+inline void CBTInqResultRecord::SetExplicitNameRequest(TBool aBool)
+	{
+	LOG_FUNC
+	if(aBool)
+		iNameStatus |= ENameExplicitRequest;
+	else
+		iNameStatus &= ~ENameExplicitRequest;
+	}
+
+inline TBool CBTInqResultRecord::HaveNameLookupResult() const
+	{
+	LOG_FUNC
+	return iNameLookupResultCode <= KErrNone;
+	}
+
+inline TInt CBTInqResultRecord::NameLookupResultCode() const
+	{// Only valid if HaveNameLookupResult == ETrue
+	LOG_FUNC
+	__ASSERT_DEBUG(HaveNameLookupResult(), Panic(EBTNameLookupResultNotFound));
+	return iNameLookupResultCode;
+	}
+
+inline TInt CBTInqResultRecord::NameLookupAttempts() const
+	{
+	LOG_FUNC
+	return iNameLookupAttempts;
+	}
+
+void CBTInqResultRecord::GetInquirySockAddr(TInquirySockAddr& aAddr)
+/**
+	Read this result record out into a TInquirySockAddr.
+**/
+	{
+	LOG_FUNC
+	aAddr.SetBTAddr(LogEntry().iBdaddr);
+
+	TBTDeviceClass cod(LogEntry().iCoD);
+	aAddr.SetMajorServiceClass(cod.MajorServiceClass());
+	aAddr.SetMajorClassOfDevice(cod.MajorDeviceClass());
+	aAddr.SetMinorClassOfDevice(cod.MinorDeviceClass());
+	
+	TUint8 resultFlags = 0;
+	
+	if(iJuiceFromHCIMask & EBluetoothRssi)
+		{
+		TInquiryLogEntry* logEntry = &(LogEntry());
+		resultFlags |= TInquirySockAddr::ERssiValid;
+		aAddr.SetRssi(static_cast<TInquiryLogEntryWithRssi*>(logEntry)->iRssi.RSSI());
+		}
+
+	aAddr.SetResultFlags(resultFlags);
+	}
+
+TInt CBTInqResultRecord::GetEir(TNameRecord& aNameRec, TBool aIgnoreCachedName)
+	{
+	// Reformat the EIR (i.e. remove 0s from EIR) for the constructor
+	LOG_FUNC
+	TInt error = KErrNone;
+
+	aNameRec.iName.Zero();
+	iCodec.Set(aNameRec);
+	if(IsEirPresent())
+		{
+		TInquiryLogEntry* logEntry = &(LogEntry());
+		iCodec.Copy(static_cast<TInquiryLogEntryWithEir*>(logEntry)->iExtendedInquiryResponse);
+		}
+	// replace device name in eir with iName if there is a complete name present
+	if(IsNameValid() && IsNameComplete() && !aIgnoreCachedName)
+		{
+		iCodec.SetDeviceName(iName, ETrue);
+		}
+	return error;
+	}
+
+TInt CBTInqResultRecord::GetName(TNameRecord& aNameRec)
+	{
+	LOG_FUNC
+	TInt err = KErrNotFound;
+	if(HaveNameLookupResult())
+		{
+		err = CnvUtfConverter::ConvertToUnicodeFromUtf8(aNameRec.iName, iName);
+		if (err >= KErrNone)
+			{
+			err = KErrNone;
+			if(!IsNameComplete())
+				{
+				aNameRec.iFlags |= TNameRecord::EPartial;
+				}
+			else
+				{
+				aNameRec.iFlags &= ~(TNameRecord::EPartial);
+				}
+			}
+		}
+	else
+		{
+		err = KErrNone; // just following the old way of working.
+		aNameRec.iName.Zero();
+		}
+	return err;
+	}
+
+TInt CBTInqResultRecord::AddIAC(TUint aIAC)
+/**
+	Adds IAC into list of those this device has responded to
+	@return KErrNone	IAC added without any bother
+	@return KErrAlreadyExists	IAC already in list
+**/
+	{
+	LOG_FUNC
+	return iIACs.InsertInOrder(aIAC);
+	}
+
+inline TBool CBTInqResultRecord::HasRespondedToIAC(TUint aIAC)
+	{
+	LOG_FUNC
+	return (iIACs.FindInOrder(aIAC) >= 0);
+	}
+
+inline TInt CBTInqResultRecord::NumberOfIACsRespondedTo()
+	{
+	LOG_FUNC
+	return iIACs.Count();
+	}
+
+inline void CBTInqResultRecord::ClearIACs()
+	{
+	LOG_FUNC
+	iIACs.Reset();
+	}
+
+//
+//	Inquiry result reference.
+//
+CBTInqResultRef::CBTInqResultRef(CBTInqResultRef& aRef)
+	: iRecord(aRef.iRecord)
+	{
+	LOG_FUNC
+	iRecord.Open();
+	}
+
+CBTInqResultRef::~CBTInqResultRef()
+	{
+	LOG_FUNC
+	iRecord.Close();
+	iLink.Deque();
+	}
+
+CBTInqResultRef::CBTInqResultRef(CBTInqResultRecord& aRec)
+	: iRecord(aRec)
+	{
+	LOG_FUNC
+	iRecord.Open();
+	}
+
+inline CBTInqResultRecord& CBTInqResultRef::Result() const
+	{
+	LOG_FUNC
+	return iRecord;
+	}
+
+
+
+//
+//	BT Inquiry Result Set.
+//
+
+CBTInqResultSet::CBTInqResultSet()
+	: iResultRefs(_FOFF(CBTInqResultRef, iLink)),
+	iNextRefIter(iResultRefs)
+	{
+	LOG_FUNC
+	}
+
+CBTInqResultSet::~CBTInqResultSet()
+	{
+	LOG_FUNC
+	Reset();
+	}
+
+void CBTInqResultSet::Reset()
+	{
+	LOG_FUNC
+	while (!iResultRefs.IsEmpty())
+		delete iResultRefs.First();
+	ReturnToFirstResult();
+	}
+
+CBTInqResultRef* CBTInqResultSet::Add(CBTInqResultRecord& aRec)
+	{
+	LOG_FUNC
+	CBTInqResultRef* ref = new CBTInqResultRef(aRec);
+	if (!ref)
+		{
+		return 0;
+		}
+	iResultRefs.AddLast(*ref);
+	if (!iNextRefIter)
+		{
+		iNextRefIter.SetToLast();
+		}
+	return ref;
+	}
+
+CBTInqResultRef* CBTInqResultSet::FindEntry(const TBTDevAddr& aAddr)
+	{
+	LOG_FUNC
+	TResultQueIter iter(iResultRefs);
+	while (iter)
+		{
+		CBTInqResultRef* ref = iter++;
+		if (ref->Result().LogEntry().iBdaddr == aAddr)
+			{
+			return ref;
+			}
+		}
+	return 0;
+	}
+
+CBTInqResultRef* CBTInqResultSet::NextResult()
+	{
+	LOG_FUNC
+	return iCurrentResult = (iNextRefIter++);
+	}
+
+inline CBTInqResultRef* CBTInqResultSet::CurrentResult()
+	{
+	LOG_FUNC
+	return iCurrentResult;
+	}
+
+void CBTInqResultSet::ReturnToFirstResult()
+	{
+	LOG_FUNC
+	iNextRefIter.SetToFirst();
+	iCurrentResult = 0;
+	}
+
+inline TBool CBTInqResultSet::IsEmpty()
+	{
+	LOG_FUNC
+	return iResultRefs.IsEmpty();
+	}
+
+void CBTInqResultSet::MoveToback(CBTInqResultRef& aRef)
+	{
+	LOG_FUNC
+	if(iNextRefIter == &aRef)
+		NextResult();
+	aRef.iLink.Deque();
+	iResultRefs.AddLast(aRef);
+	if (!iNextRefIter)
+		{
+		iNextRefIter.SetToLast();
+		}
+	}
+
+//
+//	BT Host resolver.
+//
+
+
+CBTHostResolver::CBTHostResolver(CBTInquiryMgr& aInquiryMgr)
+	: iInquiryMgr(aInquiryMgr), 
+	iRequestState(EIdle),
+	iInquiryStatus(EInquiryReady)
+	{
+	LOG_FUNC
+#ifdef _DEBUG
+	iInquiryMgr.IncrementHRCount();
+#endif
+	}
+
+CBTHostResolver::~CBTHostResolver()
+	{
+	LOG_FUNC
+	iLink.Deque();
+	iInquiryMgr.DeletingHostResolver();
+#ifdef _DEBUG
+	iInquiryMgr.DecrementHRCount();
+#endif
+	}
+
+void CBTHostResolver::GetByName(TNameRecord& /*aName*/)
+	{
+	LOG_FUNC
+	iNotify->QueryComplete(KErrNotSupported);
+	}
+
+void CBTHostResolver::GetByAddress(TNameRecord& aName)
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iRequestState == EIdle, Panic(EHostResolverTwoRequests));
+	iNameRecord = &aName;
+	iNameRecord->iName.Zero();
+	TInquirySockAddr& sa = TInquirySockAddr::Cast(aName.iAddr);
+
+	LOG1(_L("Host Resolver\tAction = %d"),sa.Action());
+
+	if(sa.Action() & KHostResCache)
+		//Complete immediately with info if available!
+		{
+		TInt err = KErrNotFound;
+		CBTInqResultRef* ref = iInquiryMgr.FindExistingCacheEntry(sa.BTAddr());
+		if (ref)
+			{// Got a result to send up
+			CBTInqResultRecord& rec = ref->Result();
+			rec.GetInquirySockAddr(sa); //Put BT address, CoD etc into 'aName'
+			// Check whether client wants EIRs instead of names
+			if(sa.Action() & KHostResEir)
+				{
+				// Client knows about EIR, we'll fill the TNameRecord with EIR
+				err = rec.GetEir(aName, EFalse);
+				}
+			else
+				{
+				// Client don't knows about EIR, we'll fill the TNameRecord with just encoded device name if present
+				err = rec.GetName(aName);
+				}
+			if (err != KErrNone)
+				{// error getting name - but other stuff fine - 
+				 // so ensure name is not gobbledigook
+				aName.iName.Zero();
+				}
+			err = KErrNone; //err has new meaning now, vis "record exists"
+			}
+		else
+			{
+			//err is KErrNotFound
+			}
+					
+		iNotify->QueryComplete(err);
+		return;
+		}
+	
+	// Must request at least one of inquiry or name lookup
+	if (!(sa.Action() & (KHostResInquiry | KHostResName)))
+		{
+		iRequestState = EError;
+		CompleteRequest(KErrArgument);
+		return;
+		}
+
+	// Check the hw state - can't do anything if its switched off
+	//
+	if(iInquiryMgr.HWState()==CBTInquiryMgr::EOff)
+		{
+		iRequestState = EError;
+		CompleteRequest(KErrHardwareNotAvailable);
+		return;
+		}
+
+	iNameLookupMode = (sa.Action()) & KHostResName ? EDoGetNames : EDontGetNames;
+	TBool ignoreCache = (sa.Action() & KHostResIgnoreCache) ? ETrue : EFalse;
+
+	if (sa.Action() & KHostResInquiry)
+		{
+		// We only support GIAC and LIAC
+		if (sa.IAC() != KLIAC && sa.IAC() != KGIAC)
+			{
+			iRequestState = EError;
+			CompleteRequest(KErrNotSupported);
+			return;
+			}
+		sa.SetBTAddr(TBTDevAddr());
+		iRequestState = EInquiry;
+		if (iInquiryStatus == EInquiryReady)
+			{// Need to start the inquiry process
+			iInquiryStatus = EInquiring;
+			// We set this before calling StartInquiry, as StartInquiry can call InquiryComplete synchronously. 
+			iResults.Reset();
+			iInquiryMgr.StartInquiry(*this, sa.IAC(), ignoreCache);
+			}
+		}
+	else // Not an inquiry - just a name lookup
+		{
+		// Just name lookup -- add it to the result set, and request a lookup of it
+		iResults.Reset();
+
+		CBTInqResultRef* ref = iInquiryMgr.AddEntryToCache(sa.BTAddr());
+		if(ref)
+			{// This ref is in cache -- need to make our own ref
+			ref = iResults.Add(ref->Result());
+			}
+		if (!ref)
+			{
+			CompleteRequest(KErrNoMemory);
+			return;
+			}
+		iResults.NextResult(); // Move iter onto first (only) result
+		iRequestState = ENameLookup;
+		iInquiryMgr.LookupName(*this, sa.BTAddr(), ignoreCache, ETrue);
+		}
+	TryToCompleteRequest();
+	}
+
+TInt CBTHostResolver::SetOption(TUint /*aLevel*/, TUint /*aName*/, const TDesC8& /*aOption*/)
+	{
+	LOG_FUNC
+	return KErrNone;
+	}
+
+void CBTHostResolver::SetHostName(TDes& aNameBuf)
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iRequestState == EIdle, Panic(EHostResolverTwoRequests));
+	
+	TBuf8<KHCILocalDeviceNameMaxLength> utf8Name;
+	TInt ret = CnvUtfConverter::ConvertFromUnicodeToUtf8(utf8Name, aNameBuf);
+	iRequestState=ESetLocalName;
+	if (ret > KErrNone)
+		{// Unconverted characters exist! Error the client
+		ret = KErrHostResNameTooLong;
+		}
+
+	// Check the hw state - can't do anything if its switched off
+	//
+	if(iInquiryMgr.HWState()==CBTInquiryMgr::EOff)
+		{
+		ret = KErrHardwareNotAvailable;
+		}
+
+	if (ret == KErrNone)
+		ret = iInquiryMgr.SetLocalName(utf8Name);
+
+	if (ret != KErrNone)
+		{
+		CompleteRequest(ret);
+		}
+	}
+
+void CBTHostResolver::GetHostName(TDes& aNameBuf)
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iRequestState == EIdle, Panic(EHostResolverTwoRequests));
+
+	iHostNameBuf = &aNameBuf;
+	iRequestState=EGetLocalName;
+	TInt ret = KErrNone;
+
+	// Check the hw state - can't do anything if its switched off
+	//
+	if(iInquiryMgr.HWState()==CBTInquiryMgr::EOff)
+		{
+		ret = KErrHardwareNotAvailable;
+		}
+
+	if(ret==KErrNone)
+		iInquiryMgr.GetLocalName();
+	else
+		CompleteRequest(ret);
+	}
+
+
+void CBTHostResolver::CancelCurrentOperation()
+/**
+	Current operation cancel by user app.
+	Reset, so that we don't bother picking up any future results.
+	We don't actually bother to cancel the async. operations, as
+	if they succeed, the InquiryMgr may as well cache them anyway.
+	The next operation after this (if there is any), must be a fresh
+	one -- i.e. it can not be a next.
+**/
+	{
+	LOG_FUNC
+	iRequestState = EIdle;
+	CompleteCurrentOperation();
+	}
+
+void CBTHostResolver::InquiryResult(CBTInqResultRecord& aResult)
+	{
+	LOG_FUNC
+	if (iInquiryStatus != EInquiring)
+		return;
+
+	// Check if we've already seen this result
+	CBTInqResultRef* ref = iResults.FindEntry(aResult.LogEntry().iBdaddr);
+	if (ref)
+		return;
+
+	TInquirySockAddr& sa = TInquirySockAddr::Cast(iNameRecord->iAddr);
+	if(!aResult.HasRespondedToIAC(sa.IAC()))
+		return; // It's never responded to our IAC, so ignore it
+
+	ref = iResults.Add(aResult);
+	if (!ref)
+		{
+		InquiryComplete(KErrNoMemory);
+		return;
+		}
+
+	if(iNameLookupMode == EDoGetNames)
+		{
+		// Find out whether cache was supposed to be ignored from TNameRecord that was passed into GetByAddress() previously
+		TBool ignoreCache = (sa.Action() & KHostResIgnoreCache) ? ETrue : EFalse;
+		// Handle a "special" case: Cache is to be ignored, but we got the _complete_ name during the inquiry process inside an EIR
+		// (which doesn't count as cached data, since it's freshly arrived from the radio). In this case we don't really want to 
+		// launch a remote name request
+		if(ignoreCache && ref->Result().IsEirPresent() && ref->Result().Codec().IsDataTypePresent(EEirLocalNameComplete))
+			{
+			// Do nothing, the entry already contains the name
+			}
+		else
+			{
+			iInquiryMgr.LookupName(*this, aResult.LogEntry().iBdaddr, ignoreCache, EFalse);
+			}
+		}
+
+	if (iRequestState == EInquiry)
+		{
+		TryToCompleteRequest();
+		}
+	}
+
+void CBTHostResolver::NameLookupResult(TInt aErr, const TBTDevAddr& aAddr, const TDesC8& aName)
+	{
+	LOG_FUNC
+	if (iNameLookupMode == EDontGetNames)
+		return; // We're not actually after names
+
+	// Check we've got this result recorded (mostly for error cases)
+	CBTInqResultRef* ref = iResults.FindEntry(aAddr);
+	if (ref && !(ref->Result().HaveNameLookupResult() && ref->Result().IsNameComplete()))
+		{
+		// we have successfully created a reference and there isn't a complete name available.
+		ref->Result().SetNameLookupResultCode(aErr);
+		ref->Result().SetNameComplete(ETrue);
+		ref->Result().SetName(aName);
+		}
+
+	TryToCompleteRequest();
+	}
+
+void CBTHostResolver::InquiryComplete(TInt aErr)
+	{
+	LOG_FUNC
+	// LC changed - if we are just doing a name lookup, iInquiryStatus
+	// doesn't get set so need additional check here.
+	//
+	if ((iInquiryStatus != EInquiring) && (iRequestState != ENameLookup))
+		return;
+	iInquiryStatus = EInquiryComplete;
+	iInqCompletionCode = aErr;
+	if(aErr==KErrHardwareNotAvailable)
+		iRequestState=EError;
+	TryToCompleteRequest();
+	}
+
+void CBTHostResolver::SetLocalNameComplete(TInt aErr)
+	{
+	LOG_FUNC
+	if (iRequestState != ESetLocalName)
+		return;
+	CompleteRequest(aErr);
+	}
+
+void CBTHostResolver::GetLocalNameComplete(TInt aErr, const TDesC8& aName)
+	{
+	LOG_FUNC
+	if (iRequestState != EGetLocalName)
+		return;
+	if (aErr == KErrNone)
+		{
+		aErr = CnvUtfConverter::ConvertToUnicodeFromUtf8(*iHostNameBuf, aName);
+		// Just allow names to be truncated...
+		}
+	CompleteRequest(aErr >= 0 ? KErrNone : aErr);
+	}
+
+TUint CBTHostResolver::GetIAC() const
+	{
+	LOG_FUNC
+	if (!iNameRecord)
+		{
+		return 0;		// avoid dereferencing a null ptr
+		}
+	
+	TInquirySockAddr& sa = TInquirySockAddr::Cast(iNameRecord->iAddr);
+	return sa.IAC();
+	}
+
+TInt CBTHostResolver::SecurityCheck(MProvdSecurityChecker *aSecurityChecker)
+	{
+	LOG_FUNC
+	__ASSERT_ALWAYS(aSecurityChecker, User::Panic(KSECURITY_PANIC, EBTPanicNullSecurityChecker));
+		
+	iSecurityChecker = aSecurityChecker;
+	return iSecurityChecker->CheckPolicy(KLOCAL_SERVICES, KBT_HOSTRESOLVER_NAME_DIAG);			
+	}
+
+void CBTHostResolver::TryToCompleteRequest()
+/**
+	This is where the work is done.
+	A big old state machine that tries to get us one step
+	closer to completing the query.
+	Gets an inquiry result out of the result set if appropriate and
+	there is one available.
+	Gets the name for the current result if required.
+	Completes the request if there is then nothing more to do.
+	Must only break out (i.e. return) if the request is completed, or
+	non-blocking mode requested
+**/
+	{
+	LOG_FUNC
+	TInquirySockAddr& sa = TInquirySockAddr::Cast(iNameRecord->iAddr);
+	if ((sa.Action() & KHostResInquiry) && iRequestState == EInquiry)
+		{
+		CBTInqResultRef* refNextRes = iResults.NextResult();
+		if (refNextRes)
+			{// Got a result to send up
+			if (iNameLookupMode == EDoGetNames)
+				{// Need to get the name of this baby...
+				iRequestState = ENameLookup;
+				}
+			else
+				{//Complete!
+				refNextRes->Result().GetInquirySockAddr(sa);
+				// If EIR was requested and we got one, stick it in the name field
+				TInt err = KErrNone;
+				if(sa.Action() & KHostResEir)
+					{
+					err = refNextRes->Result().GetEir(*iNameRecord, (sa.Action() & KHostResIgnoreCache) && !(sa.Action() & KHostResName));
+					}
+				else
+					{
+					err = refNextRes->Result().GetName(*iNameRecord);
+					}
+				if(err != KErrNone)
+					{
+					// Set name back to zero length
+					iNameRecord->iName.Zero();
+					}
+				CompleteRequest(err);
+				return;
+				}
+			}
+		else if (iInquiryStatus == EInquiryComplete)
+			{// Bad luck. No more results availble!
+			if (iInqCompletionCode == KErrNone)
+				{// Inquiry completed fine, so report end of file.
+				CompleteRequest(KErrHostResNoMoreResults);
+				}
+			else
+				{// Some error in the inquiry, so report that.
+				CompleteRequest(iInqCompletionCode);
+				}
+			return;
+			}
+		}
+
+	if ((sa.Action() & KHostResName) && iRequestState == ENameLookup)
+		{
+		CBTInqResultRef* refNextRes = iResults.CurrentResult();
+		if(!refNextRes)
+			{// Can't get the name... no result to lookup
+			CompleteRequest(KErrHostResNoMoreResults);
+			return;
+			}
+		// Walk through results and check if we have a name to complete
+		CBTInqResultRef* startResult = refNextRes;
+		do
+			{
+			CBTInqResultRecord& rec = refNextRes->Result();
+			if(rec.HaveNameLookupResult() && !rec.IsNameRequestPending() && rec.IsNameComplete())
+				{// Got a name! Complete the request
+				rec.GetInquirySockAddr(sa);
+				TInt err = rec.NameLookupResultCode();
+				if (err == KErrNone)
+					{// Copy & convert the UTF-8 name over into the result record.
+					if(sa.Action() & KHostResEir)
+						{
+						err = rec.GetEir(*iNameRecord, EFalse);
+						}
+					else
+						{
+						err = rec.GetName(*iNameRecord);
+						}
+					}
+				if (err != KErrNone)
+					{
+					iNameRecord->iName.Zero();
+					}
+				// Name lookup complete (poss. with errors)
+				if(sa.Action() & KHostResInquiry)
+					{// Ignore name failures if we're also doing inquiry
+					CompleteRequest(KErrNone);
+					}
+				else
+					{// Report any error encountered (or none)
+					CompleteRequest(err);
+					}
+				return;
+				}
+
+			iResults.MoveToback(*refNextRes);
+			refNextRes = iResults.NextResult();
+			} while(refNextRes != startResult);
+		}
+	else if(iRequestState==EError)
+		{
+		CompleteRequest(KErrHardwareNotAvailable);
+		}
+	if(sa.Action() & KHostResDontBlock)
+		{// Complete any outstanding non-blocking operation
+		CompleteRequest(KErrWouldBlock);
+		}
+
+	}
+
+void CBTHostResolver::CompleteRequest(TInt aErr)
+	{
+	LOG_FUNC
+	if (iRequestState == EIdle && aErr == KErrNone) 
+		return;
+	iRequestState = EIdle;
+	if (aErr != KErrNone)
+		{// End of query -- tidy up
+		CompleteCurrentOperation();
+		}
+	iNotify->QueryComplete(aErr);
+	}
+
+void CBTHostResolver::CompleteCurrentOperation()
+/**
+	Operation known to be complete.
+	This happens through a CancelCurrentOperation, or when
+	the current operation has read all the results out.
+**/
+	{
+	LOG_FUNC
+	if (iInquiryStatus == EInquiryReady)
+		return;
+	iInquiryStatus = EInquiryReady;
+	iResults.Reset();
+	}
+
+
+//
+//	BT Inquiry Manager.
+//
+CBTInquiryMgr::CBTInquiryMgr(CLinkMgrProtocol& aProtocol)
+	: iLinkMgrProtocol(aProtocol),
+	iNamePageTimeout((KMaxNamePageTimeout + KMinNamePageTimeout)/2), // start with mid-point timeout
+	iInquiryMode(EStandardInquiryFormat), iHRs(CBTHostResolver::LinkOffset())
+	{
+	LOG_FUNC
+	}
+
+CBTInquiryMgr::~CBTInquiryMgr()
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iHRs.IsEmpty(), Panic(EBTHostControllerQueueNotEmpty));
+	SetHWState(EOff);
+	PublishStatus();// we're not doing anything more so publish status
+	ClearHCICommandQueue();
+	delete iFlusher;
+	delete iConnectingStatus;
+	}
+
+void CBTInquiryMgr::ClearHCICommandQueue()
+	{
+	LOG_FUNC
+	if (iCommandQueue)
+		{
+		iCommandQueue->MhcqRemoveAllCommands(*this);
+		}
+	iCommandQueue = NULL;
+	}
+
+void CBTInquiryMgr::SetHCICommandQueue(MHCICommandQueue& aCommandQueue)
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(!iCommandQueue, Panic(EBTCommandQueueAlreadyExist));
+	iCommandQueue = &aCommandQueue;
+	}
+
+MHCICommandQueue& CBTInquiryMgr::CommandQueue() const
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iCommandQueue, Panic(EBTCommandQueueNotFound));
+	return *iCommandQueue;
+	}
+
+CBTInquiryMgr* CBTInquiryMgr::NewL(CLinkMgrProtocol& aProtocol)
+	{
+	LOG_STATIC_FUNC
+	CBTInquiryMgr* self = new(ELeave) CBTInquiryMgr(aProtocol);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+void CBTInquiryMgr::ConstructL()
+	{
+	LOG_FUNC
+	iFlusher = CPeriodic::NewL(CActive::EPriorityLow);
+#ifdef CONNECTION_PREEMPTS_INQUIRY
+	iConnectingStatus = CConnectingStatusSubscriber::NewL(*this);
+#endif
+	}
+
+CBTHostResolver* CBTInquiryMgr::NewHostResolverL()
+	{
+	LOG_FUNC
+	// Leave if HW switched off
+	//
+	if(iHWState==EOff)
+		User::Leave(KErrHardwareNotAvailable);
+
+	CBTHostResolver* r = new(ELeave) CBTHostResolver(*this);
+	iHRs.AddFirst(*r);
+	return r;
+	}
+
+void CBTInquiryMgr::DeletingHostResolver()
+	{
+	LOG_FUNC
+	// A host resolver is being deleted - we need to check if any other host resolvers want inquiry results from the current IAC.
+	if(!iRequestedInquiryIAC)
+		{
+		 //No 'current' IAC exists
+		 return;		 
+		}
+	TDblQueIter<CBTHostResolver> iter(iHRs);
+	TBool iacFound=EFalse;
+	while (iter)
+		{
+		if ((iter++)->GetIAC() == iRequestedInquiryIAC)
+			{
+			iacFound = ETrue;
+			}
+		}
+	if (!iacFound)
+		{
+		iRequestedInquiryIAC = 0;
+		}
+	}
+
+void CBTInquiryMgr::InquiryResult(TInt aErr,const TInquiryLogEntry& aEntry)
+/**
+	Single Inquiry result received.
+	Called via HCI for each incoming inquiry result. Need to demultiplex these
+	out to all CBTHostResolver's interested in them.
+
+	@param  aErr	An EPOC error code. Any HCI mapping should be done before
+					calling this function.
+	@param	aEntry	The log entry returned through HCI.
+**/
+	{
+	LOG_FUNC
+	LOG5(_L("err: %d,ScanRepM: %d ScanPerM: %d ScanM: %d Type: %d"),
+				 aErr,
+				 aEntry.iPageScanRepetitionMode,
+				 aEntry.iPageScanPeriodMode,
+				 aEntry.iPageScanMode,
+			   	 aEntry.iSpare );
+
+	CBTInqResultRef* ref = 0;
+
+	//Revise our cache record regardless - at least need to make sure
+	//it knows we have received juice from the HCI	
+	if(aErr == KErrNone)
+		{
+		ref = AddEntryWithJuiceToCache(aEntry);
+		if (!ref)
+			{
+			aErr = KErrNoMemory;
+			}
+		else
+			{
+			ref->Result().iFlushes = 0;
+			ref->Result().iFoundDuringCurrentInquiry = ETrue;
+
+			TInt ret = ref->Result().AddIAC(iCurrentInquiryIAC);
+			switch(ret)
+				{
+			case KErrNone:
+				++iResultCount;
+				// drop through
+			case KErrAlreadyExists:
+				break;
+			default: // Got an error adding the IAC
+				aErr = ret;
+				} // switch
+			ref->Result().AddIAC(KGIAC); // This would come back on a GIAC, so try adding GIAC.
+			// If this doesn't work, it doesn't really matter, so ignore the error.
+			} // else
+		} // if (aErr == KErrNone)
+
+	if (aErr != KErrNone)
+		{
+		InquiryComplete(aErr, 0);
+		return;
+		}
+
+	// Tell host resolvers
+	TDblQueIter<CBTHostResolver> iter(iHRs);
+	CBTHostResolver* hr;
+	while ((hr = iter ++) != NULL)
+		{
+		if (hr->GetIAC() == iCurrentInquiryIAC || hr->GetIAC() == KGIAC)
+			{
+			hr->InquiryResult(ref->Result());
+			}
+		}
+	}
+
+void CBTInquiryMgr::CoDResult(const TBTDevAddr& aAddr, TUint aCoD)
+/**
+	We have been donated a CoD from an incoming connection
+	This is useful to keep in the registry for remotely
+	initiated pairings - otherwise we will never have found
+	the CoD of the device bonding with us
+**/	
+	{
+	// create record if it doesn't already exist in cache. 
+	// If this fails, we'll just not be able to store the CoD for this device.
+
+	LOG_FUNC
+	AddEntryWithCoDToCache(aAddr, aCoD);
+	}
+
+void CBTInquiryMgr::ClockOffsetResult(const TBTDevAddr& aAddr, TBasebandTime aClockOffset)
+/**
+	We have been donated a Clock Offset - maybe an update
+**/	
+	{
+	LOG_FUNC
+	AddEntryWithClockOffsetToCache(aAddr, aClockOffset);
+	}
+
+void CBTInquiryMgr::InquiryComplete(TInt aErr, TUint8 /*aNumResponses*/)
+/**
+	Current Inquiry has completed.
+	Must tell all CBTHostResolver's who may be waiting for inquiry results.
+
+	@param  aErr	An EPOC error code. Any HCI mapping should be done before
+					calling this function.
+	@param	aNumResponses	The number of calls to InquiryResult that should
+					have been generated. We don't use this info atm, though.
+**/
+	{
+	LOG_FUNC
+	SetCacheAge(iCurrentInquiryIAC, 0);
+	TUint iacToComplete = iRequestedInquiryIAC;
+	iRequestedInquiryIAC = 0;
+	iFlusher->Cancel(); // Stop watchdog, start flusher
+	SetHWState(EIdle);
+	// don't publish status here, might be doing a name lookup
+	EnableFlusher();
+
+	// The inquiry has completed so clear any results that were marked found during
+	// the just finished inquiry
+	ClearCurrentInquiryResults();
+
+	if(aErr!=KErrHardwareNotAvailable)
+		{
+		LOG(_L("CBTInquiryMgr::InquiryComplete asking for another name lookup"));
+		DoNameLookup(ETrue); // Get any pending name lookups going
+		}
+	else
+		{
+		SetHWState(EOff);
+		LOG(_L("CBTInquiryMgr::InquiryComplete PublishState Idle"));
+		PublishStatus();// we're not doing name lookup so publish status
+		}
+	TDblQueIter<CBTHostResolver> iter(iHRs);
+	CBTHostResolver* hr;
+	while ((hr = iter++) != NULL)
+		{
+		if (hr->GetIAC() == iacToComplete)
+			{
+			hr->InquiryComplete(aErr);
+			}
+		hr++;
+		}
+	// Only queue the inquiry if we have completed all the name requests from this one.
+	// Otherwise, it will be issued after all the remote name requests have completed.
+	if (iQueuedInquiryIAC != 0 && iPendingNameRequests == 0)
+		{
+		iRequestedInquiryIAC = iQueuedInquiryIAC;
+		iQueuedInquiryIAC = 0;
+		DoInquiry();
+		}
+	}
+
+/**
+Name lookup result received.
+Called via HCI for each incoming name result.
+
+The name lookup may not have been requested by the inquiry mgr as when the
+stack gets a new connection it tries to solicit information about the
+remote.  This sort of result is just to add to our cache.
+
+Otherwise it's from a request on us, pass it on for handling.
+
+@param	aErr	An EPOC error code. Any HCI mapping should be done before
+				calling this function.
+@param	aAddr	The address of the Bluetooth device that the name is associated
+				with.
+@param	aBuf	8 bit Descriptor up to KHCIRemoteDeviceNameMaxLength
+				bytes long, containing the name.
+*/
+void CBTInquiryMgr::RemoteNameResult(TInt aErr, const TBTDevAddr& aAddr, const TBTDeviceName8& aBuf)
+	{
+	LOG_FUNC
+	LOG1(_L("aErr = %d"), aErr);
+	LOG6(_L(", aAddr: %02x %02x %02x %02x %02x %02x"),
+			  TUint8(aAddr[0]), TUint8(aAddr[1]), TUint8(aAddr[2]), TUint8(aAddr[3]), TUint8(aAddr[4]), 
+			  TUint8(aAddr[5]));
+
+	CBTInqResultRef* ref = FindExistingCacheEntry(aAddr);
+	if(ref)
+		{
+		CBTInqResultRecord& rec = ref->Result();
+		if (rec.IsNameRequestPending())
+			{
+			// We asked for this
+			HandleRemoteNameResult(aErr, *ref, aBuf);
+			return;
+			}
+		}
+
+	// Unsolicited, just wham in cache if it's good
+	if (aErr == KErrNone)
+		{
+		CBTInqResultRef* ref = AddEntryToCache(aAddr);
+		if(ref)
+			{
+			CBTInqResultRecord& rec = ref->Result();
+
+			rec.SetName(aBuf);
+			rec.SetNameComplete(ETrue);
+			rec.iFlushes = 0;
+			rec.SetNameValid(ETrue);
+			rec.SetNameRefreshRequested(EFalse);
+			}
+		}
+	}
+
+/**
+Remote host supported features notification received.
+
+The remote host supported feature notification may be received during a
+remote name request if the remote device provides entries in the remote
+host supported feature page.
+
+@param	aErr	An EPOC error code. Any HCI mapping should be done before
+				calling this function.
+@param	aAddr	The address of the Bluetooth device that the name is associated
+				with.
+@param	aHostSupportedFeatures	64 bit field holding the remote host supported
+				features page.
+*/
+void CBTInquiryMgr::RemoteHostSupportedFeatures(TInt /*aErr*/, const TBTDevAddr& /*aAddr*/, const TUint64& /*aHostSupportedFeatures*/)
+	{
+	LOG_FUNC
+	// This is currently not used by the stack since the optimisation it could provide would be
+	// difficult to take advantage of and of minimal use.
+
+	// If to be used the result should be stored in the inquiry result record along with whether
+	// a name request has been made (with EIR it is possible to have retrieved the name without
+	// a name request)
+	}
+
+/**
+Name lookup result received.
+
+We need to demultiplex these out to all CBTHostResolver's
+interested in them.
+
+@param  aErr	An EPOC error code. Any HCI mapping should be done before
+				calling this function.
+@param	aRef	The inquiry result for this info.
+@param	aBuf	8 bit Descriptor up to KHCIRemoteDeviceNameMaxLength
+				bytes long, containing the name.
+*/
+void CBTInquiryMgr::HandleRemoteNameResult(TInt aErr, CBTInqResultRef& aRef, const TBTDeviceName8& aBuf)
+	{
+	LOG_FUNC
+	
+	if(iHWState != EConnecting)
+		{
+		SetHWState(EIdle);
+		// don't set publish status here, doinquiry will do that
+		}
+		
+	if(aErr == KErrNone)
+		{
+		if(iNamePageTimeout > KMinNamePageTimeout)
+			{// got name OK, dec the page timeout
+			iNamePageTimeout -= KNamePageTimeoutIncrement;
+			}
+		}
+	else if(aErr == KHCIErrorBase - EPageTimedOut)
+		{
+		if(iNamePageTimeout < KMaxNamePageTimeout)
+			{// Got pagetime, inc. pagetime a bit
+			iNamePageTimeout += KNamePageTimeoutIncrement;
+			}
+		}
+
+
+	CBTInqResultRecord& rec = aRef.Result();
+
+	--iPendingNameRequests;
+	rec.SetNamePending(EFalse);
+	++(rec.iNameLookupAttempts);
+	if(iPendingNameRequests <= 0)
+		{
+		iNewPageRequestsPending = EFalse;
+		}
+
+	// Update our cached version.
+	if (aErr == KErrNone)
+		{
+		rec.SetName(aBuf);
+		rec.SetNameComplete(ETrue);
+		rec.iFlushes = 0;
+		rec.SetNameValid(ETrue);
+		rec.SetNameRefreshRequested(EFalse);
+		rec.SetExplicitNameRequest(EFalse); // If we had an explicit name request on this, we've completed it now
+		}
+	else
+		{
+		// got an error
+		if(rec.NameLookupAttempts() < KMaxNameLookupAttempts)
+			{// try to get later - put to back of Que for getting
+			++iPendingNameRequests;
+			rec.SetNamePending(ETrue);
+			iCurrentResults.MoveToback(aRef);
+			}
+		else
+			{// No more chances -- record lookup error code
+			rec.SetNameLookupResultCode(aErr);
+			rec.SetExplicitNameRequest(EFalse); // If we had an explicit name request on this, we've completed it now
+			}
+		}
+
+	// Try to get more names, if needed
+	LOG(_L("CBTInquiryMgr::HandleRemoteNameResult asking for another name lookup"));
+	DoNameLookup(EFalse);
+
+	if(!aRef.Result().IsNameRequestPending())
+		{// Don't propogate if name request is still pending
+		TDblQueIter<CBTHostResolver> iter(iHRs);
+		while (iter)
+			{
+			(iter++)->NameLookupResult(aErr, rec.LogEntry().iBdaddr, aBuf);
+			}
+		}
+
+	// In case we're now free, do inquiry
+	LOG(_L("CBTInquiryMgr::HandleRemoteNameResult asking for another inquiry"));
+	if (iPendingNameRequests == 0 && iRequestedInquiryIAC == 0) // If we've completed the current inquiry, see if we've got another one queued.
+		{
+		iRequestedInquiryIAC = iQueuedInquiryIAC;
+		iQueuedInquiryIAC = 0;
+		}
+	DoInquiry();
+	}
+
+const TDesC8* CBTInquiryMgr::DeviceNameFromCache(const TBTDevAddr& aAddr)
+/**
+	Used by other parts of the stack to get a name synchronously from cache if
+	there is one
+
+	@return NULL if device is unknwon
+**/
+	{
+	LOG_FUNC
+	CBTInqResultRef* entry = FindExistingCacheEntry(aAddr);
+	if (!entry)
+		return NULL;
+	else
+		{
+		return &entry->Result().Name(); 
+		}
+	}
+
+CBTInqResultRecord* CBTInquiryMgr::BasebandParametersFromCache(const TBTDevAddr& aAddr)
+	{
+	LOG_FUNC
+	CBTInqResultRef* entry = FindExistingCacheEntry(aAddr);
+	if (!entry)
+		return NULL;
+	else
+		{
+		return &(entry->Result());
+		}
+	}
+
+void CBTInquiryMgr::SetHWState(THWState aState)
+	{
+	LOG_FUNC
+	iHWState = aState;
+	}
+
+void CBTInquiryMgr::PublishStatus()
+	{
+	LOG_FUNC
+	// sets the inquiry/discovery status to bool true or false
+	TBool inquiryState = EFalse;
+
+	switch (iHWState)
+		{
+	/* deliberate fall throughs */
+	case EInquiry:
+	case ENameLookup:
+		{	
+		inquiryState = ETrue;
+		}
+		break;
+	case EIdle:
+	case EConnecting:
+	case EOff:
+	default:
+		{
+		// defaulted above to EFalse;
+		}
+		break;
+		}
+	/* only publish status if we've changed	
+	 it is however the case that if the state changes sufficiently quickly
+	 the subscriber will miss some of the state changes 
+	 this is particularly the case while doing name searches where we toggle into 
+	 idle and back to namelookup quickly and regularly, the subscriber
+	 sees a stream of etrues coming through, the efalses are missing
+	 this is probably ok as long as they know because this means they are told 
+	 more than once they are inquiring, and indeed they are, its certainly better
+	 than being told they're not if they are */	
+	if (inquiryState != iReportedInquiryState)
+		{		
+		iLinkMgrProtocol.SetUIDiscovering(inquiryState);
+		iReportedInquiryState = inquiryState;
+		if (inquiryState)
+			{
+			LOG(_L("CBTInquiryMgr::PublishState setting status TRUE"));
+			}
+		else
+			{
+			LOG(_L("CBTInquiryMgr::PublishState setting status FALSE"));
+			}
+		}
+	else
+		{
+		LOG(_L("CBTInquiryMgr::PublishState not updating status"));
+		}			
+ 	}
+
+void CBTInquiryMgr::SetLocalNameComplete(TInt aErr)
+	{
+	LOG_FUNC
+	TDblQueIter<CBTHostResolver> iter(iHRs);
+	while (iter)
+		{
+		(iter++)->SetLocalNameComplete(aErr);
+		}
+	}
+
+void CBTInquiryMgr::GetLocalNameComplete(TInt aErr, const TDesC8& aName)
+	{
+	LOG_FUNC
+	TDblQueIter<CBTHostResolver> iter(iHRs);
+	while (iter)
+		{
+		(iter++)->GetLocalNameComplete(aErr, aName);
+		}
+	}
+
+void CBTInquiryMgr::StartInquiry(CBTHostResolver& aResolver, TUint aIAC, TBool aIgnoreCache)
+	{
+	LOG_FUNC
+	// Pre-load any existing results into the CBTHostResolver
+	if (!aIgnoreCache)
+		{
+		// Pre-load any existing results into the CBTHostResolver
+		iCurrentResults.ReturnToFirstResult();
+		while (CBTInqResultRef* ref = iCurrentResults.NextResult())
+			{
+			// If GIAC is being requested, we return all results
+			if (aIAC == KGIAC || ref->Result().HasRespondedToIAC(aIAC))
+				{
+				aResolver.InquiryResult(ref->Result());
+				}
+			}
+		}
+	
+	if ( !aIgnoreCache && !iCurrentResults.IsEmpty() && CacheAge(aIAC) <= KCacheStaleAge)
+		{// Cache not yet stale, so just give these results back and dont start
+		LOG(_L("CBTInquiryMgr::StartInquiry giving result from cache"));
+		aResolver.InquiryComplete(KErrNone);
+		return;
+		}
+	
+	if (iRequestedInquiryIAC || iQueuedInquiryIAC)
+		{
+		LOG(_L("CBTInquiryMgr::StartInquiry iRequestedInquiryIAC"));
+		if(iRequestedInquiryIAC == aIAC)
+			{
+			// an Inquiry is ongoing, return any results already found during the
+			// current Inquiry if not already done so as part of the complete cache
+			if (aIgnoreCache)
+				{
+				iCurrentResults.ReturnToFirstResult();
+				while (CBTInqResultRef* ref = iCurrentResults.NextResult())
+					{
+					if (ref->Result().iFoundDuringCurrentInquiry)
+						{
+						aResolver.InquiryResult(ref->Result());
+						}
+					}	
+				}
+			// the current Inquiry will just continue
+			return;			
+			}
+		if (aIAC == KGIAC)
+			{
+			// If the current IAC is GIAC, and the requested inquiry IAC isn't, it must be LIAC
+			__ASSERT_DEBUG(iRequestedInquiryIAC == KLIAC, Panic(EBTUnexpectedIAC)); 
+			// Queue a general inquiry for when the current limited inquiry has finished
+			iQueuedInquiryIAC = aIAC;
+			return;
+			}
+		else if(iHWState == EInquiry)
+			{
+			// The host resolver should only allow through GIAC and LIAC, and we handle GIAC above
+			__ASSERT_DEBUG(aIAC == KLIAC, Panic(EBTUnexpectedIAC)); 
+			// We favour a Limited inqiury, so interrupt the current general inquiry
+			TInt err = CancelHardwareInquiry();
+			if(err!=KErrNone)
+				{
+				LOG(_L("CBTInquiryMgr::StartInquiry cancel didn't work"));
+				aResolver.InquiryComplete(err); // cancel went wrong
+				return;
+				}
+			// Queue a general inquiry for when the limited inquiry is complete
+			iRequestedInquiryIAC = KLIAC;
+			iQueuedInquiryIAC = KGIAC;
+			SetHWState(ECancellingForNewIAC);
+			iFlusher->Cancel(); 	// Stop watchdog, start flusher.
+			return;
+			}
+		else
+			{
+			// The host resolver should only allow through GIAC and LIAC, and we handle GIAC above
+			__ASSERT_DEBUG(aIAC == KLIAC, Panic(EBTUnexpectedIAC)); 
+			iRequestedInquiryIAC = KLIAC;
+			iQueuedInquiryIAC = KGIAC;
+			}
+		}
+
+	iRequestedInquiryIAC = aIAC;
+	iInquiryInteruptions = 0;
+
+	DoInquiry();
+	}
+
+void CBTInquiryMgr::Suspend()
+/**
+	Ah - somebody wishes to make a connection - we need to clear the way
+	If we are doing a namerequest we can cancel.
+	
+	WARNING - The caller of this must ensure a call to Resume() ASAP
+**/
+	{
+	LOG_FUNC
+
+	if(iHWState == EInquiry)
+		{
+		// This is a best effort service, the Connect will be tried even
+		// if we fail to stop the inquiry, so ignore errors.
+		static_cast<void>(CancelHardwareInquiry());
+		}
+	else if (iHWState == ENameLookup)
+		{
+		
+		iCurrentResults.ReturnToFirstResult();
+		while(CBTInqResultRef *ref = iCurrentResults.NextResult())
+			{
+
+			CBTInqResultRecord& rec = ref->Result();
+			if(rec.IsNameRequestPending())
+				{
+				// This is a best effort service, the Connect will be tried even
+				// if we fail to stop the Name request, so ignore errors.
+				TRAP_IGNORE(CancelRemoteNameL(rec.LogEntry().iBdaddr));
+				}
+			}
+
+		}
+		
+	iFlusher->Cancel(); 	// Stop watchdog, start flusher.
+	SetHWState(EConnecting);	// will stop inquirymanager doing anything else
+	// don't publish status here, will be cleared up when manager tries to do soemthing else
+	EnableFlusher();
+	}
+
+void CBTInquiryMgr::Resume()
+/**
+	We can now carry on...
+**/
+	{
+	LOG_FUNC
+	if(iHWState == EConnecting)
+		{
+		LOG(_L("InquiryMgr: Hardware connected; resuming operations (when a new inquiry starts"));
+	 	SetHWState(EIdle);	
+	 	// don't publish status here, it will be set by namelookup
+		LOG(_L("CBTInquiryMgr::Resume asking for another name lookup"));
+		DoNameLookup(EFalse);
+		DoInquiry();
+		EnableFlusher(); // in case no operations started
+		}
+	}
+
+void CBTInquiryMgr::LookupName(CBTHostResolver& aResolver, const TBTDevAddr& aAddr, TBool aIgnoreCache, TBool aExplicitNameRequest)
+/**
+This method is called by a CBTHostResolver to look up the name of a device with a given address. If the
+name is not immediately available a name lookup request is queued within the inquiry manager. This 
+request will be actioned by CBTInquiryMgr::DoNameLookup(), and the remote device response will be 
+sent (by CBTInquiryMgr::RemoteNameResult) to all current host resolvers.
+**/
+	{
+	LOG_FUNC
+	LOG1(_L("CBTHostResolver: 0x%8x"), &aResolver);
+	LOG6(_L(", aAddr: %02x %02x %02x %02x %02x %02x"),
+ 				  TUint8(aAddr[0]), TUint8(aAddr[1]), TUint8(aAddr[2]), TUint8(aAddr[3]), TUint8(aAddr[4]), 
+ 				  TUint8(aAddr[5]));
+ 				  
+	CBTInqResultRef* ref = AddEntryToCache(aAddr); //N.B. Creates a new entry if one doesn't exist
+
+	if(!ref)
+		{
+		aResolver.NameLookupResult(KErrNoMemory, aAddr, KNullDesC8);
+		return;
+		}
+
+	// check state of cache entry
+	CBTInqResultRecord& rec = ref->Result();
+
+	if(rec.HaveNameLookupResult() && rec.IsNameComplete() && (!aIgnoreCache|| rec.iFoundDuringCurrentInquiry))
+		{// Either got a name, or we made an attempt that failed
+		aResolver.NameLookupResult(rec.NameLookupResultCode(),
+								   rec.LogEntry().iBdaddr,
+								   rec.iName);
+		return;
+		}
+	
+	if (aExplicitNameRequest)
+		{
+		rec.SetExplicitNameRequest(ETrue);
+		}
+	
+	if(rec.IsNameRequestPending())
+		{
+		return; // it's already happening
+		}
+
+	rec.SetNamePending(ETrue);
+	rec.iNameLookupAttempts = 0;
+	++iPendingNameRequests;
+	iNewPageRequestsPending = ETrue;
+
+	if(iHWState == EInquiry)
+		{
+		if(iPendingNameRequests > iInquiryInteruptions
+		   || iInquiryInteruptions < KImmediateNameFetch)
+			{
+			TryToInterruptInquiryForNameLookup();
+			}
+		}
+	else
+		{
+		LOG(_L("CBTInquiryMgr::LookupName asking for another name lookup"));
+		DoNameLookup(EFalse);
+		}
+	}
+
+void CBTInquiryMgr::ClearCache()
+	{
+	LOG_FUNC
+	if(iHWState == EInquiry)
+		{
+		TInt err = CancelHardwareInquiry();
+		if(err==KErrNone)
+			{
+			// Don't clear cache if we couldn't cancel inquiry.
+			// We'll be slightly unfaithful in the case of OOM...
+			iCurrentResults.Reset();
+			InquiryComplete(KErrNone, 0);
+			}
+		}
+	else
+		{
+		iCurrentResults.Reset();
+		}
+	}
+
+TInt CBTInquiryMgr::SetLocalName(const TDesC8& aName)
+	{
+	LOG_FUNC
+	return iLinkMgrProtocol.SetLocalDeviceName(aName);
+	}
+
+TInt CBTInquiryMgr::GetLocalName()
+	{
+	LOG_FUNC
+	TRAPD(err, ReadLocalNameL());
+	return err;
+	}
+
+/**
+	This is called whenever the local HCI version is updated (usually only during startup), 
+	so that the inquiry mode is set accordingly
+**/
+void CBTInquiryMgr::SetInquiryMode()
+	{
+	LOG_FUNC
+	
+	THCIInquiryMode inquiryMode = EStandardInquiryFormat;
+	
+	if (iLinkMgrProtocol.IsExtendedInquiryResponseSupportedLocally())
+		{
+		inquiryMode = EInquiryWithRssiOrEir;
+		}
+	else if (iLinkMgrProtocol.IsRssiWithInquiryResultsSupportedLocally())
+		{
+		inquiryMode = EInquiryWithRssi;
+		}
+	
+	if (inquiryMode != EStandardInquiryFormat)
+		{
+		TRAPD(err, WriteInquiryModeL(inquiryMode));
+		if (err == KErrNone)
+			{
+			iPendingInquiryMode = inquiryMode;
+			}
+		}
+	}
+/**
+	This is called whenever the pending WriteInquiryMode command has completed. 
+**/
+void CBTInquiryMgr::WriteInquiryModeComplete(TBool aSucceeded)
+	{
+	LOG_FUNC
+	if (aSucceeded)
+		{
+		iInquiryMode = iPendingInquiryMode;
+		return;
+		}
+
+	// should we maybe try to set another mode? Probably worth a try...
+	// let's downgrade the inquiry mode
+	if (iPendingInquiryMode == EInquiryWithRssiOrEir)
+		{
+		TRAPD(err, WriteInquiryModeL(EInquiryWithRssi));
+		if (err == KErrNone)
+			{
+			iPendingInquiryMode = EInquiryWithRssi;
+			}
+		}
+	}
+
+void CBTInquiryMgr::DoInquiry()
+/**
+	Try to start the inquiry.
+	Only starts it if there isn't already one going.
+**/
+	{
+	LOG_FUNC
+
+	if(iRequestedInquiryIAC == 0 || iHWState != EIdle || iHRs.IsEmpty())
+		{
+#ifdef _DEBUG
+		LOG3(_L("Not starting inquiry. iRequestedInquiryIAC == %d, iHWState == %d, iHostResolverCount == %d"), iRequestedInquiryIAC, iHWState, iNumHRs);
+		if (iHRs.IsEmpty())
+			{
+			LOG(_L("No HRs interested in results - Stopping discovery"));
+			}
+#endif
+		if (iHWState == EIdle)
+			{
+			LOG(_L("CBTInquiryMgr::DoInquiry PublishStatus Idle"));	
+			PublishStatus();// make sure the status says we're idle
+			}
+		return;
+		}
+
+	// If pending on name lookup, we'll do it when that finishes
+
+	// Cache stale -- update it.
+	TInt err = StartHardwareInquiry();
+
+	if (err == KErrNone)
+		{
+	 	SetHWState(EInquiry);
+		LOG(_L("CBTInquiryMgr::DoInquiry PublishState Inquiry"));
+		PublishStatus();
+		// Use cache age to estimate time elapsed while inquiring.
+		// Synchronise it with the inquiry
+		// Stop flusher, Start inquiry wathcdog
+		iFlusher->Cancel();
+		TCallBack cb(InquiryWatchdog, this);
+		iFlusher->Start(KInquiryWatchdogPeriod * 1000000,
+						KInquiryWatchdogPeriod * 1000000,
+						cb);
+		SetCacheAge(iCurrentInquiryIAC, 0);
+		iInquirySilenceCount = 0;
+		iResultCount = 0;
+		}
+	else
+		{
+		// Couldn't start inquiry.
+		// Make sure the request is completed.
+		iRequestedInquiryIAC = 0;
+		InquiryComplete(err, 0);
+		LOG(_L("CBTInquiryMgr::DoInquiry PublishState Idle couldn't start inquiry"));
+		PublishStatus();
+		return;
+		}
+	}
+
+void CBTInquiryMgr::ClearCurrentInquiryResults()
+	{
+	LOG_FUNC
+	iCurrentResults.ReturnToFirstResult();
+	while (CBTInqResultRef* ref = iCurrentResults.NextResult())
+		{
+		ref->Result().iFoundDuringCurrentInquiry = EFalse;
+		}	
+	}
+
+TInt CBTInquiryMgr::CancelHardwareInquiry()
+	{
+	LOG_FUNC
+	// CancelInquiryL will stop the current inquiry so clear any results that
+	// were marked found during the inquiry
+	ClearCurrentInquiryResults();
+
+	TRAPD(err, CancelInquiryL());
+	return err;
+	}
+
+TInt CBTInquiryMgr::StartHardwareInquiry()
+	{
+	LOG_FUNC
+	iCurrentInquiryIAC = iRequestedInquiryIAC;
+	// attempt to free up baseband space for best performance discovery
+	iLinkMgrProtocol.PhysicalLinksMgr().RequireSlotSpace(); // will *eventually* put connections in hold - we dont wait though
+	TRAPD(err, StartInquiryL(iCurrentInquiryIAC, KInquiryLength, KInquiryMaxResults));
+
+	return err;
+	}
+
+
+
+
+void CBTInquiryMgr::DoNameLookup(TBool aInquiryComplete)
+/**
+This method attempts to issue a name lookup to the HCI
+**/
+	{
+	LOG_FUNC
+
+	if(iHWState != EIdle || iPendingNameRequests == 0 || iHRs.IsEmpty())
+		{
+#ifdef _DEBUG
+		LOG3(_L("Not starting name lookup. iCurrentInquiryIAC == %d, iHWState == %d, iHostResolverCount == %d"), iCurrentInquiryIAC, iHWState, iNumHRs);
+#endif
+		/* if hw is idle and the inquiry is ready we are finished
+		 and will not get another inquiry call so publish status idle
+		 note that if doing 'inquiry with names'
+		 in inquiry the aInquiryComplete flag stops state oscilating
+		 thostres name request for all devices will still cause this to
+		 oscilate because each name request is done individually, at this layer
+		 we have no idea whether the test program will ask for another name */	
+		if ((iHWState == EIdle) && (aInquiryComplete))
+			{
+			LOG(_L("CBTInquiryMgr::DoNameLookup inquiry finished with"));
+			PublishStatus();
+			}			
+		// else publish status will be sorted by next inquiry 
+		return;
+		}
+
+	iCurrentResults.ReturnToFirstResult();
+	CBTInqResultRef *refToGet = NULL;
+	while(CBTInqResultRef *ref = iCurrentResults.NextResult())
+		{
+		CBTInqResultRecord& rec = ref->Result();
+		if(rec.IsNameRequestPending())
+			{
+			if(!iRequestedInquiryIAC ||
+			   rec.NameLookupAttempts() < KMaxNameLookupAttemptsDuringInquiry)
+				{
+				// We want the first record for the current IAC or a record for an explicit name request.
+				// Failing that, we'll just have the first record
+				if (rec.HasRespondedToIAC(iCurrentInquiryIAC) || rec.IsExplicitNameRequest())
+					{
+					refToGet = ref;
+					break;
+					}
+				if (!refToGet)
+					{
+					refToGet = ref;
+					}
+				}
+			}
+		}
+	if (refToGet)
+		{
+		CBTInqResultRecord& rec = refToGet->Result();
+
+		// First set the page timeout, it is a best effort attempt
+		iNamePageTimeout = iLinkMgrProtocol.PhysicalLinksMgr().TryToChangePageTimeout(iNamePageTimeout);
+
+		// Request the name lookup.
+		TRAPD(err, LookupNameL(rec.LogEntry()));
+
+		if (err == KErrNone)
+			{
+			SetHWState(ENameLookup);
+			return;
+			}
+		else
+			{
+			// got a synchronous error - put in a blank name
+			HandleRemoteNameResult(err, *refToGet, KNullDesC8());
+			}
+		}
+	// Nothing new to do!
+	iNewPageRequestsPending = EFalse;
+	}
+
+void CBTInquiryMgr::TryToInterruptInquiryForNameLookup()
+	{
+	LOG_FUNC
+	TInt err = CancelHardwareInquiry();
+
+	if(err == KErrNone)
+		{// Start doing name lookups
+		iFlusher->Cancel();	//Stop watchdog, start flusher
+	 	SetHWState(EIdle);
+		// don't publish status here, namelookup/inquiry will deal with it
+		EnableFlusher();
+		++iInquiryInteruptions;
+		LOG(_L("CBTInquiryMgr::TryToInterruptInquiryForNameLookup asking for another name lookup"));
+		DoNameLookup(EFalse);
+		DoInquiry(); // <- In case name lookup fails
+		}
+	}
+
+// An inelegant workaround called from CLinkMgrProtocol::Error to get round
+//  the fact that the stack doesn't (yet) keep track of commands that it has
+//  been asked to do. If they aren't completed on a reset due to a
+//  KErrHardwareNotFound error then the stack hangs as it waits for the responses.
+void CBTInquiryMgr::CompleteCommands(TInt aErr)
+	{
+	LOG_FUNC
+	SetLocalNameComplete(aErr);
+	GetLocalNameComplete(aErr, _L8(""));
+
+	// Reset any inquiry results left over from a previous inquiry
+	iCurrentResults.Reset();
+	InquiryComplete(aErr, 0);
+	}
+
+
+// Check whether the controller supports Extended Inquiry Response by examing
+// the supported features mask using Link Manage Protocol
+TBool CBTInquiryMgr::IsExtendedInquiryResponseSupported()
+	{
+	LOG_FUNC
+	return iLinkMgrProtocol.IsExtendedInquiryResponseSupportedLocally();
+	}
+
+/******************************************************************************/
+/*	If UPDATING THE CACHE, please use one of the "AddEntry..." methods below. */
+/******************************************************************************/
+CBTInqResultRef* CBTInquiryMgr::FindExistingCacheEntry(const TBTDevAddr& aAddr)
+	{
+	LOG_FUNC
+	return(iCurrentResults.FindEntry(aAddr));
+	}
+
+CBTInqResultRef* CBTInquiryMgr::AddEntryToCache(const TBTDevAddr& aAddr)
+	{
+	LOG_FUNC
+	CBTInqResultRef* ref = FindExistingCacheEntry(aAddr);
+	if(ref)
+		{// Already in there!
+		return ref;
+		}
+
+	CBTInqResultRecord* rec = new CBTInqResultRecord(aAddr);
+	if (!rec)
+		{
+		return 0;
+		}
+
+	ref = iCurrentResults.Add(*rec);
+	if (!ref)
+		{
+		delete rec;
+		return 0;
+		}
+
+	//default CBTInqResultRecord values - provided in CBTInqResultRecord constructer (unlike v1)
+	//maybe overwritten later
+
+	EnableFlusher(); // Make sure we're aging entries.
+	return ref;
+	}
+
+CBTInqResultRef* CBTInquiryMgr::AddEntryWithJuiceToCache(const TInquiryLogEntry& aEntry)
+/**
+This method should be used if you are supplying cache with all valid
+baseband parameters.
+Setting the valid bit in clock offset allows us to tell btman that the clock
+offset value, and by inferrence the other juice values are valid -
+i.e. have been supplied by the HCI, as opposed to having been supplied
+as default.
+**/
+	{
+	LOG_FUNC
+	CBTInqResultRef* ref = AddEntryToCache(aEntry.iBdaddr);
+
+	if (ref)
+		{
+		CBTInqResultRecord& rec = ref->Result();
+		// Update all, and register that values come from HCI
+		rec.iJuiceFromHCIMask |= EBluetoothJuice;
+		// First fill in the base class members, common to all inquiry results
+		*static_cast<TInquiryLogEntry*>(&rec.iEntry) = aEntry;
+		// Now complete with extra data depending on the inquiry result type
+		switch(aEntry.iSpare)
+			{
+		case KInqLogEntryStandard:
+			break;
+		case KInqLogEntryWithEir:
+			{
+			const TInquiryLogEntryWithEir& entryEir = static_cast<const TInquiryLogEntryWithEir &>(aEntry);
+			// Only replace EIR if it contains something, since sometimes EIR transmission fails
+			if(entryEir.iExtendedInquiryResponse.Length() != 0)
+				{
+				rec.iEntry.iExtendedInquiryResponse = entryEir.iExtendedInquiryResponse;
+				}
+			rec.iJuiceFromHCIMask |= EBluetoothEir;
+			// Now check whether we can extract a complete or partial friendly name from the EIR and add it to the cache
+			TPtrC8 name;
+			TBool complete = ETrue;
+			rec.Codec().Set(rec.iEntry.iExtendedInquiryResponse);
+			// use EirCodec doing sanity check of the eir data
+			TInt error = rec.Codec().DoSanityCheck(rec.iEntry.iExtendedInquiryResponse);
+			if(error == KErrNone)
+				{
+				error = rec.Codec().GetDeviceName(name);
+				if(error >= KErrNone)
+					{
+					if(error == EDataPartial)
+						{
+						complete = EFalse;
+						}
+					// Do not overwrite complete names with partial ones
+					if(complete || !rec.IsNameValid() || (rec.IsNameValid() && !rec.IsNameComplete()))
+						{
+						rec.SetName(name);
+						rec.SetNameComplete(complete);
+						rec.iFlushes = 0;
+						rec.SetNameValid(ETrue);
+						rec.SetNameRefreshRequested(EFalse);
+						}
+					}
+				}
+			}
+		// Fall through
+		case KInqLogEntryWithRssi:
+			{
+			const TInquiryLogEntryWithRssi& entryRssi = static_cast<const TInquiryLogEntryWithRssi &>(aEntry);
+			rec.iEntry.iRssi = entryRssi.iRssi;
+			rec.iJuiceFromHCIMask |= EBluetoothRssi;
+			break;
+			}
+		default:
+			__ASSERT_DEBUG(EFalse, Panic(EBTInvalidInquiryLogEntry));
+			break;
+			}
+		// Mark as valid, HCI does not (necessarily) do this for you
+		rec.iEntry.iClockOffset |= KHCIClockOffsetValidBit;
+		}
+
+	return ref;
+	}
+
+CBTInqResultRef* CBTInquiryMgr::AddEntryWithCoDToCache(const TBTDevAddr& aAddr, const TUint aCoD)
+	{
+	LOG_FUNC
+	CBTInqResultRef* ref = AddEntryToCache(aAddr);
+
+	if (ref)
+		{
+		// Update all, and register that values come from HCI
+		ref->Result().iJuiceFromHCIMask |= EBluetoothCoD;
+		ref->Result().iEntry.iCoD = aCoD;
+		}
+
+	return ref;
+	}
+
+CBTInqResultRef* CBTInquiryMgr::AddEntryWithClockOffsetToCache(const TBTDevAddr& aAddr, const TBasebandTime aClockOffset)
+	{
+	LOG_FUNC
+	CBTInqResultRef* ref = AddEntryToCache(aAddr);
+
+	if (ref)
+		{
+		//update the clock offset - useful for subsequent connections
+		// mark as valid
+		ref->Result().iJuiceFromHCIMask |= EBluetoothClockOffSet;
+		ref->Result().LogEntry().iClockOffset = static_cast<TUint16>(aClockOffset | KHCIClockOffsetValidBit);
+		}
+
+	return ref;
+	}
+
+
+TInt CBTInquiryMgr::InquiryWatchdog(TAny* aPtr)
+/*
+Called second while doing enquiry.
+Considers whether to give up enquiry
+*/
+	{
+	LOG_STATIC_FUNC
+	CBTInquiryMgr& self = *static_cast<CBTInquiryMgr*>(aPtr);
+	__ASSERT_DEBUG(self.iHWState == EInquiry, Panic(EHostResolverBadHWState));
+	if(self.iResultCount == 0)
+		{
+		++self.iInquirySilenceCount;
+		}
+
+	if(self.iNewPageRequestsPending
+	   && (self.iInquirySilenceCount * KInquiryWatchdogPeriod) > self.iInquiryInteruptions)
+		{// Silence, and names are waiting. Defer the inquiry
+		self.TryToInterruptInquiryForNameLookup();
+		}
+
+	self.iResultCount = 0;
+	return 0;
+	}
+
+TInt CBTInquiryMgr::Flush(TAny* aPtr)
+	{
+	LOG_STATIC_FUNC
+	CBTInquiryMgr& self = *static_cast<CBTInquiryMgr*>(aPtr);
+	__ASSERT_DEBUG(self.iHWState != EInquiry, Panic(EHostResolverBadHWState));
+	self.DoFlush();
+	return 0;
+	}
+
+void CBTInquiryMgr::DoFlush()
+	{
+	LOG_FUNC
+	for (TInt i = 0; i < iCacheAge.Count(); i++)
+		{
+		++iCacheAge[i].iCacheAge;
+		}
+	iCurrentResults.ReturnToFirstResult();	
+
+	while (CBTInqResultRef* ref = iCurrentResults.NextResult())
+		{
+		CBTInqResultRecord& rec = ref->Result();
+		TInt age = rec.IncFlushes();
+		if(age >= KRecordStaleAge && rec.NumberOfIACsRespondedTo() > 0)
+			{
+			// device is around, but not seen for a while
+			rec.ClearIACs();
+			LOG(_L("CBTInquiryMgr::DoFlush - ClearIACs"));
+			}
+			
+		if(age >= KRecordDeathAge)
+			{
+			rec.SetNameValid(EFalse);
+			LOG(_L("CBTInquiryMgr::DoFlush - age >= KRecordDeathAge setting name valid False"));
+			}
+			
+		if(age >= KRecordDeathAge && rec.NumberOfIACsRespondedTo() == 0 && !rec.IsNameValid() 
+			&& (!rec.IsNameRequestPending() || iHRs.IsEmpty())) //Don't flush old record if name pending and HRs present
+			{// Record is dead. Delete it
+			LOG(_L("CBTInquiryMgr::DoFlush - Deleting reference"));
+			delete ref;
+			}
+		else if(rec.IsNameRefreshRequested() && iHWState == EIdle)
+			{// Try to get this name now, perhaps?
+			LOG(_L("CBTInquiryMgr::DoFlush - Try to get name straight away"));
+			rec.SetNameRefreshRequested(EFalse);
+			rec.SetNamePending(ETrue);
+			rec.iNameLookupAttempts = 0;
+			++iPendingNameRequests;
+			LOG(_L("CBTInquiryMgr::DoFlush asking for another name lookup"));
+			DoNameLookup(EFalse);
+			}
+		}
+	if (iCurrentResults.IsEmpty())
+		{
+		iNewPageRequestsPending = EFalse;
+		iPendingNameRequests = 0;
+		iFlusher->Cancel();
+		}
+	}
+
+void CBTInquiryMgr::EnableFlusher()
+	{
+	LOG_FUNC
+	if (iFlusher->IsActive() || iHWState == EInquiry)
+		return;
+	static const TInt usec2sec = 1000000;
+	TCallBack cb(Flush, this);
+	iFlusher->Start(usec2sec / 4, // 1/4 sec for initial flush
+					KFlushTimeoutSecs * usec2sec,
+					cb);
+	}
+
+TInt CBTInquiryMgr::CacheAge(TUint aIAC) const
+	{
+	TInt ret = KMaxTInt; // If we haven't set a cache age for this IAC, return KMaxTInt
+	for (TUint i = 0; i < iCacheAge.Count(); i++)
+		{
+		if (iCacheAge[i].iIAC == aIAC)
+			{
+			ret = iCacheAge[i].iCacheAge;
+			break;
+			}
+		}
+	return ret;
+	}
+
+void CBTInquiryMgr::SetCacheAge(TUint aIAC, TInt aAge)
+	{
+	TBool found = EFalse;
+	for (TUint i = 0; i < iCacheAge.Count(); i++)
+		{
+		if (iCacheAge[i].iIAC == aIAC)
+			{
+			iCacheAge[i].iCacheAge = aAge;
+			found = ETrue;
+			break;
+			}
+		}
+	if (!found)
+		{
+		TInquiryCacheAge ageInfo;
+		ageInfo.iIAC = aIAC;
+		ageInfo.iCacheAge = aAge;
+		iCacheAge.Append(ageInfo);
+		// If we can't append, there's not a lot we can do - we'll just have
+		// to return KMaxTInt when someone asks for the age
+		}
+	}
+
+
+// -----------------------------------------------------------------------------------------
+
+void CBTInquiryMgr::StartInquiryL(TUint aIAC, TUint8 aLength, TUint8 aNumResponses)
+	{
+	LOG_FUNC
+	// Ownership of cmd transfered even if MhcqAddCommandL leaves
+	CInquiryCommand* cmd = CInquiryCommand::NewL(aIAC, aLength, aNumResponses);
+	CommandQueue().MhcqAddCommandL(cmd, *this);
+	}
+
+void CBTInquiryMgr::CancelInquiryL()
+	{
+	LOG_FUNC
+	// Ownership of cmd transfered even if MhcqAddCommandL leaves
+	CInquiryCancelCommand* cmd = CInquiryCancelCommand::NewL();
+	CommandQueue().MhcqAddCommandL(cmd, *this);
+	}
+
+void CBTInquiryMgr::CancelRemoteNameL(const TBTDevAddr& aAddr)
+	{
+	LOG_FUNC
+	CRemoteNameRequestCancelCommand* cmd = CRemoteNameRequestCancelCommand::NewL(aAddr);
+	CommandQueue().MhcqAddCommandL(cmd, *this);
+	}
+
+void CBTInquiryMgr::WriteInquiryModeL(TUint8 aInquiryMode)
+	{
+	LOG_FUNC
+	// Ownership of cmd transfered even if MhcqAddCommandL leaves
+	CWriteInquiryModeCommand* cmd = CWriteInquiryModeCommand::NewL(aInquiryMode);
+	CommandQueue().MhcqAddCommandL(cmd, *this);
+	}
+
+/**
+This function should be used by the inquiry manager to retrieve remote names.
+*/
+void CBTInquiryMgr::LookupNameL(const TInquiryLogEntry& aEntry)
+	{
+	LOG_FUNC
+	// Ownership of cmd transfered even if MhcqAddCommandL leaves
+	CRemoteNameRequestCommand* cmd = CRemoteNameRequestCommand::NewL(aEntry.iBdaddr, aEntry.iPageScanRepetitionMode, aEntry.iPageScanMode, aEntry.iClockOffset);
+	CommandQueue().MhcqAddCommandL(cmd, *this);
+	}
+
+/**
+This function should only be used when there is an established physical link (and therefore from
+CPhysicalLink only) to retrieve a remote name.
+*/
+void CBTInquiryMgr::ReadRemoteNameL(const TBTDevAddr& aAddr)
+	{
+	LOG_FUNC
+	// Ownership of cmd transfered even if MhcqAddCommandL leaves
+	CRemoteNameRequestCommand* cmd = CRemoteNameRequestCommand::NewL(aAddr, 0, 0, 0);
+	CommandQueue().MhcqAddCommandL(cmd, *this);
+	}
+
+void CBTInquiryMgr::ReadLocalNameL()
+	{
+	LOG_FUNC
+	// Ownership of cmd transfered even if MhcqAddCommandL leaves
+	CReadLocalNameCommand* cmd = CReadLocalNameCommand::NewL();
+	CommandQueue().MhcqAddCommandL(cmd, *this);
+	}
+
+void CBTInquiryMgr::MhcqcCommandErrored(TInt aErrorCode, const CHCICommandBase* aCommand)
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(aCommand, Panic(EBTInquiryMgrUnmatchedEvent));
+	LOG2(_L("MhcqcCommandErrored: error code:%d opcode:0x%x"), aErrorCode, aCommand->Opcode());
+	
+	if (aCommand->Opcode() == KInquiryOpcode)
+		{
+		// Clear any pending stuff
+		CompleteCommands(aErrorCode);
+		// this will also set the state to Idle
+		}
+	else if (aCommand->Opcode() == KWriteInquiryModeOpcode)
+		{
+		// command had error before response -- assume not supported
+		WriteInquiryModeComplete(EFalse);
+		}
+	else if (aCommand->Opcode() == KRemoteNameRequestOpcode)
+		{
+		// command had error before response -- doctor a fake response and process it to restore sanity
+		TBuf8<256> fakeEventBuffer;
+		const TBTDevAddr remNameReqAddr = static_cast<const CRemoteNameRequestCommand*>(aCommand)->BDADDR();
+		TRemoteNameReqCompleteEvent fakeRemoteNameRequestCompleteEvent(EOK, remNameReqAddr, _L8(""), fakeEventBuffer);
+		RemoteNameReqCompleteEvent(fakeRemoteNameRequestCompleteEvent);
+		// we will not change the state so a running inquiry can complete
+		}
+	else if (aCommand->Opcode() == KReadLocalNameOpcode)
+		{
+		// command had error before response -- doctor a fake response and process it to restore sanity
+		TBuf8<256> fakeEventBuffer;
+		TReadLocalNameCompleteEvent fakeLocalNameCompleteEvent(EUnspecifiedError, 0, _L8(""), fakeEventBuffer);
+		ReadLocalNameOpcode(EUnspecifiedError, fakeLocalNameCompleteEvent);
+		// this will also set the state to Idle
+		}
+	
+	}
+
+// From MHCICommandQueueClient
+void CBTInquiryMgr::MhcqcCommandEventReceived(const THCIEventBase& aEvent,
+											const CHCICommandBase* aRelatedCommand)
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(aRelatedCommand, Panic(EBTInquiryMgrUnmatchedEvent));
+	static_cast<void>(aRelatedCommand);
+	switch(aEvent.EventCode())
+		{
+	case ERemoteNameReqCompleteEvent:
+		RemoteNameReqCompleteEvent(aEvent);
+		break;
+
+	case ERemoteHostSupportedFeaturesNotificationEvent:
+		RemoteHostSupportedFeaturesNotificationEvent(aEvent);
+		break;
+
+	case EInquiryCompleteEvent:
+		InquiryCompleteEvent(aEvent);
+		break;
+
+	case EInquiryResultEvent:
+		InquiryResultEvent(aEvent);
+		break;
+
+	case EInquiryResultwithRSSIEvent:
+		InquiryResultWithRSSIEvent(aEvent);
+		break;
+
+	case EExtendedInquiryResultEvent:
+		ExtendedInquiryResultEvent(aEvent);
+		break;
+
+	case ECommandCompleteEvent:
+		CommandCompleteEvent(aEvent);
+		break;
+
+	case ECommandStatusEvent:
+		CommandStatusEvent(aEvent, *aRelatedCommand);
+		break;
+
+	default:
+		LOG1(_L("Warning!! Unknown Command Event Received (event code:%d)"), aEvent.EventCode());
+		__ASSERT_DEBUG(EFalse, Panic(EHCIUnknownCommandEvent));
+		break;
+		}
+	}
+
+void CBTInquiryMgr::CommandCompleteEvent(const THCIEventBase& aEvent)
+	{
+	LOG_FUNC
+	const THCICommandCompleteEvent& completeEvent = THCICommandCompleteEvent::Cast(aEvent);
+	THCIOpcode opcode = completeEvent.CommandOpcode();
+	THCIErrorCode hciErr = aEvent.ErrorCode();
+
+	switch (opcode)
+		{
+	case KWriteInquiryModeOpcode:
+		WriteInquiryModeOpcode(hciErr, aEvent);
+		break;
+
+	case KReadLocalNameOpcode:
+		ReadLocalNameOpcode(hciErr, aEvent);
+		break;
+
+	case KInquiryCancelOpcode:
+		InquiryCancelOpcode(hciErr, aEvent);
+		break;
+
+	// These commands are expected to not be handled and so can be safely ignored.
+	case KRemoteNameRequestCancelOpcode:
+		LOG1(_L("ignored Command Complete event (opcode: 0x%04x)"), opcode);
+		break;
+
+	// The commands below would most likely be used by the inquiry manager, however
+	// they currently are not used.
+	case KPeriodicInquiryModeOpcode:
+	case KExitPeriodicInquiryModeOpcode:
+	case KReadInquiryScanActivityOpcode:
+	case KWriteInquiryScanActivityOpcode:
+	case KReadInquiryScanTypeOpcode:
+	case KWriteInquiryScanTypeOpcode:
+	case KReadInquiryModeOpcode:
+		LOG1(_L("Warning!! Unhandled Command Complete Event (opcode:%d)"), opcode);
+		break;
+
+	default:
+		LOG2(_L("Error!! Unknown Command complete event! Opcode %d error code %d"), opcode, hciErr);
+		__ASSERT_DEBUG(EFalse, Panic(EHCIUnknownCommandCompleteOpcode));
+		break;
+		}
+	}
+
+void CBTInquiryMgr::CommandStatusEvent(const THCIEventBase& aEvent, const CHCICommandBase& aCommand)
+	{
+	LOG_FUNC
+
+	const TCommandStatusEvent& commandStatusEvent = TCommandStatusEvent::Cast(aEvent);
+	THCIOpcode opcode = commandStatusEvent.CommandOpcode();
+	THCIErrorCode hciErr = commandStatusEvent.ErrorCode();
+
+	__ASSERT_DEBUG(aCommand.Opcode() == opcode, Panic(EBTInquiryMgrMismatchedStatusEvent));
+
+	if (hciErr != EOK)
+		{
+		// got an error
+		// map onto the event that would have occurred: some things we will have to let the client work out
+		// e.g. they should check error and connection handle etc.
+		switch (opcode)
+			{
+		case KInquiryOpcode:
+			InquiryComplete(CHciUtil::SymbianErrorCode(hciErr), 0);
+			break;
+
+		case KRemoteNameRequestOpcode:
+				{
+				const CRemoteNameRequestCommand& remNameReq = static_cast<const CRemoteNameRequestCommand&>(aCommand);
+				TInt err = CHciUtil::SymbianErrorCode(hciErr);
+				TBTDevAddr addr = remNameReq.BDADDR();
+				TBTDeviceName8 nullDevName(KNullDesC8);
+
+				RemoteNameResult(err, addr, nullDevName);
+				iLinkMgrProtocol.PhysicalLinksMgr().RemoteName(hciErr, addr, nullDevName);
+				}
+			break;
+
+		default:
+			// Complete any other commands with an error
+			CommandCompleteEvent(aEvent);
+			break;
+			}
+		}
+	}
+
+void CBTInquiryMgr::WriteInquiryModeOpcode(THCIErrorCode aHciErr, const THCIEventBase& /*aEvent*/)
+	{
+	LOG_FUNC
+	WriteInquiryModeComplete(aHciErr == EOK);
+	}
+
+void CBTInquiryMgr::ReadLocalNameOpcode(THCIErrorCode aHciErr, const THCIEventBase& aEvent)
+	{
+	LOG_FUNC
+	if (aHciErr == EOK)
+		{
+		const TReadLocalNameCompleteEvent& readLocalNameCompleteEvent = TReadLocalNameCompleteEvent::Cast(aEvent);
+		TPtrC8 localName = readLocalNameCompleteEvent.LocalName();
+		
+		GetLocalNameComplete(CHciUtil::SymbianErrorCode(aHciErr), localName);
+		iLinkMgrProtocol.UpdateLocalDeviceName(localName);
+		}
+	else
+		{
+		_LIT8(KNoName, "");
+		GetLocalNameComplete(CHciUtil::SymbianErrorCode(aHciErr), KNoName());
+		}
+	}
+
+void CBTInquiryMgr::InquiryCancelOpcode(THCIErrorCode aHciErr, const THCIEventBase& /* aEvent */)
+	{
+	LOG_FUNC
+	if (aHciErr == EOK)
+		{
+		if (iHWState == ECancellingForNewIAC)
+			{
+			SetHWState(EIdle);
+			DoInquiry();
+			}
+		}
+	// If an error comes in, it may be because the inquiry complete came in first. In that case, everything
+	// will be handled by the Inquiry complete logic
+	}
+
+// ----------------------------------------------------------------------------
+// Event processing functions
+// ----------------------------------------------------------------------------
+
+void CBTInquiryMgr::InquiryCompleteEvent(const THCIEventBase& aEvent)
+	{
+	LOG_FUNC
+	InquiryComplete(CHciUtil::SymbianErrorCode(aEvent.ErrorCode()), 0);
+	}
+
+void CBTInquiryMgr::InquiryResultEvent(const THCIEventBase& aEvent)
+	{
+	LOG_FUNC
+	
+	const TInquiryResultEvent& inquiryResultEvent = TInquiryResultEvent::Cast(aEvent);
+	TInquiryLogEntry entry;
+	TUint responses = inquiryResultEvent.NumResponses();
+	
+	for (TUint index = 0; index < responses; index++)
+		{
+		entry.iSpare = KInqLogEntryStandard;
+		entry.iPageScanRepetitionMode = inquiryResultEvent.PageScanRepetitionMode(index);
+		entry.iPageScanPeriodMode = inquiryResultEvent.Reserved1(index); // v1.1 spec, no meaning in v1.2
+		entry.iPageScanMode = inquiryResultEvent.Reserved2(index); // v1.1 spec, no meaning in v1.2
+		entry.iClockOffset = inquiryResultEvent.ClockOffset(index);
+		entry.iBdaddr = inquiryResultEvent.BDADDR(index);
+		entry.iCoD = inquiryResultEvent.ClassOfDevice(index);
+		InquiryResult(CHciUtil::SymbianErrorCode(aEvent.ErrorCode()), entry);
+		}
+	}
+
+void CBTInquiryMgr::InquiryResultWithRSSIEvent(const THCIEventBase& aEvent)
+	{
+	LOG_FUNC
+	
+	const TInquiryResultwithRSSIEvent& inquiryResultwithRSSIEvent = TInquiryResultwithRSSIEvent::Cast(aEvent);
+	TInquiryLogEntryWithRssi entry;
+	TUint responses = inquiryResultwithRSSIEvent.NumResponses();
+	
+	for (TUint index = 0; index < responses; index++)
+		{
+		entry.iSpare = KInqLogEntryWithRssi;
+		entry.iPageScanRepetitionMode = inquiryResultwithRSSIEvent.PageScanRepetitionMode(index);
+		entry.iPageScanPeriodMode = 0x00;
+		entry.iPageScanMode = 0x00;
+		entry.iClockOffset = inquiryResultwithRSSIEvent.ClockOffset(index);
+		entry.iBdaddr = inquiryResultwithRSSIEvent.BDADDR(index);
+		entry.iCoD = inquiryResultwithRSSIEvent.ClassOfDevice(index);
+		entry.iRssi = inquiryResultwithRSSIEvent.RSSI(index);
+		InquiryResult(CHciUtil::SymbianErrorCode(aEvent.ErrorCode()), entry);
+		}
+	}
+
+void CBTInquiryMgr::ExtendedInquiryResultEvent(const THCIEventBase& aEvent)
+	{
+	LOG_FUNC
+	
+	const TExtendedInquiryResultEvent& extendedInquiryResultEvent = TExtendedInquiryResultEvent::Cast(aEvent);
+	TInquiryLogEntryWithEir entry;
+	
+	entry.iSpare = KInqLogEntryWithEir;
+	entry.iPageScanRepetitionMode = extendedInquiryResultEvent.PageScanRepetitionMode();
+	entry.iPageScanPeriodMode = 0x00;
+	entry.iPageScanMode = 0x00;
+	entry.iClockOffset = extendedInquiryResultEvent.ClockOffset();
+	entry.iBdaddr = extendedInquiryResultEvent.BDADDR();
+	entry.iCoD = extendedInquiryResultEvent.ClassOfDevice();
+	entry.iRssi = extendedInquiryResultEvent.RSSI();
+	entry.iExtendedInquiryResponse = extendedInquiryResultEvent.ExtendedInquiryResponse();
+	InquiryResult(CHciUtil::SymbianErrorCode(aEvent.ErrorCode()), entry);
+	}
+
+void CBTInquiryMgr::RemoteNameReqCompleteEvent(const THCIEventBase& aEvent)
+	{
+	LOG_FUNC
+	const TRemoteNameReqCompleteEvent& remNameReqCompleteEvent = TRemoteNameReqCompleteEvent::Cast(aEvent);
+	THCIErrorCode err = aEvent.ErrorCode();
+	const TBTDevAddr addr = remNameReqCompleteEvent.BDADDR();
+	TPtrC8 buf = remNameReqCompleteEvent.RemoteName();
+	
+	//shorten the name to the proper length so that we don't waste memory
+	TInt nullTerminator = buf.Locate(0);
+	if (nullTerminator == KErrNotFound)
+		{
+		nullTerminator = buf.Length();
+		}
+	TPtrC8 remoteName = buf.Left(nullTerminator);
+	
+	// name requests have two customers...
+	// inquiry manager
+	RemoteNameResult(CHciUtil::SymbianErrorCode(err), addr, remoteName);
+	// phy manager
+	iLinkMgrProtocol.PhysicalLinksMgr().RemoteName(err, addr, remoteName);
+	}
+
+void CBTInquiryMgr::RemoteHostSupportedFeaturesNotificationEvent(const THCIEventBase& aEvent)
+	{
+	LOG_FUNC
+	const TRemoteHostSupportedFeaturesNotificationEvent& remHostSupFeatEvent = TRemoteHostSupportedFeaturesNotificationEvent::Cast(aEvent);
+	THCIErrorCode err = remHostSupFeatEvent.ErrorCode();
+	TBTDevAddr addr = remHostSupFeatEvent.BDADDR();
+	TUint64 hostSupFeats = remHostSupFeatEvent.HostSupportedFeatures();
+
+	RemoteHostSupportedFeatures(CHciUtil::SymbianErrorCode(err), addr, hostSupFeats);
+	}
+
+
+#ifdef CONNECTION_PREEMPTS_INQUIRY
+// *******************************************************************
+// ACL Connecting status subscriber
+// *******************************************************************
+/*static*/ CConnectingStatusSubscriber* CConnectingStatusSubscriber::NewL(CBTInquiryMgr& aInquiryMgr)
+	{
+	LOG_STATIC_FUNC
+	CConnectingStatusSubscriber* self = new(ELeave) CConnectingStatusSubscriber(aInquiryMgr);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CConnectingStatusSubscriber::CConnectingStatusSubscriber(CBTInquiryMgr& aInquiryMgr)
+: CActive(CActive::EPriorityStandard), iParent(aInquiryMgr)
+	{
+	LOG_FUNC
+	CActiveScheduler::Add(this);
+	}
+
+CConnectingStatusSubscriber::~CConnectingStatusSubscriber()
+	{
+	LOG_FUNC
+	Cancel();
+	iProperty.Close();
+	}
+
+void CConnectingStatusSubscriber::DoCancel()
+	{
+	LOG_FUNC
+	iProperty.Cancel();
+	}
+
+void CConnectingStatusSubscriber::ConstructL()
+	{
+	LOG_FUNC
+	User::LeaveIfError(iProperty.Attach(KPropertyUidBluetoothCategory,
+										KPropertyKeyBluetoothGetConnectingStatus));
+	Subscribe();
+	}
+
+void CConnectingStatusSubscriber::Subscribe()
+	{
+	LOG_FUNC
+	iProperty.Subscribe(iStatus);
+	SetActive();
+	}
+
+/**
+This is looking for the connection to complete.  The inquiry must be
+synchronously cancelled before the CreateConnection command is issued,
+but we can resume it when we get round to it.
+*/
+void CConnectingStatusSubscriber::RunL()
+	{
+	LOG_FUNC
+	// Subscribe to the next change of state.
+	Subscribe();
+
+	TInt isConnecting;
+	// If this device is currently connecting an ACL suspend the
+	// inquiry.
+	iProperty.Get(isConnecting);
+	
+	if(!isConnecting)
+		{
+		iParent.Resume();
+		}
+	}
+#endif	// CONNECTION_PREEMPTS_INQUIRY