--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/linkmgr/hostresolver.h Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,511 @@
+// 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
+//
+//
+
+#ifndef L2HOSTRESOLVER_H
+#define L2HOSTRESOLVER_H
+
+
+#include <bt_sock.h>
+#include <es_prot.h>
+#include <bluetooth/hcicommandqueue.h>
+#include <bluetooth/hcicommandqueueclient.h>
+
+// BT1.1: Could make these runtime configurable.
+
+// HCI Inquiry length time, in 1.28 seconds.
+static const TInt KInquiryLength = 10;
+// Upper limit to number of results we can handle
+static const TInt KInquiryMaxResults = 00;
+
+// Seconds between flushes
+static const TInt KFlushTimeoutSecs = 5;
+// Number of flushes required to actually clear a record
+static const TInt KRecordDeathAge = 120; // 10 mins
+
+
+// Maximum flushes before the a device disappears to inquires
+static const TInt KRecordStaleAge = 10; // 50 secs
+// Maximum flushes before the cache is set to stale (needing refresh)
+static const TInt KCacheStaleAge = -1; // -1 == always needs refresh
+
+// While doing inquiry, set of watchdog every second
+static const TInt KInquiryWatchdogPeriod = 1;
+// Immidiately fetch the first 3 names
+static const TInt KImmediateNameFetch = 3;
+
+// Page Timeout for name request, we'll initially use this for each one
+static const TUint16 KMinNamePageTimeout = 0x1200; // 0x1200 = 3 secs
+// Amount to increase pagetimeout, everytime a lookup fails
+static const TUint16 KNamePageTimeoutIncrement = 0x140; // 0x140 = .2 sec
+/** Max Page Timeout for name request, we'll consider using (ACL connects
+are blocked while doing name lookup, so mustn't be too high!) **/
+static const TUint16 KMaxNamePageTimeout = 0x2500; // 0x2500 = 6 secs
+
+// Max times we'll try to get a single name while an inquiry pending
+static const TInt KMaxNameLookupAttemptsDuringInquiry = 1;
+// Max number of times to try to get a name
+static const TInt KMaxNameLookupAttempts = 4;
+
+
+
+class CBTInquiryMgr;
+class CBTInqResultRef;
+class CLinkMgrProtocol;
+
+
+enum TBTInqResultValid
+ {
+ EBluetoothAddr = 0x001, //000000000001
+ EBluetoothCoD = 0x008, //000000001000
+ EBluetoothPageScanRepMode = 0x080, //000010000000
+ EBluetoothPageScanMode = 0x100, //000100000000
+ EBluetoothClockOffSet = 0x200, //001000000000
+ EBluetoothRssi = 0x400, //010000000000
+ EBluetoothEir = 0x800, //100000000000
+ EBluetoothJuice = EBluetoothCoD |
+ EBluetoothPageScanRepMode |
+ EBluetoothPageScanMode |
+ EBluetoothClockOffSet
+ };
+
+
+/**
+ BT Inquiry Result record.
+ Ref counted object, deletes itself when no more CBTInqResultRef objects
+ point to it. Aggregates the TInquiryLogEntry type.
+**/
+
+NONSHARABLE_CLASS(CBTInqResultRecord) : public CBase
+ {
+friend class CBTInquiryMgr;
+friend class CBTInqResultRef;
+
+public:
+ TInquiryLogEntry& LogEntry();
+ void SetName(const TDesC8& aName);
+ const TDesC8& Name() const;
+ TBool IsNameRequestPending() const;
+ void SetNamePending(TBool aBool);
+ TBool IsNameRefreshRequested() const;
+ void SetNameRefreshRequested(TBool aBool);
+ TBool IsNameComplete() const;
+ void SetNameComplete(TBool aBool);
+ TBool IsExplicitNameRequest() const;
+ void SetExplicitNameRequest(TBool aBool);
+ TBool IsNameValid() const;
+ void SetNameValid(TBool aBool);
+ void SetNameLookupResultCode(TInt aResultCode);
+ TBool HaveNameLookupResult() const;
+ TInt NameLookupResultCode() const;
+ TInt NameLookupAttempts() const;
+ TInt IncFlushes();
+ void GetInquirySockAddr(TInquirySockAddr& aAddr);
+ TInt GetEir(TNameRecord& aNameRec, TBool aIgnoreCachedName);
+ TInt GetName(TNameRecord& aNameRec);
+ TInt AddIAC(TUint aIAC);
+ TBool HasRespondedToIAC(TUint aIAC);
+ TInt NumberOfIACsRespondedTo();
+ void ClearIACs();
+ inline TBool IsJuiceFromHCI() { return (EBluetoothJuice == (iJuiceFromHCIMask & EBluetoothJuice)); };//for the moment demand all
+ inline TBool IsPageScanModeFromHCI() { return iJuiceFromHCIMask & EBluetoothPageScanMode; };
+ inline TBool IsPageScanRepModeFromHCI() { return iJuiceFromHCIMask & EBluetoothPageScanRepMode; };
+ inline TBool IsCoDFromHCI() { return iJuiceFromHCIMask & EBluetoothCoD; };
+ inline TBool IsClockOffsetFromHCI() { return iJuiceFromHCIMask & EBluetoothClockOffSet; }
+ inline TBool IsEirPresent() { return iJuiceFromHCIMask & EBluetoothEir; }
+ inline TExtendedInquiryResponseDataCodec& Codec() { return iCodec; }
+
+private:
+ enum TNameStatus
+ {
+ ENamePending = 1,
+ ENameRefreshRequested = 2,
+ ENameComplete = 4,
+ ENameExplicitRequest = 8, // An explicit name lookup has been requested, so don't put this to the back of the queue
+ };
+
+ ~CBTInqResultRecord();
+ // Interface for CBTInquiryMgr
+ CBTInqResultRecord(const TBTDevAddr& aAddr);
+ // Interface for CBTInqResultRef
+ void Open();
+ void Close();
+
+ // Number of CBTInqResultRef objects pointing to this result
+ TInt iRefCount;
+ // The actual inquiry log entry. It contains EIR data, RSSI value and old style TInquiryLogEntry.
+ TInquiryLogEntryWithEir iEntry;
+ // The device name's state
+ TInt iNameStatus; //Bit flag
+ // The result of name lookup, of >0 if one hasn't been done
+ TInt iNameLookupResultCode;
+ // The device's name (if known), it can be from EIR or a Remote Name Request
+ TBuf8<KHCIRemoteDeviceNameMaxLength> iName;
+ // Number of attempts made at getting name.
+ TInt iNameLookupAttempts;
+ // Flush cycles since last seen (lower == newer).
+ TInt iFlushes;
+ // IACs this device has responded to
+ RArray<TUint> iIACs;
+ // Has inquiry log entry been populated by inquiry?
+ TUint16 iJuiceFromHCIMask;
+ // Has this entry been found during the current, ongoing inquiry?
+ TBool iFoundDuringCurrentInquiry;
+
+ TExtendedInquiryResponseDataCodec iCodec;
+ };
+
+/**
+ Inquiry result reference.
+ References a CBTInqResultRecord.
+**/
+NONSHARABLE_CLASS(CBTInqResultRef) : public CBase
+ {
+public:
+ CBTInqResultRef(CBTInqResultRef& aRef);
+ CBTInqResultRef(CBTInqResultRecord& aRec);
+ ~CBTInqResultRef();
+ CBTInqResultRecord& Result() const;
+
+private:
+ // The pointer to actual CBTInqResultRecord
+ CBTInqResultRecord& iRecord;
+public:
+ // List to go on a view, in CBTInqResultSet
+ TDblQueLink iLink;
+ };
+
+/**
+ BT Inquiry Result Set.
+ A view onto a set of the current inquiry results.
+**/
+NONSHARABLE_CLASS(CBTInqResultSet) : public CBase
+ {
+public:
+ CBTInqResultSet();
+ ~CBTInqResultSet();
+ void Reset();
+ CBTInqResultRef* Add(CBTInqResultRecord& aRec);
+ CBTInqResultRef* FindEntry(const TBTDevAddr& aAddr);
+ CBTInqResultRef* NextResult();
+ CBTInqResultRef* CurrentResult();
+ void ReturnToFirstResult();
+ TBool IsEmpty();
+ void MoveToback(CBTInqResultRef& aRef);
+private:
+ typedef TDblQue<CBTInqResultRef> TResultRefQue;
+ typedef TDblQueIter<CBTInqResultRef> TResultQueIter;
+ TResultRefQue iResultRefs;
+ TResultQueIter iNextRefIter;
+ CBTInqResultRef* iCurrentResult;
+ };
+
+NONSHARABLE_STRUCT(TInquiryCacheAge)
+ {
+public:
+ TUint iIAC;
+ TInt iCacheAge;
+ };
+
+/**
+ BT Host resolver.
+ Represents one client host resolver session.
+ Only implements GetByAddress, as this is all the
+ BT API supports.
+**/
+NONSHARABLE_CLASS(CBTHostResolver) : public CHostResolvProvdBase
+ {
+public:
+ enum TInquiryStatus
+ {
+ EInquiryReady,
+ EInquiring,
+ EInquiryComplete
+ };
+ enum TNameLookupMode
+ {
+ EDontGetNames,
+ EDoGetNames
+ };
+
+ enum TRequestState
+ {
+ EIdle,
+ EInquiry,
+ ENameLookup,
+ ESetLocalName,
+ EGetLocalName,
+ EError // LC added
+ };
+
+ CBTHostResolver(CBTInquiryMgr& aInquiryMgr);
+ ~CBTHostResolver();
+ // From CHostResolvProvdBase
+ void GetByName(TNameRecord& aName);
+ void GetByAddress(TNameRecord& aName);
+ void SetHostName(TDes& aNameBuf);
+ void GetHostName(TDes& aNameBuf);
+// Need this to allow instantiation. Doesn't seem to be callable though!
+// Simply stub it, as we don't actually care...
+ virtual TInt SetOption(TUint aLevel, TUint aName, const TDesC8& aOption);
+
+ // From CResolverProvdBase
+ void CancelCurrentOperation();
+
+ // IquiryMgr interface
+ void InquiryResult(CBTInqResultRecord& aResult);
+ void NameLookupResult(TInt aErr, const TBTDevAddr& aAddr, const TDesC8& aName);
+ void InquiryComplete(TInt aErr);
+ void SetLocalNameComplete(TInt aErr);
+ void GetLocalNameComplete(TInt aErr, const TDesC8& aName);
+
+ TUint GetIAC() const;
+ inline static TInt LinkOffset() {return _FOFF(CBTHostResolver, iLink);}
+
+ //From CResolverProvdBase
+ TInt SecurityCheck(MProvdSecurityChecker *aSecurityChecker);
+private:
+ void TryToCompleteRequest();
+ void CompleteRequest(TInt aErr);
+ void CompleteCurrentOperation();
+
+ CBTInquiryMgr& iInquiryMgr;
+ // The record we're currently retreiving
+ TNameRecord* iNameRecord;
+ // the buffer we get host name into
+ TDes* iHostNameBuf;
+
+ // Current user request.
+ TRequestState iRequestState;
+ // Status of the on-going inquiry process
+ TInquiryStatus iInquiryStatus;
+ // Get names or not?
+ TNameLookupMode iNameLookupMode;
+ // Error code... Only valid when iInquiryStatus == EInquiryComplete
+ TInt iInqCompletionCode;
+ // Set of devices found, to be returned to client
+ CBTInqResultSet iResults;
+ // Member of Q in InquiryMgr.
+ TDblQueLink iLink;
+ //Mixin providing security checking, This is not an owned variable.
+ MProvdSecurityChecker* iSecurityChecker;
+ };
+
+#ifdef CONNECTION_PREEMPTS_INQUIRY
+class CConnectingStatusSubscriber;
+#endif
+
+/**
+ BT Inquiry Manager.
+ Singleton object that manages host resolvers, inquiries, and
+ name lookups.
+**/
+NONSHARABLE_CLASS(CBTInquiryMgr) : public CBase, public MHCICommandQueueClient
+ {
+public:
+ // Interface for CL2CAPProtocol
+ ~CBTInquiryMgr();
+ static CBTInquiryMgr* NewL(CLinkMgrProtocol& aProtocol);
+ CBTHostResolver* NewHostResolverL();
+
+ void SetHCICommandQueue(MHCICommandQueue& aCommandQueue);
+ void ClearHCICommandQueue();
+
+ void ClockOffsetResult(const TBTDevAddr& aAddr, TBasebandTime aClockOffset);
+ void CoDResult(const TBTDevAddr& aConn, TUint aCoD);
+
+ void SetLocalNameComplete(TInt aErr);
+ void GetLocalNameComplete(TInt aErr, const TDesC8& aName);
+ void Suspend();
+ void Resume();
+ void SetInquiryMode();
+
+
+#ifdef _DEBUG
+ void IncrementHRCount() {++iNumHRs;};
+ void DecrementHRCount() {--iNumHRs;};
+#endif
+
+ // Interface for CBTHostResolver
+ void StartInquiry(CBTHostResolver& aResolver, TUint aIAC, TBool aIgnoreCache);
+ void LookupName(CBTHostResolver& aResolver, const TBTDevAddr& aAddr, TBool aIgnoreCache, TBool aExplicitNameRequest);
+ void ClearCache();
+ TInt SetLocalName(const TDesC8& aName);
+ TInt GetLocalName();
+ CBTInqResultRef* FindExistingCacheEntry(const TBTDevAddr& aAddr);
+ CBTInqResultRef* AddEntryToCache(const TBTDevAddr& aAddr);
+ CBTInqResultRef* AddEntryWithJuiceToCache(const TInquiryLogEntry& aEntry);
+ CBTInqResultRef* AddEntryWithCoDToCache(const TBTDevAddr& aAddr, const TUint aCoD);
+ CBTInqResultRef* AddEntryWithClockOffsetToCache(const TBTDevAddr& aAddr, const TBasebandTime aClockOffset);
+ const TDesC8* DeviceNameFromCache(const TBTDevAddr& aAddr);
+ CBTInqResultRecord* BasebandParametersFromCache(const TBTDevAddr& aAddr);
+ void DeletingHostResolver();
+
+ enum THWState
+ {
+ EIdle = 0,
+ EInquiry,
+ ENameLookup,
+ EConnecting, // can't do anything really!
+// EConnected // can't do anything ?
+ EOff,
+ ECancellingForNewIAC,
+ };
+
+ THWState HWState(){ return iHWState; }
+ void SetHWState(THWState aState);
+ void PublishStatus();
+
+ void CompleteCommands(TInt aErr);
+ TBool IsExtendedInquiryResponseSupported();
+
+ // commands sent to the controller -- called from external classes
+ void ReadRemoteNameL(const TBTDevAddr& aAddr);
+
+private: // Handling logical inquiry events
+ void WriteInquiryModeComplete(TBool aSucceeded);
+ void InquiryResult(TInt aErr,const TInquiryLogEntry& aEntry);
+ void InquiryComplete(TInt aErr, TUint8 aNumResponses);
+ void RemoteNameResult(TInt aErr, const TBTDevAddr& aAddr, const TBTDeviceName8& aBuf);
+ void RemoteHostSupportedFeatures(TInt aErr, const TBTDevAddr& aAddr, const TUint64& aHostSupportedFeatures);
+
+private: // from MHCICommandQueueClient
+ virtual void MhcqcCommandEventReceived(const THCIEventBase& aEvent, const CHCICommandBase* aRelatedCommand);
+ virtual void MhcqcCommandErrored(TInt aErrorCode, const CHCICommandBase* aCommand);
+
+private: // HCI event handling functions
+ // basic types
+ void CommandCompleteEvent(const THCIEventBase& aEvent);
+ void CommandStatusEvent(const THCIEventBase& aEvent, const CHCICommandBase& aCommand);
+
+ // first class events
+ void InquiryResultEvent(const THCIEventBase& aEvent);
+ void InquiryResultWithRSSIEvent(const THCIEventBase& aEvent);
+ void ExtendedInquiryResultEvent(const THCIEventBase& aEvent);
+ void InquiryCompleteEvent(const THCIEventBase& aEvent);
+ void RemoteNameReqCompleteEvent(const THCIEventBase& aEvent);
+ void RemoteHostSupportedFeaturesNotificationEvent(const THCIEventBase& aEvent);
+
+ // command complete events
+ void WriteInquiryModeOpcode(THCIErrorCode aHciErr, const THCIEventBase& aEvent);
+ void ReadLocalNameOpcode(THCIErrorCode aHciErr, const THCIEventBase& aEvent);
+ void InquiryCancelOpcode(THCIErrorCode aHciErr, const THCIEventBase& aEvent);
+
+private:
+ CBTInquiryMgr(CLinkMgrProtocol& aProtocol);
+ void ConstructL();
+
+ MHCICommandQueue& CommandQueue() const;
+
+ // commands sent to the controller
+ void CancelInquiryL();
+ void CancelRemoteNameL(const TBTDevAddr& aAddr);
+ void StartInquiryL(TUint aIAC, TUint8 aLength, TUint8 aNumResponses);
+ void WriteInquiryModeL(TUint8 aInquiryMode);
+ void LookupNameL(const TInquiryLogEntry& aEntry);
+ void ReadLocalNameL();
+
+ void DoInquiry();
+ void DoNameLookup(TBool aInquiryComplete);
+ void HandleRemoteNameResult(TInt aErr, CBTInqResultRef& aRef, const TBTDeviceName8& aBuf);
+ void TryToInterruptInquiryForNameLookup();
+ void UpdateNotifiers(const TBTDevAddr& aAddr, const TDesC8& aName);
+ void ClearCurrentInquiryResults();
+ TInt CancelHardwareInquiry();
+ TInt StartHardwareInquiry();
+
+ static TInt InquiryWatchdog(TAny* aPtr);
+ static TInt Flush(TAny* aPtr);
+ void DoFlush();
+ void EnableFlusher();
+
+ TInt CacheAge(TUint aIAC) const;
+ void SetCacheAge(TUint aIAC, TInt aAge);
+
+private:
+ MHCICommandQueue* iCommandQueue;
+
+ // Singleton owner of us
+ CLinkMgrProtocol& iLinkMgrProtocol;
+
+ // What the hardware is currently up to (as far as we know)
+ THWState iHWState;
+ // IAC of the current inquiry
+ TUint iCurrentInquiryIAC;
+ // IAC of the inquiry that is currently requested by a host resolver, either in progress or about to start
+ TUint iRequestedInquiryIAC;
+ // IAC of the inquiry that has been put on hold while a higher priority IAC is in progress
+ TUint iQueuedInquiryIAC;
+ // Number of times we've interrupted the current inquiry
+ TInt iInquiryInteruptions;
+ // Time since the last inquiry, per IAC
+ RArray<TInquiryCacheAge> iCacheAge;
+ // Timer to age records and the cache itself
+ CPeriodic* iFlusher;
+ // Results since watchdog last went off
+ TInt iResultCount;
+ // Number of watchdogs seeing 0 devices
+ TInt iInquirySilenceCount;
+ // Number of name requests pending
+ TInt iPendingNameRequests;
+ // True is there are new page requests pending
+ TInt iNewPageRequestsPending;
+ // Current name request pagetimeout
+ TUint16 iNamePageTimeout;
+ // Current Inquiry Mode
+ TUint8 iInquiryMode;
+ // Pending Inquiry Mode
+ TUint8 iPendingInquiryMode;
+
+ CBTInqResultSet iCurrentResults;
+ TDblQue<CBTHostResolver> iHRs;
+
+ TBool iReportedInquiryState; // what did we last tell the Inquiry state P&S key
+#ifdef CONNECTION_PREEMPTS_INQUIRY
+ // Monitors if a ACL connection is currently being established.
+ CConnectingStatusSubscriber* iConnectingStatus;
+#endif
+
+#ifdef _DEBUG
+ TInt iNumHRs; // no Count() in que's - handy to have
+#endif
+ };
+
+#ifdef CONNECTION_PREEMPTS_INQUIRY
+// *******************************************************************
+// ACL Connecting status subscriber
+// *******************************************************************
+NONSHARABLE_CLASS(CConnectingStatusSubscriber) : public CActive
+ {
+public:
+ static CConnectingStatusSubscriber* NewL(CBTInquiryMgr& aInquiryMgr);
+ ~CConnectingStatusSubscriber();
+
+private:
+ CConnectingStatusSubscriber(CBTInquiryMgr& aInquiryMgr);
+ void ConstructL();
+ void Subscribe();
+
+ void RunL();
+ void DoCancel();
+
+ CBTInquiryMgr& iParent;
+ RProperty iProperty;
+ };
+#endif // CONNECTION_PREEMPTS_INQUIRY
+
+#endif