bluetooth/btstack/l2cap/l2capSigPacketConfigure.cpp
changeset 0 29b1cd4cb562
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 2004-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 #include <bluetooth/logger.h>
       
    17 
       
    18 #include "l2capSigPacketConfigure.h"
       
    19 
       
    20 #include "l2capSignalHandler.h"
       
    21 #include "L2CapChannelConfig.h"
       
    22 
       
    23 #include "l2util.h"
       
    24 
       
    25 #ifdef __FLOG_ACTIVE
       
    26 _LIT8(KLogComponent, LOG_COMPONENT_L2CAP);
       
    27 #endif
       
    28 
       
    29 //					CONFIGURE REQUEST COMMAND 
       
    30 
       
    31 
       
    32 //Pass in a TL2ConfigOptions packets.  Any options set to valid will be negotiated with there set values
       
    33 HConfigureRequest* HConfigureRequest::New(TL2CAPPort aRemotePort, CL2CapChannelConfig& aConfig,
       
    34 		  	               				  TUint8 aRTXTimerDuration,
       
    35 	                                      TUint16 aERTXTimerDuration)
       
    36 
       
    37 	{
       
    38 	LOG_STATIC_FUNC
       
    39 	HConfigureRequest* cmd = NULL;
       
    40 	RMBufChain buf;
       
    41 	TRAPD(rerr, buf.AllocL(KConfigRequestEmptyLength));
       
    42 	if(rerr == KErrNone)
       
    43 		{
       
    44 		cmd = new HConfigureRequest(buf, aRTXTimerDuration, aERTXTimerDuration);
       
    45 		if(cmd)
       
    46 			{
       
    47 			// Setup message contents.
       
    48 			cmd->SetCode(EConfigureRequest);
       
    49 			cmd->SetID(KUninitialisedID);
       
    50 						
       
    51 			cmd->SetDestinationCID(aRemotePort);
       
    52 			cmd->SetFlags(KNoConfigurationFlags);
       
    53 
       
    54 			// Add the options
       
    55 			rerr = cmd->AddOptionsToCommand(aConfig);
       
    56 			if(rerr != KErrNone)
       
    57 				{
       
    58 				delete cmd;
       
    59 				cmd = NULL;
       
    60 				}
       
    61 			}
       
    62 		else
       
    63 			{
       
    64 			// Free the allocated buffer.
       
    65 			buf.Free();
       
    66 			}
       
    67 		}
       
    68 	return cmd;
       
    69 	}
       
    70 	
       
    71 /**
       
    72 Verifies that the buffer contains a structurally correct command. 
       
    73 This does not ensure that the content of the command is semantically valid.
       
    74 
       
    75 @param aCommmand A new HL2CapCommand if the buffer contains a structurally valid command.
       
    76 @param aBuffer The buffer containing the command
       
    77 @return KErrNone if the command if created.
       
    78 		KErrNoMemory if the command structure is valid but cannot be created.
       
    79 		KErrCorrupt if the command structure is invalid.
       
    80 */
       
    81 TInt HConfigureRequest::NewCommandIfValid(RMBufChain& aBuffer, HL2CapCommand*& aCommand)
       
    82 	{
       
    83 	LOG_STATIC_FUNC
       
    84 	TInt length = aBuffer.Length();
       
    85 	if(length < KConfigRequestEmptyLength)
       
    86 		{
       
    87 		// Dodge length!
       
    88 		return KErrCorrupt;
       
    89 		}
       
    90 		
       
    91 	if(TL2CapConfigParamOptions::VerifyOptionsStructure(KOptionsOffset, aBuffer))
       
    92 		{
       
    93 		// Top!  The structure's fine, go ahead and create the command.
       
    94 		aCommand = new HConfigureRequest(aBuffer);
       
    95 		if(aCommand)
       
    96 			{
       
    97 			return KErrNone;
       
    98 			}
       
    99 		else
       
   100 			{
       
   101 			return KErrNoMemory;
       
   102 			}
       
   103 		}
       
   104 	else
       
   105 		{
       
   106 		// We'll not have any of this nonsense!
       
   107 		return KErrCorrupt;
       
   108 		}	
       
   109 	}
       
   110 	
       
   111 HConfigureRequest::HConfigureRequest(RMBufChain& aCommand,
       
   112 	  	               				 TUint8 aRTXTimerDuration,
       
   113 	                                 TUint16 aERTXTimerDuration)
       
   114  : HL2CapCommand(aCommand, aRTXTimerDuration, aERTXTimerDuration)
       
   115 	{
       
   116 	LOG_FUNC
       
   117 	}
       
   118 
       
   119 TBool HConfigureRequest::ProcessCommand(CL2CapSignalHandler& aSignalHandler)
       
   120 	{
       
   121 	LOG_FUNC
       
   122 	if(aSignalHandler.HandleConfigureRequest(this))
       
   123 		{
       
   124 		// The command has been handled.  Delete it.
       
   125 		delete this;
       
   126 		return ETrue;
       
   127 		}
       
   128 	else
       
   129 		{
       
   130 		return EFalse;
       
   131 		}
       
   132 	}
       
   133 
       
   134 TInt HConfigureRequest::ParseOptions(TL2CapConfigParamOptions& aConfigOptions, RMBufChain& aUnknownOptions) const
       
   135 	{
       
   136 	LOG_FUNC
       
   137 	return aConfigOptions.ParseOptions(KOptionsOffset, iCommand, aUnknownOptions);
       
   138 	}
       
   139 
       
   140 TInt HConfigureRequest::AddOptionsToCommand(CL2CapChannelConfig& aConfig)
       
   141 	{
       
   142 	LOG_FUNC
       
   143 	TInt rerr = TL2CapConfigParamOptions::AddConfigRequestOptions(aConfig, KOptionsOffset, iCommand);
       
   144 	if(rerr == KErrNone)
       
   145 		{
       
   146 		WriteDataLength();
       
   147 		}
       
   148 	return rerr;
       
   149 	}
       
   150 
       
   151 
       
   152 //					CONFIGURE RESPONSE COMMAND 
       
   153 //Constructs a command response ready for transmission
       
   154 HConfigureResponse* HConfigureResponse::New(TUint8 aId, TL2CAPPort aRemotePort, TConfigFlags aFlags, TConfigResponseResult aResult) 
       
   155 	{
       
   156 	LOG_STATIC_FUNC
       
   157 	HConfigureResponse* cmd = NULL;
       
   158 	RMBufChain buf;
       
   159 	TRAPD(rerr, buf.AllocL(KConfigResponseEmptyLength));
       
   160 	if(rerr == KErrNone)
       
   161 		{
       
   162 		cmd = new HConfigureResponse(buf);
       
   163 		if(cmd)
       
   164 			{
       
   165 			// Setup message contents.
       
   166 			cmd->SetCode(EConfigureResponse);
       
   167 			cmd->SetID(aId);
       
   168 						
       
   169 			cmd->SetSourceCID(aRemotePort);
       
   170 			cmd->SetFlags(aFlags);
       
   171 			cmd->SetResults(aResult);
       
   172 			}
       
   173 		else
       
   174 			{
       
   175 			// Free the allocated buffer.
       
   176 			buf.Free();
       
   177 			}
       
   178 		}
       
   179 	return cmd;
       
   180 	}
       
   181 
       
   182 /**
       
   183 Verifies that the buffer contains a structurally correct command. 
       
   184 This does not ensure that the content of the command is semantically valid.
       
   185 
       
   186 @param aCommmand A new HL2CapCommand if the buffer contains a structurally valid command.
       
   187 @param aBuffer The buffer containing the command
       
   188 @return KErrNone if the command if created.
       
   189 		KErrNoMemory if the command structure is valid but cannot be created.
       
   190 		KErrCorrupt if the command structure is invalid.
       
   191 */
       
   192 TInt HConfigureResponse::NewCommandIfValid(RMBufChain& aBuffer, HL2CapCommand*& aCommand)
       
   193 	{
       
   194 	LOG_STATIC_FUNC	
       
   195 	if(aBuffer.Length() < KConfigResponseEmptyLength)
       
   196 		{
       
   197 		// Dodge length!
       
   198 		return KErrCorrupt;
       
   199 		}
       
   200 		
       
   201 	if(TL2CapConfigParamOptions::VerifyOptionsStructure(KOptionsOffset, aBuffer))
       
   202 		{
       
   203 		// Top!  The structure's fine, go ahead and create the command.
       
   204 		aCommand = new HConfigureResponse(aBuffer);
       
   205 		if(aCommand)
       
   206 			{
       
   207 			return KErrNone;
       
   208 			}
       
   209 		else
       
   210 			{
       
   211 			return KErrNoMemory;
       
   212 			}
       
   213 		}
       
   214 	else
       
   215 		{
       
   216 		// We'll not have any of this nonsense!
       
   217 		return KErrCorrupt;
       
   218 		}	
       
   219 	}
       
   220 
       
   221 HConfigureResponse::HConfigureResponse(RMBufChain& aCommand) 
       
   222  : HL2CapCommand(aCommand)
       
   223 	{
       
   224 	LOG_FUNC
       
   225 	}
       
   226 
       
   227 TBool HConfigureResponse::ProcessCommand(CL2CapSignalHandler& aSignalHandler)	
       
   228 	{
       
   229 	LOG_FUNC
       
   230 	if(aSignalHandler.HandleConfigureResponse(this))
       
   231 		{
       
   232 		// The command has been handled.  Delete it.
       
   233 		delete this;
       
   234 		return ETrue;
       
   235 		}
       
   236 	else
       
   237 		{
       
   238 		return EFalse;
       
   239 		}
       
   240 	}
       
   241 	
       
   242 //Put this here to allow base function to be protected, ie not all commands expose functionality
       
   243 TInt HConfigureResponse::ParseOptions(TL2CapConfigParamOptions& aConfigOptions, RMBufChain& aUnknownOptions) const
       
   244 	{
       
   245 	LOG_FUNC
       
   246 	return aConfigOptions.ParseOptions(KOptionsOffset, iCommand, aUnknownOptions);
       
   247 	}
       
   248 																									
       
   249 TInt HConfigureResponse::AddOptionsToCommand(CL2CapChannelConfig& aConfig, TConfigResponseResult aResult)
       
   250 	{
       
   251 	LOG_FUNC
       
   252 	TInt rerr = TL2CapConfigParamOptions::AddConfigResponseOptions(aConfig, KOptionsOffset, iCommand, aResult);
       
   253 	if(rerr == KErrNone)
       
   254 		{
       
   255 		WriteDataLength();
       
   256 		}
       
   257 	return rerr;
       
   258 	}
       
   259 
       
   260 void HConfigureResponse::AddUnknownOptionsToCommand(RMBufChain& aUnknownOptions)
       
   261 	{
       
   262 	LOG_FUNC
       
   263 	iCommand.Append(aUnknownOptions);
       
   264 	WriteDataLength();	
       
   265 	}
       
   266 
       
   267 
       
   268 TL2CapConfigParamOptions::TL2CapConfigParamOptions()
       
   269  :	iMtuSet(EFalse),
       
   270 	iMtu(ML2CapConfigurationOption::ESpecDefaultValue),
       
   271 	iFlushTimeoutSet(EFalse),
       
   272 	iFlushTimeout(ML2CapConfigurationOption::ESpecDefaultValue),
       
   273 	iFecSet(EFalse),
       
   274 	iQosSet(EFalse),
       
   275 	iQos(ML2CapConfigurationOption::ESpecDefaultValue)
       
   276 	{
       
   277 	LOG_FUNC
       
   278 	}
       
   279 
       
   280 TBool TL2CapConfigParamOptions::operator==(const TL2CapConfigParamOptions& aThat)
       
   281 	{
       
   282 	LOG_FUNC
       
   283 	// The exactly same options must be included in both sets...
       
   284 	if (iMtuSet != aThat.iMtuSet ||
       
   285 		iFlushTimeoutSet != aThat.iFlushTimeoutSet ||
       
   286 		iFecSet != aThat.iFecSet ||
       
   287 		iQosSet != aThat.iQosSet)
       
   288 		{
       
   289 		return EFalse;
       
   290 		}
       
   291 	else
       
   292 		{
       
   293 		// ... and the included option's values must be the same.
       
   294 		return (!iMtuSet || iMtu == aThat.iMtu) &&
       
   295 			   (!iFlushTimeoutSet || iFlushTimeout == aThat.iFlushTimeout) &&
       
   296 			   (!iFecSet || iFec == aThat.iFec) &&
       
   297 			   (!iQosSet || iQos == aThat.iQos);
       
   298 		}
       
   299 	}
       
   300 
       
   301 TInt TL2CapConfigParamOptions::ParseOptions(TUint8 aOptionOffset, const RMBufChain& aCommand, RMBufChain& aUnknownOptions)
       
   302 	{
       
   303 	LOG_FUNC
       
   304 	TUint8 optionDataLen = 0;
       
   305 	TInt startOfCurrentOption = aOptionOffset;
       
   306 	TInt commandLength = aCommand.Length();
       
   307 	TInt rerr = KErrNone;
       
   308 
       
   309 	// Parse the command options.  Ensure that there is at least an option header
       
   310 	// left to read.
       
   311 	while(startOfCurrentOption + KOptionHeaderLength <= commandLength && 
       
   312 	      (rerr == KErrNone || rerr == KErrConfigUnknownOptions))
       
   313 		{
       
   314 		TBuf8<KOptionHeaderLength> headerBuf(KOptionHeaderLength);
       
   315 		aCommand.CopyOut(headerBuf, startOfCurrentOption);
       
   316 
       
   317 		TUint8 optionType = headerBuf[KTypeOffset];
       
   318 		optionDataLen = headerBuf[KLengthOffset];
       
   319 
       
   320 		// Switch on the option type. Option type could have hint bit set, remove it
       
   321 		switch(optionType & ~KOptionTypeIsHintMask)
       
   322 			{
       
   323 			case EConfigOptionTypeMTU:
       
   324 				{
       
   325 				TBuf8<KMTUOptionDataLen> mtuBuf(KMTUOptionDataLen);
       
   326 				aCommand.CopyOut(mtuBuf, startOfCurrentOption + KDataOffset);
       
   327 
       
   328 				TMTUOption mtu(LittleEndian::Get16(mtuBuf.Ptr()));
       
   329 				SetMtu(mtu);
       
   330 				}
       
   331 				break;
       
   332 
       
   333 			case EConfigOptionTypeFlushTimeoutDuration:
       
   334 				{
       
   335 				TBuf8<KFlushOptionDataLen> flushTimeoutBuf(KFlushOptionDataLen);
       
   336 				aCommand.CopyOut(flushTimeoutBuf, startOfCurrentOption + KDataOffset);
       
   337 
       
   338 				TFlushTimeoutDurationOption flushTimeoutDuration(LittleEndian::Get16(flushTimeoutBuf.Ptr()));
       
   339 				SetFlushTimeout(flushTimeoutDuration);
       
   340 				}
       
   341 				break;
       
   342 				
       
   343 			case EConfigOptionTypeQOS:
       
   344 				{
       
   345 				TBuf8<KQOSOptionDataLen> qosBuf(KQOSOptionDataLen);
       
   346 				aCommand.CopyOut(qosBuf, startOfCurrentOption + KDataOffset);
       
   347 				
       
   348 				TQualityOfServiceOption qos(static_cast<TQOSServiceType>(qosBuf[KQOSServiceTypeOffset]),
       
   349 				                            LittleEndian::Get32(qosBuf.Ptr()+KTokenRateOffset),
       
   350 											LittleEndian::Get32(qosBuf.Ptr()+KTokenBucketSizeOffset),
       
   351 											LittleEndian::Get32(qosBuf.Ptr()+KPeakBandwidthOffset),
       
   352 											LittleEndian::Get32(qosBuf.Ptr()+KLatencyOffset),
       
   353 											LittleEndian::Get32(qosBuf.Ptr()+KDelayVariationOffset));
       
   354 				SetQos(qos);
       
   355 				}
       
   356 				break;
       
   357 			
       
   358 			case EConfigOptionTypeRTxAndFEC:
       
   359 				{
       
   360 				TBuf8<KFECOptionDataLen> fecBuf(KFECOptionDataLen);
       
   361 				aCommand.CopyOut(fecBuf, startOfCurrentOption + KDataOffset);
       
   362 			
       
   363 				TRetransmissionAndFlowControlOption fec(static_cast<TL2CapChannelMode>(fecBuf[KLinkModeOffset]),
       
   364 														fecBuf[KTxWindowSizeOffset],
       
   365 														fecBuf[KMaxTransmitOffset],
       
   366 														LittleEndian::Get16(fecBuf.Ptr() + KRetransmissionTimeoutOffset),
       
   367 														LittleEndian::Get16(fecBuf.Ptr() + KMonitorTimeoutOffset),
       
   368 														LittleEndian::Get16(fecBuf.Ptr() + KMaximumPDUSizeOffset));
       
   369 				SetFec(fec);
       
   370 				}
       
   371 				break;
       
   372 
       
   373 			case EConfigOptionTypeFcs:
       
   374 				// Special case. Even though we don't support the 'FCS option' option
       
   375 				// (i.e. we always do FCS), this can be silently ignored because of
       
   376 				// its specific semantics: FCS is only disabled on a channel on which
       
   377 				// both ends include this option with the value = 'No FCS'. Since we
       
   378 				// will never do that, the value we receive from the peer has no effect
       
   379 				// and can be ignored instead of responding with 'Unknown Option',
       
   380 				// even though 'FCS Option' is 0 in our supported feature mask - some
       
   381 				// people still send the option even in this case.
       
   382 				break;
       
   383 				
       
   384 			default:
       
   385 				{
       
   386 				// Store the unknown options into the buffer argument.
       
   387 				// If the hint bit is set (MSB of option type field) ignore the unknown
       
   388 				// parameter.
       
   389 				if(!(optionType & KOptionTypeIsHintMask))
       
   390 					{
       
   391 					// This is not a hint option - add it to the list of unknown options
       
   392 					// to be sent in the subsequent response.
       
   393 					RMBufChain unknownOption;
       
   394 					TRAP(rerr, aCommand.CopyL(unknownOption, startOfCurrentOption, KOptionHeaderLength + optionDataLen));
       
   395 					if(rerr == KErrNone)
       
   396 						{
       
   397 						aUnknownOptions.Append(unknownOption);
       
   398 						rerr = KErrConfigUnknownOptions;
       
   399 						}
       
   400 					}
       
   401 				}
       
   402 				break;
       
   403 			}
       
   404 
       
   405 		// Move to the next option.
       
   406 		startOfCurrentOption += (optionDataLen + KOptionHeaderLength);
       
   407 		}
       
   408 	return rerr;
       
   409 	}
       
   410 
       
   411 /*static*/ TInt TL2CapConfigParamOptions::AddConfigResponseOptions(CL2CapChannelConfig& aConfig, TUint8 aOptionOffset, RMBufChain& aOptions, TConfigResponseResult aResult)
       
   412 	{
       
   413 	LOG_STATIC_FUNC
       
   414 	TInt rerr = KErrNone;
       
   415 	TInt currentCommandIndex = 0;
       
   416 	// General rule is that we include accepted options only in positive responses.
       
   417 	TBool isUnacceptableParams = (aResult == EConfigUnacceptableParams);
       
   418 
       
   419 	const TL2CapConfigurationOptionGroupBase::TOptionConfigStatus mtuStatus = aConfig.OutgoingMTU().ConfigOptionStatus();
       
   420 	const TL2CapConfigurationOptionGroupBase::TOptionConfigStatus flushToStatus = aConfig.IncomingFlushTimeout().ConfigOptionStatus();
       
   421 	const TL2CapConfigurationOptionGroupBase::TOptionConfigStatus qosStatus = aConfig.IncomingQOS().ConfigOptionStatus();
       
   422 	const TL2CapConfigurationOptionGroupBase::TOptionConfigStatus fecStatus = aConfig.FecNegotiator().OutgoingConfigOptionStatus();
       
   423 
       
   424 	__ASSERT_DEBUG(isUnacceptableParams ||
       
   425 					(mtuStatus != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding &&
       
   426 					 flushToStatus != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding &&
       
   427 					 qosStatus != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding &&
       
   428 					 fecStatus != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding),
       
   429 				   Panic(EL2CapConstructingPositiveConfigResponseWithUnresolvedOptionStatus));
       
   430 
       
   431 	// The BT spec (sec 5.1) specifies that positive Config Responses will always
       
   432 	// contain the MTU that is to be used on the channel.
       
   433 	if (!(isUnacceptableParams && mtuStatus != TL2CapConfigurationOptionGroupBase::EOptionConfigFailed))
       
   434 		{
       
   435 		TRAP(rerr, currentCommandIndex += AddMtuOptionL(aConfig.OutgoingMTU().Preferred().MTU(), 
       
   436 											aOptionOffset + currentCommandIndex, 
       
   437 											aOptions));
       
   438 		}
       
   439 
       
   440 	if (rerr == KErrNone &&
       
   441 		((isUnacceptableParams && flushToStatus == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed) ||
       
   442 		 (!isUnacceptableParams && aConfig.IncomingFlushTimeout().NeedToIncludeInPositiveConfigResponse())))
       
   443 		{
       
   444 		TRAP(rerr, currentCommandIndex += AddFlushOptionL(aConfig.IncomingFlushTimeout().Preferred().FlushTimeoutDuration(), 
       
   445 											aOptionOffset + currentCommandIndex, 
       
   446 											aOptions));
       
   447 		}
       
   448 
       
   449 	if (rerr == KErrNone &&
       
   450 		((isUnacceptableParams && qosStatus == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed) ||
       
   451 		 (!isUnacceptableParams && aConfig.IncomingQOS().NeedToIncludeInPositiveConfigResponse())))
       
   452 		{
       
   453 		TRAP(rerr, currentCommandIndex += AddQosOptionL(aConfig.IncomingQOS().Preferred(), 
       
   454 											aOptionOffset + currentCommandIndex,
       
   455 											aOptions));
       
   456 		}
       
   457 
       
   458 	if (rerr == KErrNone &&
       
   459 		((isUnacceptableParams && fecStatus == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed) ||
       
   460 		 (!isUnacceptableParams && aConfig.FecNegotiator().NeedToIncludeInPositiveConfigResponse())))
       
   461 		{
       
   462 		TRAP(rerr, currentCommandIndex += AddFecOptionL(aConfig.FecNegotiator().OutgoingPreferred(),
       
   463 											aOptionOffset + currentCommandIndex,
       
   464 											aOptions));
       
   465 		}
       
   466 
       
   467 	return rerr;
       
   468 	}
       
   469 
       
   470 /*static*/ TInt TL2CapConfigParamOptions::AddConfigRequestOptions(CL2CapChannelConfig& aConfig, TUint8 aOptionOffset, RMBufChain& aOptions)
       
   471 	{
       
   472 	LOG_STATIC_FUNC
       
   473 	TInt rerr = KErrNone;
       
   474 	TInt currentCommandIndex = 0;
       
   475 	
       
   476 	// Config Request parameters.
       
   477 	
       
   478 	if(aConfig.IncomingMTU().ConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigComplete && rerr == KErrNone)
       
   479 		{		
       
   480 		TRAP(rerr, currentCommandIndex += AddMtuOptionL(aConfig.IncomingMTU().Preferred().MTU(), 
       
   481 											aOptionOffset + currentCommandIndex, 
       
   482 											aOptions));
       
   483 		}
       
   484 
       
   485 	if(aConfig.OutgoingFlushTimeout().ConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigComplete && rerr == KErrNone)
       
   486 		{		
       
   487 		TRAP(rerr, currentCommandIndex += AddFlushOptionL(aConfig.OutgoingFlushTimeout().Preferred().FlushTimeoutDuration(), 
       
   488 											  aOptionOffset + currentCommandIndex, 
       
   489 											  aOptions));
       
   490 		}
       
   491 
       
   492 	if(aConfig.OutgoingQOS().ConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigComplete && rerr == KErrNone)
       
   493 		{			
       
   494 		TRAP(rerr, currentCommandIndex += AddQosOptionL(aConfig.OutgoingQOS().Preferred(), 
       
   495 											aOptionOffset + currentCommandIndex,
       
   496 											aOptions));
       
   497 		}
       
   498 		
       
   499 	if(aConfig.FecNegotiator().IncomingConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigComplete && rerr == KErrNone)
       
   500 		{
       
   501 		TRAP(rerr, currentCommandIndex += AddFecOptionL(aConfig.FecNegotiator().IncomingPreferred(),
       
   502 											aOptionOffset + currentCommandIndex,
       
   503 											aOptions));
       
   504 		}
       
   505 
       
   506 	return rerr;		
       
   507 	}
       
   508 
       
   509 /* static */ TInt TL2CapConfigParamOptions::AddMtuOptionL(TInt16 aMtu, TUint8 aOptionOffset, RMBufChain& aOptions)
       
   510 	{
       
   511 	LOG_STATIC_FUNC
       
   512 	aOptions.AppendL(KOptionHeaderLength + KMTUOptionDataLen);
       
   513 	
       
   514 	TBuf8<KOptionHeaderLength + KMTUOptionDataLen> mtuBuf(KOptionHeaderLength + KMTUOptionDataLen);
       
   515 	
       
   516 	mtuBuf[KTypeOffset] = EConfigOptionTypeMTU;
       
   517 	mtuBuf[KLengthOffset] = KMTUOptionDataLen;
       
   518 	LittleEndian::Put16(&mtuBuf[KDataOffset], aMtu);
       
   519 
       
   520 	aOptions.CopyIn(mtuBuf, aOptionOffset);
       
   521 	
       
   522 	return KOptionHeaderLength + KMTUOptionDataLen;
       
   523 	}
       
   524 	
       
   525 /* static */ TInt TL2CapConfigParamOptions::AddFlushOptionL(TInt16 aFlushTimeout, TUint8 aOptionOffset, RMBufChain& aOptions)
       
   526 	{
       
   527 	LOG_STATIC_FUNC
       
   528 	aOptions.AppendL(KOptionHeaderLength + KFlushOptionDataLen);
       
   529 	
       
   530 	TBuf8<KOptionHeaderLength + KFlushOptionDataLen> flushBuf(KOptionHeaderLength + KFlushOptionDataLen);
       
   531 
       
   532 	flushBuf[KTypeOffset] = EConfigOptionTypeFlushTimeoutDuration;
       
   533 	flushBuf[KLengthOffset] = KFlushOptionDataLen;
       
   534 	LittleEndian::Put16(&flushBuf[KDataOffset], aFlushTimeout);
       
   535 
       
   536 	aOptions.CopyIn(flushBuf, aOptionOffset);
       
   537 	
       
   538 	return KOptionHeaderLength + KFlushOptionDataLen;
       
   539 	}
       
   540 	
       
   541 /* static */ TInt TL2CapConfigParamOptions::AddQosOptionL(const TQualityOfServiceOption& aQosOption, TUint8 aOptionOffset, RMBufChain& aOptions)
       
   542 	{
       
   543 	LOG_STATIC_FUNC
       
   544 	aOptions.AppendL(KOptionHeaderLength + KQOSOptionDataLen);
       
   545 	
       
   546 	TBuf8<KOptionHeaderLength + KQOSOptionDataLen> qosBuf(KOptionHeaderLength + KQOSOptionDataLen);
       
   547 
       
   548 	qosBuf[KTypeOffset] = EConfigOptionTypeQOS;
       
   549 	qosBuf[KLengthOffset] = KQOSOptionDataLen;
       
   550 	qosBuf[KDataOffset] = 0;
       
   551 
       
   552 	// Now insert each of the QOS options
       
   553 	qosBuf[KDataOffset + KQOSServiceTypeOffset] = static_cast<TUint8>(aQosOption.ServiceType());
       
   554 	LittleEndian::Put32(&qosBuf[KDataOffset + KTokenRateOffset], aQosOption.TokenRate());	
       
   555 	LittleEndian::Put32(&qosBuf[KDataOffset + KTokenBucketSizeOffset], aQosOption.TokenBucketSize());	
       
   556 	LittleEndian::Put32(&qosBuf[KDataOffset + KPeakBandwidthOffset], aQosOption.PeakBandwidth());	
       
   557 	LittleEndian::Put32(&qosBuf[KDataOffset + KLatencyOffset], aQosOption.Latency());	
       
   558 	LittleEndian::Put32(&qosBuf[KDataOffset + KDelayVariationOffset], aQosOption.DelayVariation());	
       
   559 	
       
   560 	aOptions.CopyIn(qosBuf, aOptionOffset);	
       
   561 	
       
   562 	return KOptionHeaderLength + KQOSOptionDataLen;
       
   563 	}
       
   564 
       
   565 /* static */ TInt TL2CapConfigParamOptions::AddFecOptionL(const TRetransmissionAndFlowControlOption& aFecOption, TUint8 aOptionOffset, RMBufChain& aOptions)
       
   566 	{
       
   567 	LOG_STATIC_FUNC
       
   568 	aOptions.AppendL(KOptionHeaderLength + KFECOptionDataLen);
       
   569 	
       
   570 	TBuf8<KOptionHeaderLength + KFECOptionDataLen> fecBuf(KOptionHeaderLength + KFECOptionDataLen);
       
   571 
       
   572 	fecBuf[KTypeOffset] = EConfigOptionTypeRTxAndFEC;	
       
   573 	fecBuf[KLengthOffset] = KFECOptionDataLen;
       
   574 	
       
   575 	fecBuf[KDataOffset] = aFecOption.LinkModeAsUnsignedByte();	
       
   576 	fecBuf[KDataOffset + KTxWindowSizeOffset] = aFecOption.TxWindowSize();	
       
   577 	fecBuf[KDataOffset + KMaxTransmitOffset] = aFecOption.MaxTransmit();	
       
   578 	LittleEndian::Put16(&fecBuf[KDataOffset + KRetransmissionTimeoutOffset], aFecOption.RetransmissionTimeout());	
       
   579 	LittleEndian::Put16(&fecBuf[KDataOffset + KMonitorTimeoutOffset], aFecOption.MonitorTimeout());	
       
   580 	LittleEndian::Put16(&fecBuf[KDataOffset + KMaximumPDUSizeOffset], aFecOption.MaximumPDUSize());	
       
   581 
       
   582 	aOptions.CopyIn(fecBuf, aOptionOffset);
       
   583 	
       
   584 	return KOptionHeaderLength + KFECOptionDataLen;
       
   585 	}
       
   586 
       
   587 /* static */ TBool TL2CapConfigParamOptions::VerifyOptionsStructure(TUint8 aOptionOffset, const RMBufChain& aCommand)
       
   588 	{
       
   589 	LOG_STATIC_FUNC
       
   590 	TUint8 optionDataLen = 0;
       
   591 	TInt startOfCurrentOption = aOptionOffset;
       
   592 	TInt commandLength = aCommand.Length();
       
   593 	TBuf8<KOptionHeaderLength> headerBuf(KOptionHeaderLength);
       
   594 
       
   595 	TBool valid = ETrue;
       
   596 	// Parse the command options.  Ensure that there is at least an option header
       
   597 	// left to read.
       
   598 	while(startOfCurrentOption + KOptionHeaderLength <= commandLength && valid)
       
   599 		{
       
   600 		aCommand.CopyOut(headerBuf, startOfCurrentOption);
       
   601 		
       
   602 		TUint8 optionType = headerBuf[KTypeOffset];
       
   603 		optionDataLen = headerBuf[KLengthOffset];
       
   604 
       
   605 		// Switch on the option type. Option type could have hint bit set, remove it
       
   606 		switch(optionType & ~KOptionTypeIsHintMask)
       
   607 			{
       
   608 			case EConfigOptionTypeMTU:
       
   609 				if(optionDataLen != KMTUOptionDataLen || 
       
   610 				   startOfCurrentOption + KOptionHeaderLength + optionDataLen > commandLength)
       
   611 					{
       
   612 					valid = EFalse;
       
   613 					}
       
   614 				break;
       
   615 
       
   616 			case EConfigOptionTypeFlushTimeoutDuration:
       
   617 				if(optionDataLen != KFlushOptionDataLen || 
       
   618 				   startOfCurrentOption + KOptionHeaderLength + optionDataLen > commandLength)
       
   619 					{
       
   620 					valid = EFalse;
       
   621 					}
       
   622 				break;
       
   623 				
       
   624 			case EConfigOptionTypeQOS:
       
   625 				if(optionDataLen != KQOSOptionDataLen || 
       
   626 				   startOfCurrentOption + KOptionHeaderLength + optionDataLen > commandLength)
       
   627 					{
       
   628 					valid = EFalse;
       
   629 					}
       
   630 				break;
       
   631 			
       
   632 			case EConfigOptionTypeRTxAndFEC:
       
   633 				if(optionDataLen != KFECOptionDataLen || 
       
   634 				   startOfCurrentOption + KOptionHeaderLength + optionDataLen > commandLength)
       
   635 					{
       
   636 					valid = EFalse;
       
   637 					}
       
   638 				break;
       
   639 
       
   640 			case EConfigOptionTypeFcs:
       
   641 				if(optionDataLen != KFcsOptionDataLen || 
       
   642 			       startOfCurrentOption + KOptionHeaderLength + optionDataLen > commandLength)
       
   643 					{
       
   644 					valid = EFalse;
       
   645 					}
       
   646 				break;
       
   647 				
       
   648 			default:
       
   649 				// Store the unknown options into the buffer argument.
       
   650 				if(startOfCurrentOption + KOptionHeaderLength + optionDataLen > commandLength)
       
   651 					{
       
   652 					// The option is not correctly formatted.
       
   653 					valid = EFalse;
       
   654 					}
       
   655 				break;
       
   656 			};
       
   657 		// Move to the next option.
       
   658 		startOfCurrentOption += (optionDataLen + KOptionHeaderLength);
       
   659 		}
       
   660 
       
   661 	if(startOfCurrentOption != commandLength)
       
   662 		{
       
   663 		// Spurious bytes
       
   664 		valid = EFalse;
       
   665 		}
       
   666 
       
   667 	return valid;
       
   668 	}
       
   669