diff -r 000000000000 -r 29b1cd4cb562 bluetooth/btstack/l2cap/L2CapFecNegotiator.h --- /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*/