bluetooth/btstack/l2cap/L2CapChannelConfig.cpp
changeset 0 29b1cd4cb562
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Manages the negotiation of L2Cap configuration parameters.
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <bluetooth/logger.h>
       
    19 #include <es_prot.h>
       
    20 #include "l2util.h"
       
    21 #include "L2CapChannelConfig.h"
       
    22 #include "l2capEntityConfig.h"
       
    23 #include "l2capSigPacketConfigure.h"
       
    24 
       
    25 #ifndef __UNITTest__
       
    26     #include "l2constants.h"
       
    27 	#include "l2capSAPSignalHandler.h"
       
    28 #else
       
    29 	#include "cl2capconfigproxy.h"
       
    30 	#ifdef _DEBUG
       
    31 	#include "l2capDebugControlInterface.h"
       
    32 	#endif
       
    33 #endif
       
    34 
       
    35 #ifdef __FLOG_ACTIVE
       
    36 _LIT8(KLogComponent, LOG_COMPONENT_L2CAP);
       
    37 #endif
       
    38 
       
    39 
       
    40 // A helper for the implementation of a workaround for a bug in the negotiation algorithm
       
    41 // of some remotes.
       
    42 NONSHARABLE_STRUCT(SL2CapChannelIncomingConfigOptionSnapshot)
       
    43     {
       
    44     SL2CapChannelIncomingConfigOptionSnapshot(const CL2CapChannelConfig& aChannelConfig);
       
    45     TBool operator==(const SL2CapChannelIncomingConfigOptionSnapshot& aThat);
       
    46 
       
    47     TMTUOption                          iMtu;
       
    48     TL2CapConfigurationOptionGroupBase::TOptionConfigStatus iMtuStatus;
       
    49 
       
    50     TFlushTimeoutDurationOption         iFlushTimeout;
       
    51     TL2CapConfigurationOptionGroupBase::TOptionConfigStatus iFlushTimeoutStatus;
       
    52 
       
    53     TRetransmissionAndFlowControlOption iFec;
       
    54     TL2CapConfigurationOptionGroupBase::TOptionConfigStatus iFecStatus;
       
    55 
       
    56     TQualityOfServiceOption             iQos;
       
    57     TL2CapConfigurationOptionGroupBase::TOptionConfigStatus iQosStatus;
       
    58     };
       
    59 
       
    60 
       
    61 /*static*/ CL2CapChannelConfig* CL2CapChannelConfig::NewL(CL2CapSAPSignalHandler& aSAPSignalHandler)
       
    62 	{
       
    63 	LOG_STATIC_FUNC
       
    64 	CL2CapChannelConfig* self = new(ELeave) CL2CapChannelConfig(aSAPSignalHandler);
       
    65 	CleanupStack::PushL(self);
       
    66 	self->ConstructL();
       
    67 	CleanupStack::Pop();
       
    68 	return self;
       
    69 	}
       
    70 
       
    71 CL2CapChannelConfig::~CL2CapChannelConfig()
       
    72 	{
       
    73 	LOG_FUNC
       
    74 	delete iIncomingMTU;
       
    75 	delete iOutgoingMTU;
       
    76 	delete iIncomingFlushTimeoutDuration;
       
    77 	delete iOutgoingFlushTimeoutDuration;
       
    78 	delete iIncomingQOS;
       
    79 	delete iOutgoingQOS;
       
    80 	}
       
    81 	
       
    82 void CL2CapChannelConfig::ConstructL()
       
    83 	{
       
    84 	LOG_FUNC
       
    85 
       
    86 	// Initialise the configuration options.
       
    87 	iIncomingMTU = new (ELeave)TL2CapConfigurationOptionGroup<TMTUOption>
       
    88 	           (TMTUOption::EPreferredValue,
       
    89 				TMTUOption::EAbsoluteMinimumValue,
       
    90 				TMTUOption::EPreferredValue,
       
    91 				TMTUOption::ESpecDefaultValue,
       
    92 				TL2CapConfigurationOptionGroupBase::ENegotiateToMinimum);
       
    93 	iOutgoingMTU = new (ELeave)TL2CapConfigurationOptionGroup<TMTUOption>
       
    94 	           (TMTUOption::EMaximumValue,
       
    95 				TMTUOption::ESpecMinimumValue,
       
    96 			    TMTUOption::EPreferredValue,
       
    97 			    TMTUOption::ESpecDefaultValue,
       
    98 				TL2CapConfigurationOptionGroupBase::ENegotiateToMinimum);
       
    99 
       
   100 	// Flush timeout is settable in the SAP but not implemented so we're not looking at the SAP value.
       
   101 	iIncomingFlushTimeoutDuration = new (ELeave)TL2CapConfigurationOptionGroup<TFlushTimeoutDurationOption>
       
   102 	           (TFlushTimeoutDurationOption::EMaximumValue,
       
   103 			    TFlushTimeoutDurationOption::ESpecMinimumValue,
       
   104 	            TFlushTimeoutDurationOption::ESpecDefaultValue,
       
   105 	            TFlushTimeoutDurationOption::ESpecDefaultValue,
       
   106 				TL2CapConfigurationOptionGroupBase::ENegotiated);
       
   107 	iOutgoingFlushTimeoutDuration = new (ELeave)TL2CapConfigurationOptionGroup<TFlushTimeoutDurationOption>
       
   108                (TFlushTimeoutDurationOption::EMaximumValue,
       
   109 				TFlushTimeoutDurationOption::EMaximumValue,
       
   110 				TFlushTimeoutDurationOption::ESpecDefaultValue,
       
   111 				TFlushTimeoutDurationOption::ESpecDefaultValue,
       
   112 				TL2CapConfigurationOptionGroupBase::ENegotiated);
       
   113 
       
   114 	// QOS isn't implemented nor settable in the SAP.
       
   115 	iIncomingQOS = new (ELeave)TL2CapConfigurationOptionGroup<TQualityOfServiceOption>
       
   116 	           (TQualityOfServiceOption::EMaximumValue,
       
   117 				TQualityOfServiceOption::ESpecMinimumValue,
       
   118 				TQualityOfServiceOption::ESpecDefaultValue,
       
   119 				TQualityOfServiceOption::ESpecDefaultValue,
       
   120 				TL2CapConfigurationOptionGroupBase::ENegotiated);
       
   121 	iOutgoingQOS = new (ELeave)TL2CapConfigurationOptionGroup<TQualityOfServiceOption>
       
   122 	           (TQualityOfServiceOption::EMaximumValue,
       
   123 				TQualityOfServiceOption::ESpecMinimumValue,
       
   124 				TQualityOfServiceOption::ESpecDefaultValue,
       
   125 				TQualityOfServiceOption::ESpecDefaultValue,
       
   126 				TL2CapConfigurationOptionGroupBase::ENegotiated);
       
   127 
       
   128 	iRequestedChannelReliability		= TL2CapConfig::EReliableChannel;
       
   129 	iLegacyModesDisallowed				= EFalse;
       
   130 	iRequestedFlushTimeout				= TL2CapConfig::EDefaultDataObsolescenceTimeout;
       
   131 	iRequestedRetransmissionTimeout		= TL2CapConfig::EDefaultRetransmission;
       
   132 
       
   133 	LOG2(_L("CL2CapChannelConfig.iFecNegotiator = %X.%X"), (TAny*)this, (TAny*)&iFecNegotiator)
       
   134 	}
       
   135 
       
   136 
       
   137 #ifndef __UNITTest__
       
   138 CL2CapChannelConfig::CL2CapChannelConfig(CL2CapSAPSignalHandler& aSAPSignalHandler)
       
   139  : iSAPSignalHandler(aSAPSignalHandler)
       
   140 #else
       
   141 CL2CapChannelConfig::CL2CapChannelConfig(CL2CapConfigProxy& aSAPSignalHandler)
       
   142  : iSAPSignalHandler(aSAPSignalHandler)
       
   143 #endif	
       
   144 	{
       
   145 	LOG_FUNC
       
   146 	}
       
   147 
       
   148 void CL2CapChannelConfig::CloneChannelConfig(const CL2CapChannelConfig& aCopy)
       
   149 	{
       
   150 	LOG_FUNC
       
   151 
       
   152 	// Copy all aspects of this class that should be cloned from the listening SAP.
       
   153 	*iIncomingMTU 	= *(aCopy.iIncomingMTU);
       
   154 	*iOutgoingMTU 	= *(aCopy.iOutgoingMTU);
       
   155 	*iIncomingFlushTimeoutDuration 	= *(aCopy.iIncomingFlushTimeoutDuration);
       
   156 	*iOutgoingFlushTimeoutDuration 	= *(aCopy.iOutgoingFlushTimeoutDuration);
       
   157 	*iOutgoingQOS 	= *(aCopy.iOutgoingQOS);
       
   158 	*iIncomingQOS 	= *(aCopy.iIncomingQOS);
       
   159 	
       
   160 	iRequestedChannelReliability	= aCopy.iRequestedChannelReliability;
       
   161 	iLegacyModesDisallowed			= aCopy.iLegacyModesDisallowed;
       
   162 	iRequestedFlushTimeout			= aCopy.iRequestedFlushTimeout;
       
   163 	iRequestedRetransmissionTimeout	= aCopy.iRequestedRetransmissionTimeout;
       
   164 	// iFecNegotiator gets updated using the iRequested... field values on OpenChannelRequest. 
       
   165 	}
       
   166 
       
   167 
       
   168 TInt CL2CapChannelConfig::HandleConfigRequest(HConfigureRequest& aConfigRequest, RMBufChain& aUnknownOptions)
       
   169 	{
       
   170 	LOG_FUNC
       
   171 	// Pile these options on top of the previously received ones in case it's
       
   172 	// a continuation packet. They're all processed once we've received the
       
   173 	// whole transaction, in ConfigRequestComplete().
       
   174 	return aConfigRequest.ParseOptions(iReceivedConfigRequestOptions, aUnknownOptions);
       
   175 	}
       
   176 
       
   177 TInt CL2CapChannelConfig::HandleConfigResponse(HConfigureResponse& aConfigResponse, RMBufChain& aUnknownOptions)
       
   178 	{
       
   179 	LOG_FUNC
       
   180     // Note: If it's a positive response (Success), then any parameters not specified by
       
   181     // the peer are assumed to be as requested.
       
   182     // If it's negative then it only includes suggested values for rejected parameters
       
   183     // and the ones not rejected will have to be re-requested in following message exchanges.
       
   184 
       
   185     TL2CapConfigParamOptions options;
       
   186     TInt err = aConfigResponse.ParseOptions(options, aUnknownOptions);
       
   187     if (err)
       
   188         {
       
   189         return err;
       
   190         }
       
   191 
       
   192     const TBool isUnacceptableParameters = (aConfigResponse.Results() == EConfigUnacceptableParams);
       
   193     const TBool isSuccess = (aConfigResponse.Results() == EConfigSuccess);
       
   194 
       
   195     // Prelude to the negotiation problem described at the bottom:
       
   196     // snapshot current option status for comparison after the message is processed.
       
   197     SL2CapChannelIncomingConfigOptionSnapshot optionStatusBeforeProcessing(*this);
       
   198     
       
   199     // MTU
       
   200     if (options.IsMtuSet())
       
   201         {
       
   202         if (isUnacceptableParameters)
       
   203             {
       
   204             iIncomingMTU->PeerRejectsOption(options.Mtu());
       
   205             }
       
   206         else
       
   207             {
       
   208             iIncomingMTU->PeerAcceptsOption(options.Mtu());
       
   209             }
       
   210         }
       
   211     else if (isSuccess)
       
   212         {
       
   213         // A positive response acknowledges all options - if one is not
       
   214         // included then it means that the peer agrees with our proposal
       
   215         // (or the default, or the last accepted value).
       
   216         iIncomingMTU->PeerAcceptsOption();
       
   217         }
       
   218     // [else]: if an option is not explicitly mentioned and it's not
       
   219     // a positive response, then the option's status remains untouched.
       
   220 
       
   221     // Flush Timeout Duration
       
   222     if (options.IsFlushTimeoutSet())
       
   223         {
       
   224         if (isUnacceptableParameters)
       
   225             {
       
   226             iOutgoingFlushTimeoutDuration->PeerRejectsOption(options.FlushTimeout());
       
   227             }
       
   228         else
       
   229             {
       
   230             // Note: we're ignoring the explicitly set value as it can only
       
   231             // be what we sent, otherwise it's a broken/malicious peer and we don't
       
   232             // want to use the value.
       
   233             iOutgoingFlushTimeoutDuration->PeerAcceptsOption();
       
   234             }
       
   235         }
       
   236     else if (isSuccess)
       
   237         {
       
   238         iOutgoingFlushTimeoutDuration->PeerAcceptsOption();
       
   239         }
       
   240 
       
   241     // Quality Of Service
       
   242     if (options.IsQosSet())
       
   243         {
       
   244         if (isUnacceptableParameters)
       
   245             {
       
   246             iOutgoingQOS->PeerRejectsOption(options.Qos());
       
   247             }
       
   248         else
       
   249             {
       
   250             iOutgoingQOS->PeerAcceptsOption(options.Qos());
       
   251             }
       
   252         }
       
   253     else if (isSuccess)
       
   254         {
       
   255         iOutgoingQOS->PeerAcceptsOption();
       
   256         }
       
   257 
       
   258     // Retransmission And Flow Control
       
   259     if (options.IsFecSet())
       
   260         {
       
   261         if (isUnacceptableParameters)
       
   262             {
       
   263             err = iFecNegotiator.PeerRejectsOption(options.Fec());
       
   264             }
       
   265         else
       
   266             {
       
   267             err = iFecNegotiator.PeerAcceptsOption(options.Fec());
       
   268             }
       
   269         }
       
   270     else if (isSuccess)
       
   271         {
       
   272         iFecNegotiator.PeerAcceptsOption();
       
   273         }
       
   274 
       
   275     if (isUnacceptableParameters && !err)
       
   276         {
       
   277         // negotiation algorithm bug workaround.
       
   278 
       
   279         // The problem this tries to work around is as follows:
       
   280         // S - local Symbian entity, C - remote host
       
   281         // SDP connection is being opened, C supports (E)RTM so we try to negotiate it:
       
   282         // 1. S sends ConfigReq[FEC=ERTM, MTU=n].
       
   283         // 2. C responds with ConfigRsp(UnacceptableParameters)[MTU=n].
       
   284         // 3. S obeys the reject, thinking C is rejecting the MTU (note the MTU value proposed
       
   285         //    by C is the same value we sent in (1));
       
   286         //    S sends a new ConfigReq, including the proposed MTU and the FEC which is still pending
       
   287         //    a response, thus creating a ConfigReq identical to the one from (1).
       
   288         // 4. C responds like in (2).
       
   289         // 5. S reacts like in (3).
       
   290         // -- we got into an infinite loop --
       
   291         // The whole situation is due to C in (2) responding with ConfigRsp(UnacceptableParameters)[MTU=n]
       
   292         // while what it really means is ConfigRsp(UnacceptableParameters)[FEC=Basic].
       
   293         // This was found at UPF33 - June 2009 and they fixed their code then, but there still
       
   294         // might be a lot of devices out doing the wrong thing.
       
   295         //
       
   296         // The workaround is to snapshot option status before and after the peer's
       
   297         // Config Response is processed and compare it. If it's exactly the same then
       
   298         // we're in a stalemate, so we cross our fingers and then drop our FEC proposal
       
   299         // to Basic. Remote accepts the ConfigReq with Basic mode and the whole palaver is over.
       
   300         // (the status snapshot includes the Preferred value and the config status of all
       
   301         // options).
       
   302         SL2CapChannelIncomingConfigOptionSnapshot optionStatusAfterProcessing(*this);
       
   303         if (optionStatusBeforeProcessing == optionStatusAfterProcessing)
       
   304             {
       
   305             err = iFecNegotiator.PeerRejectsOption(TRetransmissionAndFlowControlOption());
       
   306             // Note: we'll also fall here if an option has started off with status Failed and
       
   307             // the peer rejected our preferred value, suggesting a value that's again unacceptable.
       
   308             // Example: user requests incoming MTU = 500 which is less than 672, which means
       
   309             // the default peer value of 672 is unacceptable and so the option's status is Failed
       
   310             // by default. If the value of 500 is then rejected by the peer, and it suggests
       
   311             // something else, be it 672 or anything > 500, the status and the actual value will
       
   312             // remain Failed and 500 - so if the status of the other options hasn't changed,
       
   313             // we'll fall in here. It's harmless though because it means we've failed to agree
       
   314             // and will disconnect, so it doesn't matter whether the FEC value is changed.
       
   315             }
       
   316         }
       
   317     return err;
       
   318     }
       
   319 
       
   320 TInt CL2CapChannelConfig::ConfigRequestComplete(TBool aConfigRequestSent, TConfigResponseResult& aResult)
       
   321     {
       
   322     LOG_FUNC
       
   323     TInt err = KErrNone;
       
   324 
       
   325 	// Note that this method applies a different interpretation of the spec than
       
   326 	// HandleConfigResponse. This is due to an ambiguity in the spec which yields two
       
   327 	// possible interpretations:
       
   328 	// (Interpretation A) When handling a Config Response, we assume that:
       
   329 	// (1) if it's positive, then it acknowledges all the options we've sent in Config Request;
       
   330 	// (2) if it's negative, then it only rejects the options that it includes, and neither
       
   331 	//     acknowledges nor rejects the ones that are not included.
       
   332 	// (Interpretation B) When responding to a Config Request, we effectively assume
       
   333 	// the following:
       
   334 	// (1) is the same,
       
   335 	// (2) if it's negative, then it only rejects the options that it includes and acknowledges
       
   336 	//     the ones that are not included.
       
   337 	// There are implementations using both interpetations, so we do different things depending
       
   338 	// on negotiation direction for maximum interop - we assume that interpretation A taken in
       
   339 	// HandleConfigResponse makes more sense, but to be interoperable with both algorithms, we
       
   340 	// respond to a ConfigRequest using interpretation B.
       
   341 	// Here is why, by example:
       
   342 	// 1. Peer sends us Config Request with MTU and FEC;
       
   343 	// 2. We reject the MTU but FEC is ok, so we send a Config Response [Unacceptable Parameters](MTU);
       
   344 	//    According to interpretation B we also accept the FEC, while interpretation A
       
   345 	//    means we ignore it and Peer will include it again in the following ConfigRequest.
       
   346 	// 3a. If Peer implements interpretation B, then it assumes we've accepted the FEC
       
   347 	//    and considers the option value to have been agreed, so it will not include it
       
   348 	//    in the next Config Request along with MTU. Fortunately, we use the same
       
   349 	//    interpretation here so we're in sync.
       
   350 	// 3b. If Peer implements interpretation A, then it will include the FEC in the next
       
   351 	//    Config Request anyway because it's still outstanding, so what we do to the option
       
   352 	//    now doesn't matter. Theoretically Peer could suddenly change its mind and forego
       
   353 	//    negotiating FEC, but obviously unless it's a human no implemntation will do it :)
       
   354 
       
   355     if (iReceivedConfigRequestOptions.IsMtuSet())
       
   356         {
       
   357         iOutgoingMTU->PeerRequestsOption(iReceivedConfigRequestOptions.Mtu());
       
   358         }
       
   359     else
       
   360         {
       
   361         iOutgoingMTU->PeerRequestsLastAcceptedValue();
       
   362         }
       
   363 
       
   364     if (iReceivedConfigRequestOptions.IsFlushTimeoutSet())
       
   365         {
       
   366         iIncomingFlushTimeoutDuration->PeerRequestsOption(iReceivedConfigRequestOptions.FlushTimeout());
       
   367         }
       
   368     else
       
   369         {
       
   370         iIncomingFlushTimeoutDuration->PeerRequestsLastAcceptedValue();
       
   371         }
       
   372 
       
   373     if (iReceivedConfigRequestOptions.IsQosSet())
       
   374         {
       
   375         iIncomingQOS->PeerRequestsOption(iReceivedConfigRequestOptions.Qos());
       
   376         }
       
   377     else
       
   378         {
       
   379         iIncomingQOS->PeerRequestsLastAcceptedValue();
       
   380         }
       
   381 
       
   382     if (iReceivedConfigRequestOptions.IsFecSet())
       
   383         {
       
   384         err = iFecNegotiator.PeerRequestsOption(iReceivedConfigRequestOptions.Fec());
       
   385         }
       
   386     else
       
   387         {
       
   388         err = iFecNegotiator.PeerRequestsLastAcceptedValue();
       
   389         if (err == KErrNone)
       
   390             {
       
   391             // Check if the outgoing FEC connection needs to be downgraded to basic mode.
       
   392             // NB This ONLY makes sense if our config request has not already been queued...
       
   393             //    ...otherwise it would break the config algorithm.
       
   394             if(!aConfigRequestSent)
       
   395                 {
       
   396                 FecNegotiator().DowngradeIncomingToBasicIfOutgoingIsBasic();
       
   397                 }
       
   398             }
       
   399         }
       
   400 
       
   401     // Now reset the Config Request option store in case there's a next negotiation round.
       
   402     iReceivedConfigRequestOptions = TL2CapConfigParamOptions();
       
   403     
       
   404     /*
       
   405     For a config request we know the peer values - so the peer and the actual values should
       
   406     either be the same, or the peer should be outside our limits (See the implementation of
       
   407     TL2CapConfigurationOptionGroupBase::TOptionConfigStatus.)
       
   408     If this __ASSERT_DEBUG is hit, it is likely that the API has been upgraded or
       
   409     the default values have been upgraded in a way which breaks the configuration logic.
       
   410     */
       
   411     __ASSERT_DEBUG(iOutgoingMTU->ConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding &&
       
   412                    iIncomingFlushTimeoutDuration->ConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding &&
       
   413                    iIncomingQOS->ConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding &&
       
   414                    iFecNegotiator.OutgoingConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding,
       
   415                    Panic(EL2CAPInvalidConfigOptionState));
       
   416 
       
   417     // Check the response code required for the subsequent Config Response.
       
   418     if(iOutgoingMTU->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed ||
       
   419        iIncomingFlushTimeoutDuration->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed ||
       
   420        iIncomingQOS->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed ||
       
   421        iFecNegotiator.OutgoingConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed)
       
   422         {
       
   423         aResult = EConfigUnacceptableParams;
       
   424         }
       
   425     else
       
   426         {
       
   427         aResult = EConfigSuccess;
       
   428         }
       
   429 
       
   430     return err;
       
   431     }
       
   432 
       
   433 /**	
       
   434 	Process the entity information received from peer. Used to make sure that we don't try
       
   435 	and negotiate a configuration that the peer is not capable of negotiating.  The predominant use
       
   436 	case is to make sure that we do not negotiate FEC parameters with a device that is only capable
       
   437 	of basic mode.
       
   438 **/
       
   439 TInt CL2CapChannelConfig::UpdateLocalConfigWithEntityCapabilities()
       
   440 	{
       
   441 	LOG_FUNC
       
   442 	TL2CapEntityInfo config; 
       
   443 	TInt err = iL2CapEntityConfig->PeerL2CapSupportedFeatures(config);
       
   444 	if (err == KErrNone)
       
   445 		{
       
   446 		// Signalling state machine is responsible for not calling us until we've got
       
   447 		// peer entity information.
       
   448 		__ASSERT_DEBUG(config.LinkInfoState() == EL2CapEntityInfoDefined,
       
   449 					   Panic(EL2CAPUpdateLocalConfigCalledWithoutPeerEntityConfig));
       
   450 		// Based on knowledge about the peer's extended information, set up mode negotiator.
       
   451 		TBool peerSupportsRequestedConfig = GenerateFecOptions(config);
       
   452 		if (!peerSupportsRequestedConfig)
       
   453 			{
       
   454 			err = KErrL2CAPPeerDoesNotSupportRequestedChannelMode;
       
   455 			}
       
   456 		}
       
   457 	return err;
       
   458 	}
       
   459 
       
   460 /**	
       
   461 	Handles configurable options provided in TL2CapConfig by user APIs.
       
   462 	aOnTheAirConfigRequired will be set to True if the specified parameters require the
       
   463 	L2CAP reconfiguration process, False otherwise.
       
   464 **/
       
   465 TInt CL2CapChannelConfig::UpdateConfigAPIChange(const TL2CapConfig& aApiConfig, TBool& aOnTheAirReconfigRequired)
       
   466 	{
       
   467 	LOG_FUNC
       
   468 	TInt err = KErrNone;
       
   469 
       
   470 	aOnTheAirReconfigRequired = EFalse;
       
   471 
       
   472 	err = UpdateReliability(aApiConfig);
       
   473 	if (err == KErrNone)
       
   474 		{
       
   475 		err = UpdateMtuMru(aApiConfig, aOnTheAirReconfigRequired);
       
   476 		}
       
   477 
       
   478 	// GenerateFecOptions() will be called on OpenChannelRequest to transform these options
       
   479 	// into concrete FEC option values groups.
       
   480 
       
   481 	return err;
       
   482 	}
       
   483 
       
   484 
       
   485 /**	
       
   486 	Returns true if all the configuration elements included in a incoming configuration response
       
   487 	have been successfully configured
       
   488 **/
       
   489 CL2CapChannelConfig::TChannelConfigStatus CL2CapChannelConfig::LocalConfigurationStatus() const	
       
   490 	{
       
   491 	LOG_FUNC
       
   492 	TChannelConfigStatus status = EChannelConfigOutstanding;
       
   493 	
       
   494 	if((iIncomingMTU->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigComplete) &&
       
   495 	   (iOutgoingFlushTimeoutDuration->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigComplete) &&
       
   496 	   (iOutgoingQOS->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigComplete) &&
       
   497 	   (iFecNegotiator.IncomingConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigComplete))
       
   498 		{
       
   499 		status = EChannelConfigComplete;
       
   500 		}
       
   501 	else
       
   502 		{
       
   503 		if((iIncomingMTU->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed) ||
       
   504 		   (iOutgoingFlushTimeoutDuration->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed) ||
       
   505 		   (iOutgoingQOS->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed) ||
       
   506 		   (iFecNegotiator.IncomingConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed))
       
   507 			{
       
   508 			status = EChannelConfigFailed;
       
   509 			}
       
   510 		}
       
   511 	return status;
       
   512 	}
       
   513 
       
   514 /**	
       
   515 	Public function that registers the entity channel configuration with this channel configuration
       
   516 **/
       
   517 void CL2CapChannelConfig::RegisterL2CapEntityConfig(TL2CAPEntityConfig& aL2CapEntityConfig)
       
   518 	{
       
   519 	LOG_FUNC
       
   520 	__ASSERT_DEBUG(!iL2CapEntityConfig, Panic(EL2CAPAttemptToRegisterEntityConfigTwice));
       
   521 	iL2CapEntityConfig = &aL2CapEntityConfig;
       
   522 	}	
       
   523 
       
   524 /**
       
   525 	Channel configuration is being taken down. 
       
   526 **/
       
   527 void CL2CapChannelConfig::DetachChannelConfig()
       
   528 	{
       
   529 	LOG_FUNC
       
   530 	// If the channel config has registered with the Entity
       
   531 	// config remove the association.
       
   532 	iL2CapEntityConfig = NULL;
       
   533 	}
       
   534 
       
   535 // Translates abstract 'Channel Reliability' etc. into concrete option groups.
       
   536 // Called just-in-time on OpenChannelRequest, when the L2CAP connection is being made.
       
   537 // Should only be called once in the lifetime of a connection.
       
   538 TBool CL2CapChannelConfig::GenerateFecOptions(const TL2CapEntityInfo& aPeerEntityConfig)
       
   539 	{
       
   540 	LOG_FUNC
       
   541 
       
   542 	__ASSERT_DEBUG(aPeerEntityConfig.LinkInfoState() == EL2CapEntityInfoDefined,
       
   543 				   Panic(EL2CAPFecConfigAttemptWithoutPeerInfo));
       
   544 
       
   545 	// We may end up falling back from Streaming to ERTM, so set up a sensible MaxTransmit value
       
   546 	// for both Reliable and Unreliable case.
       
   547 	TUint8 maxTransmit = TRetransmissionAndFlowControlOption::KMaxValidEnhancedNumberTransmit;
       
   548 	// TL2CapConfig::EDefaultRetransmission is 0xffff, which is a special value in the API that
       
   549 	// means 'maximum possible MaxTransmit'. Note that we assume here that the maximum MaxTransmit
       
   550 	// is 0, which is only true for enhanced modes. If a legacy mode is negotiated, FECNegotiator
       
   551 	// will change the 0 to 255.
       
   552 	if (iRequestedRetransmissionTimeout != TL2CapConfig::EDefaultRetransmission)
       
   553 		{
       
   554 		maxTransmit = static_cast<TUint8>(iRequestedRetransmissionTimeout / TRetransmissionAndFlowControlOption::KDefaultRetransmissionTimeout);
       
   555 		}
       
   556 
       
   557 	TBool peerSupportsRequestedConfig = iFecNegotiator.Setup(iRequestedChannelReliability, iLegacyModesDisallowed, aPeerEntityConfig, maxTransmit);
       
   558 	if (peerSupportsRequestedConfig)
       
   559 		{
       
   560 		// Set the outgoing flush parameters NOT to allow flushing.
       
   561 		// Note: the TL2CapConfig API does allow setting of the flush timeout, and we do have some
       
   562 		// support for it across the board, but that code is unused. This is the place where
       
   563 		// iRequestedFlushTimeout gets ignored and if ever start supporting flushing, then we should
       
   564 		// take it into account and set the flushTimeoutDuration accordingly if unreliable channel
       
   565 		// is requested.
       
   566 		TFlushTimeoutDurationOption flushTimeoutDuration(TFlushTimeoutDurationOption::EMaximumValue);
       
   567 		iOutgoingFlushTimeoutDuration->SetRequiredValue(flushTimeoutDuration, flushTimeoutDuration, flushTimeoutDuration);
       
   568 		}
       
   569 
       
   570 	return peerSupportsRequestedConfig;
       
   571 	}
       
   572 
       
   573 TInt CL2CapChannelConfig::UpdateReliability(const TL2CapConfig& aApiConfig)
       
   574 	{
       
   575 	LOG_FUNC
       
   576 	TInt err = KErrNone;
       
   577 	TBool specified = EFalse;
       
   578 	TL2CapConfig::TChannelReliability reliability = aApiConfig.ChannelReliability(specified);
       
   579 	if (specified)
       
   580 		{
       
   581 		if (iSAPSignalHandler.IsChannelClosed())
       
   582 			{
       
   583 			TBool getFlushTimeout = EFalse;
       
   584 			TBool getRtxTimeout = EFalse;
       
   585 	
       
   586 			if (reliability == TL2CapConfig::EUnreliableDesiredChannel)
       
   587 				{
       
   588 				getFlushTimeout = getRtxTimeout = ETrue;
       
   589 				}
       
   590 			else if (reliability == TL2CapConfig::EUnreliableChannel)
       
   591 				{
       
   592 				getFlushTimeout = ETrue;
       
   593 				}
       
   594 			else // Reliable
       
   595 				{
       
   596 				getRtxTimeout = ETrue;
       
   597 				}
       
   598 	
       
   599 			TUint16 timeout = 0;
       
   600 	
       
   601 			if (getFlushTimeout)
       
   602 				{
       
   603 				timeout = aApiConfig.ObsolescenceTimer(specified);
       
   604 				if (!specified)
       
   605 					{
       
   606 					err = KErrArgument;
       
   607 					}
       
   608 				else
       
   609 					{
       
   610 					iRequestedFlushTimeout = timeout;
       
   611 					}
       
   612 				}
       
   613 			
       
   614 			if (getRtxTimeout)
       
   615 				{
       
   616 				timeout = aApiConfig.RetransmissionTimer(specified);
       
   617 				if (!specified)
       
   618 					{
       
   619 					err = KErrArgument;
       
   620 					}
       
   621 				else
       
   622 					{
       
   623 					iRequestedRetransmissionTimeout = timeout;
       
   624 					}
       
   625 				}
       
   626 	
       
   627 			if (err == KErrNone)
       
   628 				{
       
   629 				iRequestedChannelReliability = reliability;
       
   630 				iLegacyModesDisallowed = aApiConfig.LegacyModesDisallowed();
       
   631 		
       
   632 				if (iRequestedFlushTimeout < KMinOutgoingFlushTimeout)
       
   633 					{
       
   634 					iRequestedFlushTimeout = KMinOutgoingFlushTimeout;
       
   635 					}
       
   636 				}
       
   637 			} // channel Closed
       
   638 		else
       
   639 			{
       
   640 			// Channel not in Closed state - can't change reliability.
       
   641 			err = KErrInUse;
       
   642 			}
       
   643 		} // reliability specified
       
   644 	return err;
       
   645 	}
       
   646 
       
   647 TInt CL2CapChannelConfig::UpdateMtuMru(const TL2CapConfig& aApiConfig, TBool& aOnTheAirReconfigRequired)
       
   648 	{
       
   649 	LOG_FUNC
       
   650 
       
   651 	// MTU-related params.
       
   652 	TBool mtuSpecified = EFalse;
       
   653 	TBool minMtuSpecified = EFalse;
       
   654 	TUint16 newMTU = aApiConfig.MaxTransmitUnitSize(mtuSpecified);
       
   655 	TUint16 newMinMTU = aApiConfig.MinMTU(minMtuSpecified);
       
   656 	TMTUOption currentMTU = iOutgoingMTU->Preferred();
       
   657 
       
   658 	// MRU-related params.
       
   659 	TBool mruSpecified = EFalse;
       
   660 	TBool minMruSpecified = EFalse;
       
   661 	TUint16 newMRU = aApiConfig.MaxReceiveUnitSize(mruSpecified);
       
   662 	TUint16 newMinMRU = aApiConfig.MinMRU(minMruSpecified);
       
   663 	TMTUOption currentMRU = iIncomingMTU->Preferred();
       
   664 
       
   665 	if ((mtuSpecified || minMtuSpecified || mruSpecified || minMruSpecified) &&
       
   666 		!iSAPSignalHandler.IsChannelClosed() && !iSAPSignalHandler.IsChannelOpen())
       
   667 		{
       
   668 		// Not the brightest idea to mess with these during ongoing config.
       
   669 		return KErrInUse;
       
   670 		}
       
   671 	else
       
   672 		{
       
   673 		if (mtuSpecified || minMtuSpecified)
       
   674 			{
       
   675 			TMTUOption mtuToSet = mtuSpecified ? newMTU : currentMTU;
       
   676 			// if !minMtuSpecified then assume the lower bound to be = newMTU
       
   677 			TMTUOption minMtuToSet = minMtuSpecified ? newMinMTU : newMTU;
       
   678 
       
   679 			if (minMtuToSet > mtuToSet)
       
   680 				{
       
   681 				return KErrL2CAPAttemptToSetMinMtuGreaterThanMtu;
       
   682 				}
       
   683 
       
   684 			iOutgoingMTU->SetRequiredValue(TMTUOption(TMTUOption::EMaximumValue), minMtuToSet, mtuToSet);
       
   685 			aOnTheAirReconfigRequired = ETrue;
       
   686 			}
       
   687 
       
   688 		if (mruSpecified || minMruSpecified)
       
   689 			{
       
   690 			TMTUOption mruToSet = mruSpecified ? newMRU : currentMRU;
       
   691 			 // if !minMruSpecified then assume the lower bound is the spec minimum
       
   692 			TMTUOption minMruToSet = minMruSpecified ? newMinMRU : TMTUOption(TMTUOption::ESpecMinimumValue);
       
   693 
       
   694 			if (minMruToSet > mruToSet)
       
   695 				{
       
   696 				return KErrL2CAPAttemptToSetMinMruGreaterThanMru;
       
   697 				}
       
   698 
       
   699 			iIncomingMTU->SetRequiredValue(mruToSet, minMruToSet, mruToSet);
       
   700 			aOnTheAirReconfigRequired = ETrue;
       
   701 			}
       
   702 		}
       
   703 	return KErrNone;
       
   704 	}
       
   705 
       
   706 TInt CL2CapChannelConfig::GetChannelMode(TL2CapChannelMode& aMode) const
       
   707 	{
       
   708 	LOG_FUNC
       
   709 	__ASSERT_DEBUG(iFecNegotiator.IncomingLinkMode() == iFecNegotiator.OutgoingLinkMode(),
       
   710 				   Panic(EL2CAPAsymmetricChannelModes));
       
   711 	aMode = iFecNegotiator.IncomingLinkMode();
       
   712 	return KErrNone;
       
   713 	}
       
   714 
       
   715 
       
   716 SL2CapChannelIncomingConfigOptionSnapshot::SL2CapChannelIncomingConfigOptionSnapshot(const CL2CapChannelConfig& aChannelConfig)
       
   717  :  iMtu(aChannelConfig.IncomingMTU().Preferred()),
       
   718     iMtuStatus(aChannelConfig.IncomingMTU().ConfigOptionStatus()),
       
   719     iFlushTimeout(aChannelConfig.OutgoingFlushTimeout().Preferred()),
       
   720     iFlushTimeoutStatus(aChannelConfig.OutgoingFlushTimeout().ConfigOptionStatus()),
       
   721     iFec(aChannelConfig.FecNegotiator().IncomingPreferred()),
       
   722     iFecStatus(aChannelConfig.FecNegotiator().IncomingConfigOptionStatus()),
       
   723     iQos(aChannelConfig.OutgoingQOS().Preferred()),
       
   724     iQosStatus(aChannelConfig.OutgoingQOS().ConfigOptionStatus())
       
   725     {
       
   726     LOG_FUNC
       
   727     }
       
   728 
       
   729 TBool SL2CapChannelIncomingConfigOptionSnapshot::operator==(const SL2CapChannelIncomingConfigOptionSnapshot& aThat)
       
   730     {
       
   731     LOG_FUNC
       
   732     return iMtu == aThat.iMtu                   && iMtuStatus == aThat.iMtuStatus &&
       
   733            iFlushTimeout == aThat.iFlushTimeout && iFlushTimeoutStatus == aThat.iFlushTimeoutStatus &&
       
   734            iFec == aThat.iFec                   && iFecStatus == aThat.iFecStatus &&
       
   735            iQos == aThat.iQos                   && iQosStatus == aThat.iQosStatus;
       
   736     }