bluetooth/btstack/l2cap/L2CapFecNegotiator.h
changeset 0 29b1cd4cb562
child 10 8a27654f7b62
--- /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*/