--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/l2cap/L2CapFecNegotiator.h Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,314 @@
+// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+
+
+/**
+ @file
+ @internalComponent
+*/
+
+#ifndef L2CAPFECNEGOTIATOR_H
+#define L2CAPFECNEGOTIATOR_H
+
+#include "L2types.h"
+
+class TL2CapFecNegotiator;
+class TL2CapSingleDirectionFecNegotiatorBase;
+
+// This encapsulates channel mode dependent FEC option handling behaviors.
+// Channel mode policy is applied outside of this.
+NONSHARABLE_CLASS(TModeSpecificFecOptionHandlerBase)
+ {
+public:
+ // Checks whether the field values are valid (within specification limits).
+ // To be used early, during the parsing of an option received from the peer.
+ // Note: valid doesn't mean acceptable.
+ virtual TBool IsOptionValid(const TRetransmissionAndFlowControlOption& aFecOption) const = 0;
+ virtual TBool IsPeerResponseAcceptable(const TRetransmissionAndFlowControlOption& aPreferred,
+ const TRetransmissionAndFlowControlOption& aPeer) const = 0;
+ // The return value says whether the option needs to be included in ConfigRsp.
+ // [Only enhanced mode positive responses need to be included as they convey new information
+ // on the timers and MPS]
+ virtual TBool BuildPositiveResponse(TRetransmissionAndFlowControlOption& aPreferred,
+ const TRetransmissionAndFlowControlOption& aPeer) const;
+ virtual void BuildNegativeResponse(TRetransmissionAndFlowControlOption& aPreferred,
+ const TRetransmissionAndFlowControlOption& aPeer) const;
+ // In general configuration procedure (spec chapter 7 General Procedures) if the remote accepts
+ // an option from our ConfigReq, it doesn't have to include it in the response. So before
+ // processing the options from a ConfigRsp we've received, we go through the preferred values
+ // we've sent in ConfigReq and pretend that the remote has accepted them without a hitch. Then
+ // options included in the received ConfigRsp are processed. This works well with plain-vanilla
+ // negotiated options, but TRetransmissionAndFlowControl for enhanced modes is different:
+ // request and response semantics are a bit different, and so the request does not contain all
+ // information needed in a response. So we have to take the request we've sent, guess the
+ // missing information, and thus create a fake response. And that's what this method does.
+ virtual void PrepareImplicitPeerResponse(TRetransmissionAndFlowControlOption& aImplicitResponse,
+ const TRetransmissionAndFlowControlOption& aPreferred) const;
+
+ // Set user-requested MaxTransmit value. The value is given in the enhanced range
+ // 0-255, where 0 means infinity and is only valid for ERTM. Deriving classes are
+ // responsible for the cut-off of the infinity value on 255 if they can't handle it.
+ virtual void SetMaxTransmit(TRetransmissionAndFlowControlOption& aFecOption, TUint8 aMaxTransmit) const;
+
+ virtual void ZeroUnspecifiedRequestFields(TRetransmissionAndFlowControlOption& aFecOption) const;
+ virtual void ZeroUnspecifiedResponseFields(TRetransmissionAndFlowControlOption& aFecOption) const;
+ };
+
+NONSHARABLE_CLASS(TStreamingFecHandler) : public TModeSpecificFecOptionHandlerBase
+ {
+public:
+ virtual TBool IsOptionValid(const TRetransmissionAndFlowControlOption& aFecOption) const;
+ virtual TBool IsPeerResponseAcceptable(const TRetransmissionAndFlowControlOption& aPreferred,
+ const TRetransmissionAndFlowControlOption& aPeer) const;
+ virtual TBool BuildPositiveResponse(TRetransmissionAndFlowControlOption& aPreferred,
+ const TRetransmissionAndFlowControlOption& aPeer) const;
+ virtual void BuildNegativeResponse(TRetransmissionAndFlowControlOption& aPreferred,
+ const TRetransmissionAndFlowControlOption& aPeer) const;
+ virtual void ZeroUnspecifiedRequestFields(TRetransmissionAndFlowControlOption& aFecOption) const;
+ virtual void ZeroUnspecifiedResponseFields(TRetransmissionAndFlowControlOption& aFecOption) const;
+ };
+
+NONSHARABLE_CLASS(TErtmFecHandler) : public TModeSpecificFecOptionHandlerBase
+ {
+public:
+ virtual TBool IsOptionValid(const TRetransmissionAndFlowControlOption& aFecOption) const;
+ virtual TBool IsPeerResponseAcceptable(const TRetransmissionAndFlowControlOption& aPreferred,
+ const TRetransmissionAndFlowControlOption& aPeer) const;
+ virtual TBool BuildPositiveResponse(TRetransmissionAndFlowControlOption& aPreferred,
+ const TRetransmissionAndFlowControlOption& aPeer) const;
+ virtual void BuildNegativeResponse(TRetransmissionAndFlowControlOption& aPreferred,
+ const TRetransmissionAndFlowControlOption& aPeer) const;
+ virtual void PrepareImplicitPeerResponse(TRetransmissionAndFlowControlOption& aImplicitResponse,
+ const TRetransmissionAndFlowControlOption& aPreferred) const;
+ virtual void SetMaxTransmit(TRetransmissionAndFlowControlOption& aFecOption, TUint8 aMaxTransmit) const;
+ virtual void ZeroUnspecifiedRequestFields(TRetransmissionAndFlowControlOption& aFecOption) const;
+ virtual void ZeroUnspecifiedResponseFields(TRetransmissionAndFlowControlOption& aFecOption) const;
+ };
+
+NONSHARABLE_CLASS(TLegacyFecHandler) : public TModeSpecificFecOptionHandlerBase
+ {
+public:
+ virtual TBool IsOptionValid(const TRetransmissionAndFlowControlOption& aFecOption) const;
+ virtual TBool IsPeerResponseAcceptable(const TRetransmissionAndFlowControlOption& aPreferred,
+ const TRetransmissionAndFlowControlOption& aPeer) const;
+ virtual void SetMaxTransmit(TRetransmissionAndFlowControlOption& aFecOption, TUint8 aMaxTransmit) const;
+ };
+
+NONSHARABLE_CLASS(TBasicFecHandler) : public TModeSpecificFecOptionHandlerBase
+ {
+public:
+ // Most peers will actually only request Basic implicitly i.e. by not including the FEC
+ // option at all, but we treat implicit/explicit values uniformly and will still execute
+ // these. And a Basic FEC can be explicit if the peer does new modes, but for some
+ // reason doesn't want to use them and has sent us an Unacceptable Params ConfigRsp with
+ // Basic in it.
+ virtual TBool IsOptionValid(const TRetransmissionAndFlowControlOption& aFecOption) const;
+ virtual TBool IsPeerResponseAcceptable(const TRetransmissionAndFlowControlOption& aPreferred,
+ const TRetransmissionAndFlowControlOption& aPeer) const;
+ };
+
+// This groups all mode-specific handlers and provides delegator methods that forward calls to
+// appropriate FecHandlers.
+NONSHARABLE_CLASS(TFecOptionHandlerDelegator)
+ {
+public:
+ inline TBool IsOptionValid(const TRetransmissionAndFlowControlOption& aFecOption) const;
+ inline TBool IsPeerResponseAcceptable(const TRetransmissionAndFlowControlOption& aPreferred,
+ const TRetransmissionAndFlowControlOption& aPeer) const;
+ inline TBool BuildPositiveResponse(TRetransmissionAndFlowControlOption& aPreferred,
+ const TRetransmissionAndFlowControlOption& aPeer) const;
+ inline void BuildNegativeResponse(TRetransmissionAndFlowControlOption& aPreferred,
+ const TRetransmissionAndFlowControlOption& aPeer) const;
+ inline void PrepareImplicitPeerResponse(TRetransmissionAndFlowControlOption& aImplicitResponse,
+ const TRetransmissionAndFlowControlOption& aPreferred) const;
+ inline void SetMaxTransmit(TRetransmissionAndFlowControlOption& aFecOption, TUint8 aMaxTransmit) const;
+ inline void ZeroUnspecifiedRequestFields(TRetransmissionAndFlowControlOption& aFecOption) const;
+ inline void ZeroUnspecifiedResponseFields(TRetransmissionAndFlowControlOption& aFecOption) const;
+private:
+ TModeSpecificFecOptionHandlerBase& Handler(const TRetransmissionAndFlowControlOption& aFecOption);
+ const TModeSpecificFecOptionHandlerBase& Handler(const TRetransmissionAndFlowControlOption& aFecOption) const;
+
+ TModeSpecificFecOptionHandlerBase* ModeToHandler(TL2CapChannelMode aMode);
+ const TModeSpecificFecOptionHandlerBase* ModeToHandler(TL2CapChannelMode aMode) const;
+
+#ifdef __FLOG_ACTIVE
+ void LogCurrentValues(const TRetransmissionAndFlowControlOption& aPreferred,
+ const TRetransmissionAndFlowControlOption& aPeer) const;
+#endif
+private:
+ TStreamingFecHandler iStreamingFecHandler;
+ TErtmFecHandler iErtmFecHandler;
+ TLegacyFecHandler iLegacyFecHandler;
+ TBasicFecHandler iBasicFecHandler;
+ };
+
+NONSHARABLE_CLASS(TL2CapSingleDirectionFecNegotiatorBase) : public TL2CapConfigurationOptionGroupBase
+{
+public:
+ inline TL2CapSingleDirectionFecNegotiatorBase(const TL2CapFecNegotiator& aFecNegotiator);
+
+ inline void SetPeer(const TRetransmissionAndFlowControlOption& aFecOption);
+ inline void SetPreferred(const TRetransmissionAndFlowControlOption& aFecOption);
+
+ void SetupForRenegotiation();
+
+ inline TOptionConfigStatus ConfigOptionStatus() const;
+
+ inline const TRetransmissionAndFlowControlOption& Peer() const;
+ inline const TRetransmissionAndFlowControlOption& Preferred() const;
+
+
+protected:
+ TBool IsPeerModeAcceptable(TL2CapChannelMode aPeerMode, TBool& aDisconnect) const;
+
+#ifdef __FLOG_ACTIVE
+ void LogState() const;
+#endif
+
+protected:
+ const TL2CapFecNegotiator& iFecNegotiator;
+
+ TOptionConfigStatus iConfigStatus;
+ TRetransmissionAndFlowControlOption iPeer;
+ TRetransmissionAndFlowControlOption iPreferred;
+ };
+
+NONSHARABLE_CLASS(TL2CapIncomingFecNegotiator) : public TL2CapSingleDirectionFecNegotiatorBase
+ {
+public:
+ inline TL2CapIncomingFecNegotiator(const TL2CapFecNegotiator& aFecNegotiator);
+ void ProcessPeerValue(const TRetransmissionAndFlowControlOption& aFecOption,
+ TBool aIsUnacceptableParameters);
+ void ProcessImplicitPeerValue();
+ void Setup();
+protected:
+ void BuildRequest(TL2CapChannelMode aMode, TRetransmissionAndFlowControlOption& aFecOption);
+ };
+
+NONSHARABLE_CLASS(TL2CapOutgoingFecNegotiator) : public TL2CapSingleDirectionFecNegotiatorBase
+ {
+public:
+ inline TL2CapOutgoingFecNegotiator(const TL2CapFecNegotiator& aFecNegotiator);
+ TInt ProcessPeerValue(const TRetransmissionAndFlowControlOption& aFecOption);
+ void Setup();
+ inline TBool NeedToIncludeInPositiveConfigResponse();
+ inline void SetIncludeInPositiveConfigResponse(TBool aVal);
+private:
+ TBool iIncludeValueInPositiveConfigResponse;
+ };
+
+// This is the interface to the FEC option negotiation functionality, through which
+// all interaction with the external world should be done.
+NONSHARABLE_CLASS(TL2CapFecNegotiator)
+ {
+public:
+ // Variants of the negotiation procedure defined in 2.1 Core Spec Addendum 1,
+ // chapter 5.4 Retransmission And Flow Control Option.
+ enum TNegotiationBehavior
+ {
+ // Allows all spec-allowed fallback options: Streaming -> ERTM, ERTM -> Basic and
+ // Streaming -> Basic. E.g. if our preferred mode is ERTM and peer proposes Basic,
+ // we'll fall back to it. The negotiation procedure is a simple minimization
+ // algorithm, where the party with the higher-precedence mode wins.
+ // Also note that we try to apply the same hierarchy to RTM and FC, so effectively
+ // you can read this as Unreliable -> Reliable, Reliable -> Basic and Unreliable -> Basic,
+ // where Reliable = { ERTM, RTM } and Unreliable = { Streaming, FC }
+ // For the precedence of modes, see channel mode <= operator or the spec, same section.
+ EState1,
+ // Like State1, only Unreliable -> Reliable is not allowed (Unreliable -> Basic and
+ // Reliable -> Basic still are).
+ EState1NoUnreliableToReliable,
+ // No fallback - disconnect immediately if peer proposes a different channel mode than
+ // we want.
+ EState2
+ };
+
+public:
+ inline TL2CapFecNegotiator();
+
+ TBool Setup(TL2CapConfig::TChannelReliability aChannelReliability,
+ TBool aLegacyModesDisallowed,
+ const TL2CapEntityInfo& aPeerEntityConfig,
+ TUint8 aMaxTransmit);
+
+ // Can't renegotiate FEC currently but with Generic AMP time-outs will be renegotiable.
+ void SetupForRenegotiation();
+
+ // Methods below implement events in option state machine - they're identical
+ // to the ones in the generic state machine in TL2CapConfigurationOptionGroup.
+ inline TInt PeerRequestsOption(const TRetransmissionAndFlowControlOption& aFecOption);
+ inline TInt PeerRequestsLastAcceptedValue();
+
+ inline TInt PeerRejectsOption(const TRetransmissionAndFlowControlOption& aFecOption);
+ inline TInt PeerAcceptsOption(const TRetransmissionAndFlowControlOption& aFecOption);
+ inline void PeerAcceptsOption();
+
+ inline TBool NeedToIncludeInPositiveConfigResponse();
+
+ void DowngradeIncomingToBasicIfOutgoingIsBasic();
+ TInt CheckNegotiatedChannelMode(TBool& aDowngrade);
+
+ // [Methods below add a lot of fluff but they provide strong decoupling and encapsulation.
+ // None of the internal classes are exposed.]
+
+ inline const TRetransmissionAndFlowControlOption& IncomingPreferred() const;
+ inline const TRetransmissionAndFlowControlOption& OutgoingPreferred() const;
+
+ inline TL2CapConfigurationOptionGroupBase::TOptionConfigStatus IncomingConfigOptionStatus() const;
+ inline TL2CapConfigurationOptionGroupBase::TOptionConfigStatus OutgoingConfigOptionStatus() const;
+
+ inline TL2CapDataControllerConfig DataControllerConfig() const;
+
+ // These abstract away the fact that some parameters are negotiated in opposite paths depending
+ // on the modes used (eg Monitor TO), and which fields the values should be taken from (Peer or
+ // Preferred).
+ inline TL2CapChannelMode OutgoingLinkMode() const;
+ inline TL2CapChannelMode IncomingLinkMode() const;
+ inline TUint8 OutgoingLinkModeAsUnsignedByte() const;
+ inline TUint8 IncomingLinkModeAsUnsignedByte() const;
+ inline TUint8 OutgoingTxWindowSize() const;
+ inline TUint8 IncomingTxWindowSize() const;
+ inline TUint8 OutgoingMaxTransmit() const;
+ inline TUint8 IncomingMaxTransmit() const;
+ inline TUint16 OutgoingRetransmissionTimeout() const;
+ inline TUint16 IncomingRetransmissionTimeout() const;
+ inline TUint16 OutgoingMonitorTimeout() const;
+ inline TUint16 IncomingMonitorTimeout() const;
+ inline TUint16 OutgoingMaximumPDUSize() const;
+ inline TUint16 IncomingMaximumPDUSize() const;
+
+ // These are for the internal per-direction negotiator objects.
+ TBool IsModeLegal(TL2CapChannelMode aPeerMode) const;
+ inline const TL2CapEntityInfo& PeerSupportedModes() const;
+ inline TNegotiationBehavior NegotiationBehavior() const;
+ inline TL2CapChannelMode DesiredMode() const;
+ inline TUint8 MaxTransmit() const;
+ inline const TFecOptionHandlerDelegator& ModeSpecificHandlers() const;
+private:
+ TL2CapIncomingFecNegotiator iIncomingNegotiator;
+ TL2CapOutgoingFecNegotiator iOutgoingNegotiator;
+
+ TL2CapEntityInfo iPeerSupportedModes;
+ TNegotiationBehavior iNegotiationBehavior;
+ TL2CapChannelMode iDesiredMode;
+ TUint8 iMaxTransmit;
+
+ TFecOptionHandlerDelegator iModeSpecificHandlers;
+ };
+
+#include "L2CapFecNegotiator.inl"
+
+#endif /*L2CAPFECNEGOTIATOR_H*/