bluetooth/btstack/l2cap/L2CapFecNegotiator.cpp
changeset 0 29b1cd4cb562
child 10 8a27654f7b62
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 2006-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 //
       
    15 
       
    16 
       
    17 
       
    18 /**
       
    19  @file
       
    20  @internalComponent
       
    21 */
       
    22 
       
    23 #include <bluetooth/logger.h>
       
    24 #include "L2CapFecNegotiator.h"
       
    25 #include "L2CapPDU.h"
       
    26 
       
    27 static TBool operator<=(TL2CapChannelMode aLeft, TL2CapChannelMode aRight);
       
    28 template<typename T> static inline TBool IsWithinBounds(const T aValue, const T aLeftBound, const T aRightBound);
       
    29 
       
    30 #ifdef __FLOG_ACTIVE
       
    31 _LIT8(KLogComponent, LOG_COMPONENT_L2CAP);
       
    32 #endif
       
    33 
       
    34 //
       
    35 // Mode-specific handlers
       
    36 //
       
    37 
       
    38 TBool TModeSpecificFecOptionHandlerBase::BuildPositiveResponse(TRetransmissionAndFlowControlOption& aPreferred,
       
    39 															   const TRetransmissionAndFlowControlOption& aPeer) const
       
    40 	{
       
    41 	LOG_FUNC
       
    42 	// As simple as that according to the general negotiation process, i.e. not when negotiating
       
    43 	// the 2.1 Core Spec Addendum 1 - introduced modes.
       
    44 	aPreferred = aPeer;
       
    45 	// Don't include the exactly same FEC in response.
       
    46 	return EFalse;
       
    47 	}
       
    48 
       
    49 void TModeSpecificFecOptionHandlerBase::BuildNegativeResponse(TRetransmissionAndFlowControlOption& /*aPreferred*/,
       
    50 															  const TRetransmissionAndFlowControlOption& /*aPeer*/) const
       
    51 	{
       
    52 	LOG_FUNC
       
    53 	// Just send what we've got in Preferred.
       
    54 	}
       
    55 
       
    56 void TModeSpecificFecOptionHandlerBase::SetMaxTransmit(TRetransmissionAndFlowControlOption& aFecOption, TUint8 /*aMaxTransmit*/) const
       
    57 	{
       
    58 	LOG_FUNC
       
    59 	aFecOption.SetMaxTransmit(0);
       
    60 	}
       
    61 
       
    62 void TModeSpecificFecOptionHandlerBase::PrepareImplicitPeerResponse(TRetransmissionAndFlowControlOption& aImplicitResponse,
       
    63 																	const TRetransmissionAndFlowControlOption& aPreferred) const
       
    64 	{
       
    65 	LOG_FUNC
       
    66 	aImplicitResponse = aPreferred;
       
    67 	}
       
    68 
       
    69 void TModeSpecificFecOptionHandlerBase::ZeroUnspecifiedRequestFields(TRetransmissionAndFlowControlOption& /*aFecOption*/) const
       
    70 	{LOG_FUNC}
       
    71 
       
    72 void TModeSpecificFecOptionHandlerBase::ZeroUnspecifiedResponseFields(TRetransmissionAndFlowControlOption& /*aFecOption*/) const
       
    73 	{LOG_FUNC}
       
    74 
       
    75 
       
    76 // Streaming Mode
       
    77 
       
    78 TBool TStreamingFecHandler::IsOptionValid(const TRetransmissionAndFlowControlOption& aFecOption) const
       
    79 	{
       
    80 	LOG_FUNC
       
    81 	return aFecOption.MaximumPDUSize() >= TRetransmissionAndFlowControlOption::KMinValidMaximumPDUSize;
       
    82 	}
       
    83 
       
    84 TBool TStreamingFecHandler::IsPeerResponseAcceptable(const TRetransmissionAndFlowControlOption& aPreferred,
       
    85 													 const TRetransmissionAndFlowControlOption& aPeer) const
       
    86 	{
       
    87 	LOG_FUNC
       
    88 	return aPeer.MaximumPDUSize() <= aPreferred.MaximumPDUSize();
       
    89 	}
       
    90 
       
    91 TBool TStreamingFecHandler::BuildPositiveResponse(TRetransmissionAndFlowControlOption& aPreferred,
       
    92 												  const TRetransmissionAndFlowControlOption& aPeer) const
       
    93 	{
       
    94 	LOG_FUNC
       
    95 	TRetransmissionAndFlowControlOption response = aPeer;
       
    96 	// Trim MPS to our desired value.
       
    97 	response.SetMaximumPDUSize(Min(TRetransmissionAndFlowControlOption::KDefaultMaximumPDUSize,
       
    98 								   response.MaximumPDUSize()));
       
    99 	// Zero the ignored fields no matter what peer sent us in them.
       
   100 	ZeroUnspecifiedResponseFields(response);
       
   101 
       
   102 	aPreferred = response;
       
   103 	// Include the FEC in ConfigRsp.
       
   104 	return ETrue;
       
   105 	}
       
   106 
       
   107 void TStreamingFecHandler::BuildNegativeResponse(TRetransmissionAndFlowControlOption& aPreferred,
       
   108                                                  const TRetransmissionAndFlowControlOption& /*aPeer*/) const
       
   109     {
       
   110     LOG_FUNC
       
   111     // Channel Mode has been already set and that's the parameter that what we're actually
       
   112     // rejecting. The rest is informational and should be set by the remote to its own
       
   113     // liking based on the mode proposed, so we _could_ set them to 0, but just in case
       
   114     // we're talking to a dumb peer - or a bit older version of my own code that wouldn't
       
   115     // accept 0s, for that matter - set them to sensible defaults.
       
   116     aPreferred = TRetransmissionAndFlowControlOption(aPreferred.LinkMode(), ETrue);
       
   117     ZeroUnspecifiedRequestFields(aPreferred);
       
   118     }
       
   119 
       
   120 void TStreamingFecHandler::ZeroUnspecifiedRequestFields(TRetransmissionAndFlowControlOption& aFecOption) const
       
   121 	{
       
   122 	LOG_FUNC
       
   123 	aFecOption.SetTxWindowSize(0);
       
   124 	aFecOption.SetMaxTransmit(0);
       
   125 	aFecOption.SetRetransmissionTimeout(0);
       
   126 	aFecOption.SetMonitorTimeout(0);
       
   127 	}
       
   128 
       
   129 void TStreamingFecHandler::ZeroUnspecifiedResponseFields(TRetransmissionAndFlowControlOption& aFecOption) const
       
   130 	{
       
   131 	LOG_FUNC
       
   132 	aFecOption.SetTxWindowSize(0);
       
   133 	aFecOption.SetMaxTransmit(0);
       
   134 	aFecOption.SetRetransmissionTimeout(0);
       
   135 	aFecOption.SetMonitorTimeout(0);
       
   136 	}
       
   137 
       
   138 
       
   139 // Enhanced Retransmission Mode
       
   140 
       
   141 TBool TErtmFecHandler::IsOptionValid(const TRetransmissionAndFlowControlOption& aFecOption) const
       
   142 	{
       
   143 	LOG_FUNC
       
   144 	return aFecOption.MaximumPDUSize() >= TRetransmissionAndFlowControlOption::KMinValidMaximumPDUSize &&
       
   145 		   aFecOption.TxWindowSize() >= TRetransmissionAndFlowControlOption::KMinValidTxWindowSize &&
       
   146 		   aFecOption.TxWindowSize() <= TRetransmissionAndFlowControlOption::KMaxValidEnhancedTxWindowSize;
       
   147 	}
       
   148 
       
   149 TBool TErtmFecHandler::IsPeerResponseAcceptable(const TRetransmissionAndFlowControlOption& aPreferred,
       
   150 												const TRetransmissionAndFlowControlOption& aPeer) const
       
   151 	{
       
   152 	LOG_FUNC
       
   153 	return // MaxTransmit in response doesn't matter.
       
   154 		   IsWithinBounds(aPeer.RetransmissionTimeout(),
       
   155 				   		  TRetransmissionAndFlowControlOption::KMinAcceptableRetransmissionTimeout,
       
   156 				   		  TRetransmissionAndFlowControlOption::KMaxAcceptableRetransmissionTimeout) &&
       
   157 		   IsWithinBounds(aPeer.MonitorTimeout(),
       
   158 				   		  TRetransmissionAndFlowControlOption::KMinAcceptableMonitorTimeout,
       
   159 				   		  TRetransmissionAndFlowControlOption::KMaxAcceptableMonitorTimeout) &&
       
   160 		   aPeer.TxWindowSize() <= aPreferred.TxWindowSize() &&
       
   161 		   aPeer.MaximumPDUSize() <= aPreferred.MaximumPDUSize();
       
   162 	}
       
   163 
       
   164 TBool TErtmFecHandler::BuildPositiveResponse(TRetransmissionAndFlowControlOption& aPreferred,
       
   165 											 const TRetransmissionAndFlowControlOption& aPeer) const
       
   166 	{
       
   167 	LOG_FUNC
       
   168 	TRetransmissionAndFlowControlOption response = aPeer;
       
   169 	// Peer sends us 0s in Retransmission and Monitor time-outs in Request and expects us
       
   170 	// to send values for the timers we're going to use in the response.
       
   171 	response.SetRetransmissionTimeout(TRetransmissionAndFlowControlOption::KDefaultRetransmissionTimeout);
       
   172 	response.SetMonitorTimeout(TRetransmissionAndFlowControlOption::KDefaultMonitorTimeout);
       
   173 	ZeroUnspecifiedResponseFields(response);
       
   174 
       
   175 	// Trim TxWindow and MPS to our preferred values.
       
   176 	response.SetTxWindowSize(Min(TRetransmissionAndFlowControlOption::KDefaultEnhancedTxWindowSize,
       
   177 								 response.TxWindowSize()));
       
   178 	response.SetMaximumPDUSize(Min(TRetransmissionAndFlowControlOption::KDefaultMaximumPDUSize,
       
   179 								   response.MaximumPDUSize()));
       
   180 
       
   181 	aPreferred = response;
       
   182 	// Include the FEC in ConfigRsp.
       
   183 	return ETrue;
       
   184 	}
       
   185 
       
   186 void TErtmFecHandler::BuildNegativeResponse(TRetransmissionAndFlowControlOption& aPreferred,
       
   187                                             const TRetransmissionAndFlowControlOption& /*aPeer*/) const
       
   188     {
       
   189     LOG_FUNC
       
   190     // Channel Mode has been already set and that's the parameter that what we're actually
       
   191     // rejecting. The rest is informational and should be set by the remote to its own
       
   192     // liking based on the mode proposed, so we _could_ set them to 0, but just in case
       
   193     // we're talking to a dumb peer - or a bit older version of my own code that wouldn't
       
   194     // accept 0s, for that matter - set them to sensible defaults.
       
   195     aPreferred = TRetransmissionAndFlowControlOption(aPreferred.LinkMode(), ETrue);
       
   196     ZeroUnspecifiedRequestFields(aPreferred);
       
   197     }
       
   198 
       
   199 void TErtmFecHandler::SetMaxTransmit(TRetransmissionAndFlowControlOption& aFecOption, TUint8 aMaxTransmit) const
       
   200 	{
       
   201 	aFecOption.SetMaxTransmit(aMaxTransmit);
       
   202 	}
       
   203 
       
   204 void TErtmFecHandler::PrepareImplicitPeerResponse(TRetransmissionAndFlowControlOption& aImplicitResponse,
       
   205 												  const TRetransmissionAndFlowControlOption& aPreferred) const
       
   206 	{
       
   207 	LOG_FUNC
       
   208 	TModeSpecificFecOptionHandlerBase::PrepareImplicitPeerResponse(aImplicitResponse, aPreferred);
       
   209 	// Peer is supposed to send us time-out values that it will use. It should always send
       
   210 	// a response FEC if we're negotiating enhanced modes, so eventually we will get the real
       
   211 	// values (unless the peer is broken).
       
   212 	aImplicitResponse.SetRetransmissionTimeout(TRetransmissionAndFlowControlOption::KDefaultRetransmissionTimeout);
       
   213 	aImplicitResponse.SetMonitorTimeout(TRetransmissionAndFlowControlOption::KDefaultMonitorTimeout);
       
   214 	}
       
   215 
       
   216 void TErtmFecHandler::ZeroUnspecifiedRequestFields(TRetransmissionAndFlowControlOption& aFecOption) const
       
   217 	{
       
   218 	aFecOption.SetRetransmissionTimeout(0);
       
   219 	aFecOption.SetMonitorTimeout(0);
       
   220 	}
       
   221 
       
   222 void TErtmFecHandler::ZeroUnspecifiedResponseFields(TRetransmissionAndFlowControlOption& aFecOption) const
       
   223 	{
       
   224 	aFecOption.SetMaxTransmit(0);
       
   225 	}
       
   226 
       
   227 // Flow Control Mode and Retransmission Mode
       
   228 
       
   229 TBool TLegacyFecHandler::IsOptionValid(const TRetransmissionAndFlowControlOption& aFecOption) const
       
   230 	{
       
   231 	LOG_FUNC
       
   232 	return aFecOption.MaximumPDUSize() >= TRetransmissionAndFlowControlOption::KMinValidMaximumPDUSize &&
       
   233 		   aFecOption.TxWindowSize() >= TRetransmissionAndFlowControlOption::KMinValidTxWindowSize &&
       
   234 		   aFecOption.TxWindowSize() <= TRetransmissionAndFlowControlOption::KMaxValidLegacyTxWindowSize &&
       
   235 		   aFecOption.MaxTransmit() >= TRetransmissionAndFlowControlOption::KMinValidNumberTransmit &&
       
   236 		   aFecOption.MaxTransmit() <= TRetransmissionAndFlowControlOption::KMaxValidLegacyNumberTransmit;
       
   237 	}
       
   238 
       
   239 TBool TLegacyFecHandler::IsPeerResponseAcceptable(const TRetransmissionAndFlowControlOption& aPreferred,
       
   240 												  const TRetransmissionAndFlowControlOption& aPeer) const
       
   241 	{
       
   242 	LOG_FUNC
       
   243 	return aPeer == aPreferred;
       
   244 	}
       
   245 
       
   246 void TLegacyFecHandler::SetMaxTransmit(TRetransmissionAndFlowControlOption& aFecOption, TUint8 aMaxTransmit) const
       
   247 	{
       
   248 	aFecOption.SetMaxTransmit(aMaxTransmit == TRetransmissionAndFlowControlOption::KMaxValidEnhancedNumberTransmit ?
       
   249 							  TRetransmissionAndFlowControlOption::KMaxValidLegacyNumberTransmit :
       
   250 							  aMaxTransmit);
       
   251 	}
       
   252 
       
   253 // Basic mode
       
   254 
       
   255 TBool TBasicFecHandler::IsOptionValid(const TRetransmissionAndFlowControlOption& /*aFecOption*/) const
       
   256 	{
       
   257 	LOG_FUNC
       
   258 	// Only the mode field is specified for Basic, and we know the mode is Basic already...
       
   259 	return ETrue;
       
   260 	}
       
   261 
       
   262 TBool TBasicFecHandler::IsPeerResponseAcceptable(const TRetransmissionAndFlowControlOption& /*aPreferred*/,
       
   263 												 const TRetransmissionAndFlowControlOption& /*aPeer*/) const
       
   264 	{
       
   265 	LOG_FUNC
       
   266 	// Only the mode field is specified for Basic, and we know the mode is Basic already...
       
   267 	return ETrue;
       
   268 	}
       
   269 
       
   270 // TFecOptionHandlerDelegator
       
   271 
       
   272 TModeSpecificFecOptionHandlerBase& TFecOptionHandlerDelegator::Handler(const TRetransmissionAndFlowControlOption& aFecOption)
       
   273 	{
       
   274 	TModeSpecificFecOptionHandlerBase* handler = ModeToHandler(aFecOption.LinkMode());
       
   275 	__ASSERT_ALWAYS(handler != NULL, Panic(EL2CAPUnknownChannelMode));
       
   276 	return *handler;
       
   277 	}
       
   278 
       
   279 const TModeSpecificFecOptionHandlerBase& TFecOptionHandlerDelegator::Handler(const TRetransmissionAndFlowControlOption &aFecOption) const
       
   280 	{
       
   281 	const TModeSpecificFecOptionHandlerBase* handler = ModeToHandler(aFecOption.LinkMode());
       
   282 	__ASSERT_ALWAYS(handler != NULL, Panic(EL2CAPUnknownChannelMode));
       
   283 	return *handler;
       
   284 	}
       
   285 
       
   286 TModeSpecificFecOptionHandlerBase* TFecOptionHandlerDelegator::ModeToHandler(TL2CapChannelMode aMode)
       
   287 	{
       
   288 	TModeSpecificFecOptionHandlerBase* processor = 0;
       
   289 	switch (aMode)
       
   290 		{
       
   291 		case EL2CAPStreamingMode:
       
   292 			processor = &iStreamingFecHandler;
       
   293 			break;
       
   294 		case EL2CAPEnhancedRetransmissionMode:
       
   295 			processor = &iErtmFecHandler;
       
   296 			break;
       
   297 		case EL2CAPRetransmissionMode:
       
   298 		case EL2CAPFlowControlMode:
       
   299 			processor = &iLegacyFecHandler;
       
   300 			break;
       
   301 		case EL2CAPBasicMode:
       
   302 			processor = &iBasicFecHandler;
       
   303 			break;
       
   304 		default:
       
   305 			break;
       
   306 			// yes, return NULL.
       
   307 		}
       
   308 	return processor;
       
   309 	}
       
   310 
       
   311 const TModeSpecificFecOptionHandlerBase* TFecOptionHandlerDelegator::ModeToHandler(TL2CapChannelMode aMode) const
       
   312 	{
       
   313 	return const_cast<TFecOptionHandlerDelegator&>(*this).ModeToHandler(aMode);
       
   314 	}
       
   315 
       
   316 #ifdef __FLOG_ACTIVE
       
   317 void TFecOptionHandlerDelegator::LogCurrentValues(const TRetransmissionAndFlowControlOption& aPreferred,
       
   318 												  const TRetransmissionAndFlowControlOption& aPeer) const
       
   319 	{
       
   320 	TBuf<TRetransmissionAndFlowControlOption::KReadableDesSpaceRequired> buf;
       
   321 	aPeer.GetReadable(buf);
       
   322 	LOG1(_L("\tCurrent Peer: %S"), &buf)
       
   323 	buf.Zero();
       
   324 	aPreferred.GetReadable(buf);
       
   325 	LOG1(_L("\tCurrent Preferred: %S"), &buf)
       
   326 	}
       
   327 #endif
       
   328 
       
   329 //
       
   330 // TL2CapSingleDirectionFecNegotiatorBase
       
   331 //
       
   332 void TL2CapSingleDirectionFecNegotiatorBase::SetupForRenegotiation()
       
   333 	{
       
   334 	LOG_FUNC
       
   335 	if (iFecNegotiator.DesiredMode() == EL2CAPBasicMode &&
       
   336 		// Only skip negotiating Basic if it still is the last accepted value.
       
   337 		iPeer.LinkMode() == EL2CAPBasicMode)
       
   338 		{
       
   339 		// See comment in Setup().
       
   340 		iConfigStatus = EOptionConfigComplete;
       
   341 		}
       
   342 #ifdef __FLOG_ACTIVE
       
   343 	LogState();
       
   344 #endif
       
   345 	}
       
   346 
       
   347 TBool TL2CapSingleDirectionFecNegotiatorBase::IsPeerModeAcceptable(TL2CapChannelMode aPeerMode,
       
   348 																   TBool& aDisconnect) const
       
   349 	{
       
   350 	LOG_FUNC
       
   351 	TBool acceptable = ETrue;
       
   352 	aDisconnect = EFalse;
       
   353 
       
   354 	LOG3(_L("\tNegotiation Behavior = %d, Desired Mode = %d, Peer Mode = %d"),
       
   355 		 iFecNegotiator.NegotiationBehavior(), iFecNegotiator.DesiredMode(), aPeerMode)
       
   356 
       
   357 	if (iFecNegotiator.NegotiationBehavior() == TL2CapFecNegotiator::EState2)
       
   358 		{
       
   359 		if (iFecNegotiator.DesiredMode() != aPeerMode)
       
   360 			{
       
   361 			// Game over.
       
   362 			acceptable = EFalse;
       
   363 			aDisconnect = ETrue;
       
   364 			}
       
   365 		}
       
   366 	else // some sort of State 1
       
   367 		{
       
   368 		// A safety net - check that it's legal for our peer to propose this mode.
       
   369 		if (!iFecNegotiator.IsModeLegal(aPeerMode))
       
   370 			{
       
   371 			// Remote is behaving out of spec.
       
   372 			acceptable = EFalse;
       
   373 			LOG1(_L("Peer proposed an illegal mode = %d"), aPeerMode);
       
   374 			}
       
   375 		else
       
   376 			{
       
   377 			// Check that the mode is within our limits according to the spec-defined precedence
       
   378 			// hierarchy. Note that the spec only defines the precedence and State 1/2 algorithm
       
   379 			// for the new modes + Basic, but we try and apply it to the legacy modes as well for
       
   380 			// predictable & consistent behavior.
       
   381 			acceptable = aPeerMode <= iFecNegotiator.DesiredMode();
       
   382 			// Now, the State 1 algorithm gives us two choices in case peer proposes a mode
       
   383 			// that's higher precedence than our desired mode (aPeerMode < iDesiredMode) -
       
   384 			// - we can either accept it or close the connection - we cannot propose a different
       
   385 			// one. EState1NoUnreliableToReliable means we do not want to allow fallback from an
       
   386 			// unreliable mode to a reliable one, i.e. when we propose an unreliable mode,
       
   387 			// but the remote proposes a reliable one (ERTM is higher prec. than Streaming,
       
   388 			// ditto RTM vs FC).
       
   389 			if (acceptable && iFecNegotiator.NegotiationBehavior() == TL2CapFecNegotiator::EState1NoUnreliableToReliable &&
       
   390 				(iFecNegotiator.DesiredMode() == EL2CAPStreamingMode || iFecNegotiator.DesiredMode() == EL2CAPFlowControlMode) &&
       
   391 				(aPeerMode == EL2CAPEnhancedRetransmissionMode || aPeerMode == EL2CAPRetransmissionMode))
       
   392 				{
       
   393 				acceptable = EFalse;
       
   394 				if (!(iFecNegotiator.DesiredMode() == EL2CAPFlowControlMode && aPeerMode == EL2CAPRetransmissionMode))
       
   395 					{
       
   396 					// Only disconnect immediately if the peer seems to be implementing enhanced
       
   397 					// modes - mostly to be interoperable with pre-2.1 Core Spec Addendum 1 Symbian
       
   398 					// code, which doesn't handle disconnects well when there're still unresponded
       
   399 					// request commands.
       
   400 					// If we don't disconnect, a FEC for our desired mode will be sent, and we'll
       
   401 					// see what happens - free style negotiation is allowed with legacy remotes.
       
   402 					aDisconnect = ETrue;
       
   403 					}
       
   404 				LOG(_L("\tRefusing to fall back from Unreliable to Reliable"));
       
   405 				}
       
   406 			}
       
   407 		} // State 1
       
   408 
       
   409 	LOG2(_L("\tPeer channel mode acceptable = %d, disconnect required = %d"), acceptable, aDisconnect);
       
   410 	return acceptable;
       
   411 	}
       
   412 
       
   413 #ifdef __FLOG_ACTIVE
       
   414 void TL2CapSingleDirectionFecNegotiatorBase::LogState() const
       
   415 	{
       
   416 	LOG3(_L("\tdesired channel mode = %d, mode negotiation behavior = %d, config status = %d"),
       
   417 			iFecNegotiator.DesiredMode(), iFecNegotiator.NegotiationBehavior(), iConfigStatus)
       
   418 	TBuf<TRetransmissionAndFlowControlOption::KReadableDesSpaceRequired> readable;
       
   419 	iPreferred.GetReadable(readable);
       
   420 	LOG1(_L("\tpreferred FEC = %S"), &readable);
       
   421 	readable.Zero();
       
   422 	iPeer.GetReadable(readable);
       
   423 	LOG1(_L("\tpeer FEC = %S"), &readable);
       
   424 	}
       
   425 #endif
       
   426 
       
   427 //
       
   428 // TL2CapIncomingFecNegotiator
       
   429 //
       
   430 void TL2CapIncomingFecNegotiator::Setup()
       
   431     {
       
   432     LOG_FUNC
       
   433     // Set up spec default as initial peer value.
       
   434     iPeer = TRetransmissionAndFlowControlOption();
       
   435 
       
   436     // Set up our initial request.
       
   437     BuildRequest(iFecNegotiator.DesiredMode(), iPreferred);
       
   438 
       
   439     if (iFecNegotiator.DesiredMode() == EL2CAPBasicMode)
       
   440         {
       
   441         // Basic mode is the implicit default, so it's complete unless peer says otherwise.
       
   442         // Besides, the fact that Basic is our desired mode normally means that the peer doesn't
       
   443         // support anything else, so it would not be able to parse a TRetransmissionAndFlowControl
       
   444         // option if we sent it.
       
   445         iConfigStatus = EOptionConfigComplete;
       
   446         }
       
   447 
       
   448 #ifdef __FLOG_ACTIVE
       
   449     LogState();
       
   450 #endif
       
   451     }
       
   452 
       
   453 void TL2CapIncomingFecNegotiator::ProcessPeerValue(const TRetransmissionAndFlowControlOption& aFecOption,
       
   454 												   TBool aIsUnacceptableParameters)
       
   455 	{
       
   456 	LOG_FUNC
       
   457 
       
   458 	iPeer = aFecOption;
       
   459 
       
   460 	// 'return' parameter from IsPeerModeAcceptable() - we'll ignore it because in
       
   461 	// incoming direction we disconnect if response config status is failed anyway.
       
   462 	TBool disconnect;
       
   463 
       
   464 	TBool peerAcceptable = IsPeerModeAcceptable(iPeer.LinkMode(), disconnect);
       
   465 	if (peerAcceptable && !aIsUnacceptableParameters)
       
   466 		{
       
   467 		peerAcceptable = iFecNegotiator.ModeSpecificHandlers().IsPeerResponseAcceptable(iPreferred, iPeer);
       
   468 		}
       
   469 
       
   470  	if (!peerAcceptable)
       
   471  		{
       
   472 		iConfigStatus = EOptionConfigFailed;
       
   473  		}
       
   474  	else
       
   475  		{
       
   476 	 	if (aIsUnacceptableParameters)
       
   477 			{
       
   478 	 		iConfigStatus = EOptionConfigOutstanding;
       
   479             // Only take the channel mode from peer's proposal and set informational
       
   480             // (i.e. all other) parameters to our values.
       
   481             BuildRequest(aFecOption.LinkMode(), iPreferred);
       
   482 			}
       
   483 		else
       
   484 			{
       
   485 			iConfigStatus = EOptionConfigComplete;
       
   486 			}
       
   487 		}
       
   488  	LOG1(_L("\tIncoming FEC Config Status is now %d"), iConfigStatus);
       
   489 	}
       
   490 
       
   491 void TL2CapIncomingFecNegotiator::ProcessImplicitPeerValue()
       
   492 	{
       
   493 	LOG_FUNC
       
   494 	// We need to assume that the peer accepted our request and sent an appropriate response back.
       
   495 	TRetransmissionAndFlowControlOption response;
       
   496 	iFecNegotiator.ModeSpecificHandlers().PrepareImplicitPeerResponse(response, iPreferred);
       
   497 	ProcessPeerValue(response, EFalse);
       
   498 	}
       
   499 
       
   500 void TL2CapIncomingFecNegotiator::BuildRequest(TL2CapChannelMode aMode, TRetransmissionAndFlowControlOption& aFecOption)
       
   501     {
       
   502     LOG_FUNC
       
   503     aFecOption = TRetransmissionAndFlowControlOption(aMode, ETrue);
       
   504     iFecNegotiator.ModeSpecificHandlers().SetMaxTransmit(aFecOption, iFecNegotiator.MaxTransmit());
       
   505     iFecNegotiator.ModeSpecificHandlers().ZeroUnspecifiedRequestFields(aFecOption);
       
   506     }
       
   507 
       
   508 //
       
   509 // TL2CapOutgoingFecNegotiator
       
   510 //
       
   511 void TL2CapOutgoingFecNegotiator::Setup()
       
   512     {
       
   513     LOG_FUNC
       
   514     // Set up spec default as initial peer value.
       
   515     iPeer = TRetransmissionAndFlowControlOption();
       
   516 
       
   517     // iPreferred will be constructed when we process peer value once a Config Request has been received.
       
   518 #ifdef __FLOG_ACTIVE
       
   519     LogState();
       
   520 #endif
       
   521     }
       
   522 
       
   523 TInt TL2CapOutgoingFecNegotiator::ProcessPeerValue(const TRetransmissionAndFlowControlOption& aFecOption)
       
   524 	{
       
   525 	LOG_FUNC
       
   526 
       
   527 	TInt err = KErrNone;
       
   528 	TBool disconnect = EFalse;
       
   529 	TBool peerModeAcceptable = IsPeerModeAcceptable(aFecOption.LinkMode(), disconnect);
       
   530 	
       
   531 	if (peerModeAcceptable)
       
   532 		{
       
   533 		iPeer = aFecOption;
       
   534 		iIncludeValueInPositiveConfigResponse = iFecNegotiator.ModeSpecificHandlers().BuildPositiveResponse(iPreferred, iPeer);
       
   535 		iConfigStatus = EOptionConfigComplete;
       
   536 		}
       
   537 	else
       
   538 		{
       
   539 		if (disconnect)
       
   540 			{
       
   541 			// Disconnect immediately without sending an Unacceptable Parameters response.
       
   542 			iConfigStatus = EOptionConfigFailed;
       
   543 			err = KErrConfigRejected;
       
   544 			}
       
   545 		else
       
   546 			{
       
   547             iPreferred.SetLinkMode(iFecNegotiator.DesiredMode());			
       
   548 			iFecNegotiator.ModeSpecificHandlers().BuildNegativeResponse(iPreferred, aFecOption);
       
   549 			// Cause an Unacceptable Parameters response.
       
   550 			iConfigStatus = EOptionConfigFailed;
       
   551 			// Preferred contains our desired FEC, it will be included in the Unaccepted Parameters response.
       
   552 			}
       
   553 		}
       
   554 	LOG1(_L("\tOutgoing FEC Config Status is now %d"), iConfigStatus);
       
   555 	return err;
       
   556 	}
       
   557 
       
   558 
       
   559 //
       
   560 // TL2CapFecNegotiator
       
   561 //
       
   562 TBool TL2CapFecNegotiator::Setup(TL2CapConfig::TChannelReliability aChannelReliability,
       
   563 								 TBool aLegacyModesDisallowed,
       
   564 								 const TL2CapEntityInfo& aPeerEntityConfig,
       
   565 								 TUint8 aMaxTransmit)
       
   566 	{
       
   567 	LOG_FUNC
       
   568 
       
   569 	__ASSERT_DEBUG(aPeerEntityConfig.LinkInfoState() == EL2CapEntityInfoDefined,
       
   570 				   Panic(EL2CAPFecConfigAttemptWithoutPeerInfo));
       
   571 	iPeerSupportedModes = aPeerEntityConfig;
       
   572     iMaxTransmit = aMaxTransmit;
       
   573     
       
   574 	TBool modeNegotiable = EFalse;
       
   575 
       
   576 	iDesiredMode = EL2CAPBasicMode;
       
   577 
       
   578 	// From 2.4 Modes of Operation:
       
   579 	// "Flow Control Mode and Retransmission mode shall only be enabled when communicating with
       
   580 	// L2CAP entities that do not support either Enhanced Retransmission mode or Streaming mode."
       
   581 	// From 5.4 Retransmission And Flow Control Option:
       
   582 	// "Basic mode, Flow Control mode and Retransmission mode shall only be used for backwards
       
   583 	// compatibility with L2CAP entities that do not support Enhanced Retransmission mode or
       
   584 	// Streaming mode."
       
   585 	//
       
   586 	// Make of that what you will, but the official Symbian interpretation is that RTM or FC may
       
   587 	// only be used if the remote doesn't support any of the new modes.
       
   588 	const TBool enhancedModeSupported = iPeerSupportedModes.SupportsEnhancedRetransmissionMode() ||
       
   589 										iPeerSupportedModes.SupportsStreamingMode();
       
   590 
       
   591 	switch (aChannelReliability)
       
   592 		{
       
   593 	case TL2CapConfig::EReliableChannel:
       
   594 		iNegotiationBehavior = aLegacyModesDisallowed ? EState2 : EState1;
       
   595 		if (iPeerSupportedModes.SupportsEnhancedRetransmissionMode())
       
   596 			{
       
   597 			iDesiredMode = EL2CAPEnhancedRetransmissionMode;
       
   598 			modeNegotiable = ETrue;
       
   599 			}
       
   600 		else if (!aLegacyModesDisallowed)
       
   601 			{
       
   602 			if (iPeerSupportedModes.SupportsRetranmission() && !enhancedModeSupported)
       
   603 				{
       
   604 				iDesiredMode = EL2CAPRetransmissionMode;
       
   605 				modeNegotiable = ETrue;
       
   606 				}
       
   607 			else
       
   608 				{
       
   609 				iDesiredMode = EL2CAPBasicMode;
       
   610 				modeNegotiable = ETrue;
       
   611 				}
       
   612 			}
       
   613 		break;
       
   614 
       
   615 	case TL2CapConfig::EUnreliableChannel:
       
   616 		iNegotiationBehavior = aLegacyModesDisallowed ? EState2 : EState1NoUnreliableToReliable;
       
   617 		if (iPeerSupportedModes.SupportsStreamingMode())
       
   618 			{
       
   619 			iDesiredMode = EL2CAPStreamingMode;
       
   620 			modeNegotiable = ETrue;
       
   621 			}
       
   622 		else if (!aLegacyModesDisallowed)
       
   623 			{
       
   624 			if (iPeerSupportedModes.SupportsFlowControl()  && !enhancedModeSupported)
       
   625 				{
       
   626 				iDesiredMode = EL2CAPFlowControlMode;
       
   627 				modeNegotiable = ETrue;
       
   628 				}
       
   629 			else
       
   630 				{
       
   631 				iDesiredMode = EL2CAPBasicMode;
       
   632 				modeNegotiable = ETrue;
       
   633 				}
       
   634 			}
       
   635 		break;
       
   636 
       
   637 	case TL2CapConfig::EUnreliableDesiredChannel:
       
   638 		// Be open to all proposals within spec-defined constraints.
       
   639 		iNegotiationBehavior = EState1;
       
   640 		if (iPeerSupportedModes.SupportsStreamingMode())
       
   641 			{
       
   642 			iDesiredMode = EL2CAPStreamingMode;
       
   643 			modeNegotiable = ETrue;
       
   644 			}
       
   645 		else if (iPeerSupportedModes.SupportsFlowControl() & !enhancedModeSupported)
       
   646 			{
       
   647 			iDesiredMode = EL2CAPFlowControlMode;
       
   648 			modeNegotiable = ETrue;
       
   649 			}
       
   650 		else if (iPeerSupportedModes.SupportsEnhancedRetransmissionMode())
       
   651 			{
       
   652 			iDesiredMode = EL2CAPEnhancedRetransmissionMode;
       
   653 			modeNegotiable = ETrue;
       
   654 			}
       
   655 		else if (iPeerSupportedModes.SupportsRetranmission() && !enhancedModeSupported)
       
   656 			{
       
   657 			iDesiredMode = EL2CAPRetransmissionMode;
       
   658 			modeNegotiable = ETrue;
       
   659 			}
       
   660 		else
       
   661 			{
       
   662 			iDesiredMode = EL2CAPBasicMode;
       
   663 			modeNegotiable = ETrue;
       
   664 			}
       
   665 		break;
       
   666 		}
       
   667 
       
   668 	if (modeNegotiable)
       
   669 		{
       
   670         iIncomingNegotiator.Setup();
       
   671         iOutgoingNegotiator.Setup();
       
   672 		}
       
   673 	return modeNegotiable;
       
   674 	}
       
   675 
       
   676 void TL2CapFecNegotiator::SetupForRenegotiation()
       
   677 	{
       
   678 	LOG_FUNC
       
   679 	iIncomingNegotiator.SetupForRenegotiation();
       
   680 	iOutgoingNegotiator.SetupForRenegotiation();
       
   681 	}
       
   682 
       
   683 // A helper that optimizes the negotiation process by downgrading incoming preferred mode
       
   684 // to Basic if the remote requests Basic, we accept it, and haven't sent out our request yet.
       
   685 // Caveat: This should be only called if our Config Request hasn't been sent yet
       
   686 // and we know we've received peer's Config Request.
       
   687 void TL2CapFecNegotiator::DowngradeIncomingToBasicIfOutgoingIsBasic()
       
   688 	{
       
   689 	LOG_FUNC
       
   690 	// If we've already accepted Peer's Basic mode request, we may downgrade the incoming
       
   691 	// direction to Basic as well, since FEC in a single direction is forbidden.
       
   692 	// Otherwise we may end up with FEC in just one direction and would have to
       
   693 	// downgrade and renegotiate anyway.
       
   694 	// Note: this only makes sense if we haven't sent our Config Request yet.
       
   695 	// The caller is responsible for checking this.
       
   696 	if ((iNegotiationBehavior == EState1 ||
       
   697 		 iNegotiationBehavior == EState1NoUnreliableToReliable) &&
       
   698 		iOutgoingNegotiator.ConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigFailed &&
       
   699 		iOutgoingNegotiator.Preferred().LinkMode() == EL2CAPBasicMode &&
       
   700 		iIncomingNegotiator.Preferred().LinkMode() != EL2CAPBasicMode)
       
   701 		{
       
   702 		LOG(_L("\tReceived Basic mode Config Request, downgrading incoming channel mode to Basic"));
       
   703 		// Downgrade incoming FEC to be basic mode.
       
   704   		TRetransmissionAndFlowControlOption basicFec;
       
   705   		iIncomingNegotiator.SetPreferred(basicFec);
       
   706 		}
       
   707 	}
       
   708 
       
   709 TInt TL2CapFecNegotiator::CheckNegotiatedChannelMode(TBool& aDowngrade)
       
   710 	{
       
   711 	LOG_FUNC
       
   712 	TInt err = KErrNone;
       
   713 
       
   714 	if ((iNegotiationBehavior == EState1 ||
       
   715 		 iNegotiationBehavior == EState1NoUnreliableToReliable)
       
   716 		&&
       
   717 		 ((iOutgoingNegotiator.Preferred().LinkMode() == EL2CAPBasicMode &&
       
   718 		   iIncomingNegotiator.Peer().LinkMode() != EL2CAPBasicMode)
       
   719 		  ||
       
   720 		  (iIncomingNegotiator.Peer().LinkMode() == EL2CAPBasicMode &&
       
   721 		   iOutgoingNegotiator.Preferred().LinkMode() != EL2CAPBasicMode)))
       
   722 		{
       
   723 		LOG(_L("\tDowngrading unidirectional FEC to Basic in both directions"));
       
   724 
       
   725 		TRetransmissionAndFlowControlOption basicFec;
       
   726 		iIncomingNegotiator.SetPreferred(basicFec);
       
   727 		iOutgoingNegotiator.SetPreferred(basicFec);
       
   728 
       
   729 		SetupForRenegotiation();
       
   730 		aDowngrade = ETrue;
       
   731 		}
       
   732 	else if (IncomingLinkMode() != OutgoingLinkMode())
       
   733 		{
       
   734 		LOG2(_L("\tSomehow managed to negotiate %d incoming mode and %d outgoing mode"),
       
   735 			 IncomingLinkMode(), OutgoingLinkMode());
       
   736 		err = KErrL2CAPNegotiatedDifferentModesForEachDirection;
       
   737 		}
       
   738 	else
       
   739 		{
       
   740 		aDowngrade = EFalse;
       
   741 		}
       
   742 
       
   743 	return err;
       
   744 	}
       
   745 
       
   746 TBool TL2CapFecNegotiator::IsModeLegal(TL2CapChannelMode aPeerMode) const
       
   747 	{
       
   748 	LOG_FUNC
       
   749 	TBool legal = ETrue;
       
   750 	if ((aPeerMode == EL2CAPEnhancedRetransmissionMode && !iPeerSupportedModes.SupportsEnhancedRetransmissionMode()) ||
       
   751 		(aPeerMode == EL2CAPStreamingMode              && !iPeerSupportedModes.SupportsStreamingMode()) ||
       
   752 		(aPeerMode == EL2CAPRetransmissionMode         && !iPeerSupportedModes.SupportsRetranmission()) ||
       
   753 		(aPeerMode == EL2CAPFlowControlMode            && !iPeerSupportedModes.SupportsFlowControl()) ||
       
   754 		// if any of the new modes is supported then none of the old ones shall be used
       
   755 		((aPeerMode == EL2CAPRetransmissionMode || aPeerMode == EL2CAPFlowControlMode) &&
       
   756 		 (iPeerSupportedModes.SupportsEnhancedRetransmissionMode() || iPeerSupportedModes.SupportsStreamingMode())))
       
   757 		{
       
   758 		legal = EFalse;
       
   759 		}
       
   760 	return legal;
       
   761 	}
       
   762 
       
   763 // The enhanced modes are ordered according to the 2.1 Core Spec Addendum 1
       
   764 // "state 1" precedence (pt 5.4), but in reverse order.
       
   765 //	1. Streaming
       
   766 //	2. ERTM
       
   767 //	3. Basic
       
   768 // The legacy modes are ordered similarly:
       
   769 //	1. Flow Control
       
   770 //  2. RTM
       
   771 //	3. Basic
       
   772 // Additionally pairs consisting of a legacy and a new mode are never in relation.
       
   773 static TBool operator<=(TL2CapChannelMode aLeft, TL2CapChannelMode aRight)
       
   774 	{
       
   775 	TBool inRelation = EFalse;
       
   776 	switch(aLeft)
       
   777 		{
       
   778 		case EL2CAPBasicMode:
       
   779 			inRelation = ETrue;
       
   780 			break;
       
   781 
       
   782 		case EL2CAPRetransmissionMode:
       
   783 			switch (aRight)
       
   784 				{
       
   785 				case EL2CAPBasicMode:
       
   786 					inRelation = EFalse;
       
   787 					break;
       
   788 				case EL2CAPRetransmissionMode:
       
   789 					inRelation = ETrue;
       
   790 					break;
       
   791 				case EL2CAPFlowControlMode:
       
   792 					inRelation = ETrue;
       
   793 					break;
       
   794 				case EL2CAPEnhancedRetransmissionMode:
       
   795 					inRelation = EFalse;
       
   796 					break;
       
   797 				case EL2CAPStreamingMode:
       
   798 					inRelation = EFalse;
       
   799 					break;
       
   800 				}
       
   801 			break;
       
   802 
       
   803 		case EL2CAPFlowControlMode:
       
   804 			switch (aRight)
       
   805 				{
       
   806 				case EL2CAPBasicMode:
       
   807 					inRelation = EFalse;
       
   808 					break;
       
   809 				case EL2CAPRetransmissionMode:
       
   810 					inRelation = EFalse;
       
   811 					break;
       
   812 				case EL2CAPFlowControlMode:
       
   813 					inRelation = ETrue;
       
   814 					break;
       
   815 				case EL2CAPEnhancedRetransmissionMode:
       
   816 					inRelation = EFalse;
       
   817 					break;
       
   818 				case EL2CAPStreamingMode:
       
   819 					inRelation = EFalse;
       
   820 					break;
       
   821 				}
       
   822 			break;
       
   823 
       
   824 		case EL2CAPEnhancedRetransmissionMode:
       
   825 			switch (aRight)
       
   826 				{
       
   827 				case EL2CAPBasicMode:
       
   828 					inRelation = EFalse;
       
   829 					break;
       
   830 				case EL2CAPRetransmissionMode:
       
   831 					inRelation = EFalse;
       
   832 					break;
       
   833 				case EL2CAPFlowControlMode:
       
   834 					inRelation = EFalse;
       
   835 					break;
       
   836 				case EL2CAPEnhancedRetransmissionMode:
       
   837 					inRelation = ETrue;
       
   838 					break;
       
   839 				case EL2CAPStreamingMode:
       
   840 					inRelation = ETrue;
       
   841 					break;
       
   842 				}
       
   843 			break;
       
   844 
       
   845 		case EL2CAPStreamingMode:
       
   846 			switch (aRight)
       
   847 				{
       
   848 				case EL2CAPBasicMode:
       
   849 					inRelation = EFalse;
       
   850 					break;
       
   851 				case EL2CAPRetransmissionMode:
       
   852 					inRelation = EFalse;
       
   853 					break;
       
   854 				case EL2CAPFlowControlMode:
       
   855 					inRelation = EFalse;
       
   856 					break;
       
   857 				case EL2CAPEnhancedRetransmissionMode:
       
   858 					inRelation = EFalse;
       
   859 					break;
       
   860 				case EL2CAPStreamingMode:
       
   861 					inRelation = ETrue;
       
   862 					break;
       
   863 				}
       
   864 			break;
       
   865 		}
       
   866 
       
   867 	return inRelation;
       
   868 	}
       
   869 
       
   870 template<typename T>
       
   871 static inline TBool IsWithinBounds(const T aValue, const T aLeftBound, const T aRightBound)
       
   872 	{
       
   873 	return aLeftBound <= aValue && aValue <= aRightBound;
       
   874 	}