bluetooth/btstack/l2cap/l2capLinkSignalHandler.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 "l2capLinkSignalHandler.h"
       
    19 
       
    20 #include "l2capSAPSignalHandler.h"
       
    21 
       
    22 #include "l2capSigPacketEcho.h"
       
    23 #include "l2capSigPacketInformation.h"
       
    24 #include "l2capSigPacketConnection.h"
       
    25 #include "l2capSigPacketConfigure.h"
       
    26 #include "l2capSigPacketDisconnection.h"
       
    27 #include "l2capSigPacketCommandReject.h"
       
    28 
       
    29 #include "l2capCommand.h"
       
    30 
       
    31 #include "l2capMuxController.h"
       
    32 #include "l2signalmgr.h"
       
    33 
       
    34 #include "l2capEntityConfig.h"
       
    35 
       
    36 #include "l2util.h"
       
    37 
       
    38 #ifdef __FLOG_ACTIVE
       
    39 _LIT8(KLogComponent, LOG_COMPONENT_L2CAP);
       
    40 #endif
       
    41 
       
    42 CL2CapLinkSignalHandler* CL2CapLinkSignalHandler::NewL(CL2CAPMux* aMuxer)
       
    43 	{
       
    44 	LOG_STATIC_FUNC
       
    45  	CL2CapLinkSignalHandler* linkSigHandler=new (ELeave) CL2CapLinkSignalHandler(aMuxer);
       
    46 	CleanupStack::PushL(linkSigHandler);
       
    47 	linkSigHandler->ConstructL();
       
    48 	CleanupStack::Pop();
       
    49 	return linkSigHandler;
       
    50  	}
       
    51 
       
    52 CL2CapLinkSignalHandler::~CL2CapLinkSignalHandler()
       
    53 	{
       
    54 	LOG_FUNC
       
    55 	DeleteCommands(iPendingCommands);
       
    56 	DeleteCommands(iCommandsAwaitingResponse);
       
    57 	}
       
    58 	
       
    59 
       
    60 
       
    61 void CL2CapLinkSignalHandler::ConstructL()
       
    62 	{
       
    63 	LOG_FUNC
       
    64 	}
       
    65 
       
    66 // Disable warning WINS 4355: 'this' : used in base member initializer list
       
    67 // This will not cause any problems in this usage and is preferable to the use of a
       
    68 // non-owned pointer.
       
    69 #pragma warning (disable: 4355)
       
    70 CL2CapLinkSignalHandler::CL2CapLinkSignalHandler(CL2CAPMux* aMuxer)
       
    71  : CL2CapSignalHandler(aMuxer),
       
    72    iPeerL2CapEntityConfig(*this),
       
    73    iSigMTU(KL2MinMTU)
       
    74 	{
       
    75 	LOG_FUNC
       
    76 	}
       
    77 #pragma warning (default: 4355)
       
    78 
       
    79 
       
    80 TBool CL2CapLinkSignalHandler::HandleConnectionRequest(HConnectionRequest* aConnectionRequest)
       
    81 	{
       
    82 	LOG_FUNC
       
    83 	const TL2CAPPort scid = aConnectionRequest->SourceCID(); 
       
    84 	const TInt8 id = aConnectionRequest->ID();
       
    85 	TBool scidValid = ETrue;
       
    86 
       
    87 	if(scid < KL2CapDynamicCIDStart)	   
       
    88 		{
       
    89 		scidValid = EFalse;
       
    90 		}
       
    91 	else
       
    92 		{
       
    93 		CL2CapSAPSignalHandler* listeningSH = iMuxer->MuxController().FindListeningSignalHandler(aConnectionRequest->PSM());
       
    94 		if(!listeningSH)
       
    95 			{
       
    96 			// Create a Connection Response Command
       
    97 			HL2CapCommand* command = HConnectionResponse::New(id, 0, scid, EConnectPSMNotSupported);
       
    98 			if(command)
       
    99 				{
       
   100 				AddToOutgoingQueue(command);
       
   101 				}
       
   102 			}
       
   103 		else
       
   104 			{
       
   105 			// Does given CID already exist in the queue?
       
   106 			CL2CapSAPSignalHandler* sh = iMuxer->GetSignalHandlerWithRemoteCID(scid);
       
   107 			if (sh)
       
   108 				{
       
   109 				// ... it does: check whether the Connection Request is a retransmission
       
   110 				// (and retransmit the response if so), or a new command (illegal - send CmdRej).
       
   111 				if (!sh->IsDuplicateCommandRequest(aConnectionRequest))
       
   112 					{
       
   113 					LOG1(_L("Received a new Connection Request for an existing CID: 0x%04x"), scid)
       
   114 					scidValid = EFalse;
       
   115 					}
       
   116 				}
       
   117 			else
       
   118 				{
       
   119 				LOG1(_L("Remote CID (0x%04x) is free"),scid)
       
   120 				// Usual case, remote CID is free.
       
   121 				TInt err = listeningSH->PassiveConnectionRequest(iMuxer->RemoteBTAddr(), aConnectionRequest);
       
   122 				if(err != KErrNone)
       
   123 					{
       
   124 					HL2CapCommand* command = HConnectionResponse::New(id, 0, scid, EConnectPSMNotSupported);
       
   125 					if(command)
       
   126 						{
       
   127 						AddToOutgoingQueue(command);
       
   128 						}
       
   129 					}
       
   130 				// If the command could not be created the connection will fail in the
       
   131 				// signalling state machine.
       
   132 				}
       
   133 			}
       
   134 		}
       
   135 
       
   136 	if (!scidValid)
       
   137 		{
       
   138 		TL2CAPCommandRejectData reason;
       
   139 		reason.iReason = EInvalidCID;
       
   140 		reason.iLocalEndpoint = 0;
       
   141 		reason.iRemoteEndpoint = scid;
       
   142 		reason.iMTUExceeded = 0;
       
   143 		
       
   144 		HL2CapCommand* command = HCommandReject::New(reason, id);
       
   145 		if(command)
       
   146 			{
       
   147 			AddToOutgoingQueue(command);
       
   148 			}
       
   149 		}
       
   150 
       
   151 	// Always return true.  This is the only signal handler 
       
   152 	// that can process this command.
       
   153 	return ETrue;
       
   154 	}
       
   155 
       
   156 TInt CL2CapLinkSignalHandler::ConstructEchoRequest(const TDes8* aData, MEchoResponseHandler& aEchoResponseHandler)
       
   157 	{
       
   158 	LOG_FUNC
       
   159 	TInt rerr = KErrNone;
       
   160 	HEchoRequest* command = NULL;
       
   161 	
       
   162 	if(aData)
       
   163 		{
       
   164 		RMBufChain data;
       
   165 		TRAP(rerr, data.CreateL(*aData));
       
   166 		if(rerr == KErrNone)
       
   167 			{
       
   168 			command = HEchoRequest::New(data, CurrentRTXTimerDuration(HL2CapCommand::KDefaultRTXTimerDuration));
       
   169 			}
       
   170 		}
       
   171 	else
       
   172 		{
       
   173 		command = HEchoRequest::New();
       
   174 		}
       
   175 	
       
   176 	if(rerr == KErrNone)
       
   177 		{
       
   178 		if(command)
       
   179 			{
       
   180 			command->SetEchoResponseHandler(aEchoResponseHandler);
       
   181 			AddToOutgoingQueue(command);
       
   182 			}
       
   183 		else
       
   184 			{
       
   185 			rerr = KErrNoMemory;
       
   186 			}
       
   187 		}
       
   188 	return rerr;
       
   189 	}
       
   190 
       
   191 void CL2CapLinkSignalHandler::DeregisterOutstandingEchoRequests(MEchoResponseHandler& aEchoResponseHandler)
       
   192 	{
       
   193 	LOG_FUNC
       
   194 	// Find any Echo Request and if the calling reference matches set
       
   195 	// it to NULL.
       
   196 	HL2CapCommand* l2CapCommand;
       
   197 
       
   198 	TDblQueIter<HL2CapCommand> iter(iCommandsAwaitingResponse);
       
   199 	while((l2CapCommand = iter++) != NULL)
       
   200 		{
       
   201 		if(l2CapCommand->Code() == EEchoRequest)
       
   202 			{
       
   203 			HEchoRequest* request = static_cast<HEchoRequest*>(l2CapCommand);
       
   204 			if(request->EchoResponseHandler() == &aEchoResponseHandler)
       
   205 				{
       
   206 				// Found a matching request - there can only be one so stop searching.
       
   207 				request->RemoveEchoResponseHandler();
       
   208 				break;
       
   209 				}
       
   210 			}
       
   211 		}
       
   212 	}
       
   213 
       
   214 TBool CL2CapLinkSignalHandler::HandleEchoResponse(HEchoResponse* aEchoResponse)
       
   215 	{
       
   216 	LOG_FUNC
       
   217 	// Check that the Echo Response has been requested.
       
   218 	HL2CapCommand* requestCommand = FindMatchingOutstandingRequest(EEchoRequest, aEchoResponse->ID());
       
   219 	if(requestCommand)
       
   220 		{
       
   221 		HEchoRequest* request = static_cast<HEchoRequest*>(requestCommand);
       
   222 		if(request->EchoResponseHandler())
       
   223 			{
       
   224 			RMBufChain data;
       
   225 			HBufC8* echoDataBuf = NULL;
       
   226 			if(aEchoResponse->GetData(data) == KErrNone)
       
   227 				{
       
   228 				echoDataBuf = HBufC8::New(data.Length());	
       
   229 				if(echoDataBuf)
       
   230 					{		
       
   231 					const TDes8& bufc = echoDataBuf->Des();
       
   232 					TDes8& echoData = const_cast<TDes8&>(bufc);
       
   233 					echoData.SetMax();
       
   234 					data.CopyOut(echoData);
       
   235 					}
       
   236 				data.Free();
       
   237 				}
       
   238 			
       
   239 			iMuxer->EchoResponseReceived(echoDataBuf, *request->EchoResponseHandler());
       
   240 			}
       
   241 		// Delete the request.
       
   242 		delete requestCommand;
       
   243 		}
       
   244 	// If the response does not have an outstanding request drop
       
   245 	// the command silently.  Always return true, this command
       
   246 	// can only be for the link signal handler.
       
   247 	return ETrue;
       
   248 	}
       
   249 
       
   250 TBool CL2CapLinkSignalHandler::HandleEchoRequest(HEchoRequest* aEchoRequest) //Incoming
       
   251 	{
       
   252 	LOG_FUNC
       
   253 	//1. Create a Echo Response Command
       
   254 	HL2CapCommand* command = HEchoResponse::New(aEchoRequest->ID());
       
   255 
       
   256 	//2. Add to the list of outgoing commands
       
   257 	if(command)
       
   258 		{
       
   259 		AddToOutgoingQueue(command);
       
   260 		}
       
   261 	return ETrue;
       
   262 	}	
       
   263 	
       
   264 TInt CL2CapLinkSignalHandler::ConstructInformationRequest(TInfoType aInfoType)
       
   265 	{
       
   266 	LOG_FUNC
       
   267 	TInt rerr = KErrNone;
       
   268 
       
   269 	//1. Create a ConnectionRequest Command
       
   270 	HL2CapCommand* command = HInformationRequest::New(aInfoType, CurrentRTXTimerDuration(HL2CapCommand::KDefaultRTXTimerDuration));
       
   271 	if(command)
       
   272 		{
       
   273 		AddToOutgoingQueue(command);
       
   274 		}
       
   275 	else
       
   276 		{
       
   277 		rerr = KErrNoMemory;
       
   278 		}
       
   279 	return rerr;
       
   280 	}	
       
   281 	
       
   282 TBool CL2CapLinkSignalHandler::HandleInformationRequest(HInformationRequest* aInformationRequest)
       
   283 	{
       
   284 	LOG_FUNC
       
   285 	// The peer is requesting the L2CAP entities capabilities.
       
   286 	switch(aInformationRequest->InfoType())
       
   287 		{
       
   288 		case EExtendedFeaturesSupported:
       
   289 			{
       
   290 			TUint32 extendedFeatures = KL2CAPExtendedFeaturesSupported;
       
   291 
       
   292 			HL2CapCommand* command = HInformationResponse::New(EExtendedFeaturesSupported, ESuccess, aInformationRequest->ID(), extendedFeatures);
       
   293 			if(command)
       
   294 				{
       
   295 				// Add to the list of outgoing commands
       
   296 				AddToOutgoingQueue(command);	
       
   297 				}
       
   298 			// If the command could not be created the connection will fail in the
       
   299 			// signalling state machine.
       
   300 			break;
       
   301 			}
       
   302 
       
   303 		// If the info requested is Connectionless MTU or a info type that
       
   304 		// is not recognised, return a response with result code 'not supported'.
       
   305 		case EConnectionlessMTU:
       
   306 		default:
       
   307 			{
       
   308 			//Return InfoType and Not supported
       
   309 			HL2CapCommand* command = HInformationResponse::New(aInformationRequest->InfoType(), 
       
   310 			                                                   ENotsupported, 
       
   311 			                                                   aInformationRequest->ID());
       
   312 			if(command)
       
   313 				{
       
   314 				// Add to the list of outgoing commands
       
   315 				AddToOutgoingQueue(command);	
       
   316 				}
       
   317 			// If the command could not be created the connection will fail in the
       
   318 			// signalling state machine.
       
   319 			break;
       
   320 			}
       
   321 		};
       
   322 
       
   323 	//This should not occur as it should be handled by derived classes. 
       
   324 	return(ETrue);
       
   325 	}
       
   326 
       
   327 TBool CL2CapLinkSignalHandler::HandleInformationResponse(HInformationResponse* aInformationResponse)
       
   328 	{
       
   329 	LOG_FUNC
       
   330 	// Check that the Information Response has been requested.
       
   331 	HL2CapCommand* requestCommand = FindMatchingOutstandingRequest(EInformationRequest, aInformationResponse->ID());
       
   332 	if(requestCommand)
       
   333 		{
       
   334 		HInformationRequest* req = static_cast<HInformationRequest*>(requestCommand);
       
   335 		// The Info Type in the response should match that in the 
       
   336 		// request.
       
   337 		if(req->InfoType() == aInformationResponse->InfoType())
       
   338 			{
       
   339 			switch(aInformationResponse->InfoType())
       
   340 				{
       
   341 				case EExtendedFeaturesSupported:
       
   342 					if(aInformationResponse->Result() == ESuccess)
       
   343 						{
       
   344 						iPeerL2CapEntityConfig.UpdatePeerL2CapSupportedFeatures(aInformationResponse->RemoteExtendedFeatureMask());
       
   345 						}
       
   346 					else
       
   347 						{
       
   348 						// The result was a failure.  Set the supported
       
   349 						// features to the default of not supported.
       
   350 						iPeerL2CapEntityConfig.UpdatePeerL2CapSupportedFeatures(TL2CapEntityInfo());
       
   351 						}
       
   352 					iMuxer->L2CapEntityConfigUpdated();
       
   353 					break;
       
   354 					
       
   355 				default:
       
   356 					break;
       
   357 				};
       
   358 			}
       
   359 		else
       
   360 			{
       
   361 			// The request and response info types don't match.  If the request
       
   362 			// was for extended features, [for the sake of interop] assume that
       
   363 			// no extended features are supported by the peer device.
       
   364 			if(req->InfoType() == EExtendedFeaturesSupported)
       
   365 				{
       
   366 				iPeerL2CapEntityConfig.UpdatePeerL2CapSupportedFeatures(TL2CapEntityInfo());
       
   367 				iMuxer->L2CapEntityConfigUpdated();
       
   368 				}
       
   369 			}
       
   370 					
       
   371 		// Delete the request.
       
   372 		delete requestCommand;
       
   373 		}
       
   374 	// If the response does not have an outstanding request drop
       
   375 	// the command silently.  Always return true, this command
       
   376 	// can only be for the link signal handler.
       
   377 	return ETrue;
       
   378 	}
       
   379 
       
   380 TBool CL2CapLinkSignalHandler::HandleCommandReject(HCommandReject* aCommandReject)
       
   381 	{
       
   382 	LOG_FUNC
       
   383 	// Process the incoming command reject data
       
   384 	TL2CAPCommandRejectData rejectData;
       
   385 	
       
   386 	if (aCommandReject->RejectData(rejectData) != KErrNone) 
       
   387 		{
       
   388 		LOG(_L("CL2CapLinkSignalHandler::HandleCommandReject - reject data could not be parsed"));
       
   389 		// Couldn't parse the reject data, but we've got no-one to
       
   390 		// pass handling this on to, so we have to say we've processed
       
   391 		// it.
       
   392 		return ETrue;
       
   393 		}
       
   394 
       
   395 	LOG1(_L("CL2CapLinkSignalHandler::HandleCommandReject - reject data: reason %d"), rejectData.iReason);
       
   396 		
       
   397 	switch(rejectData.iReason)
       
   398 		{
       
   399 		case ECommandNotUnderstood:
       
   400 			{
       
   401 			// The peer does not recognise a command we have sent.
       
   402 			// Check if the outstanding request is causing the issue.
       
   403 			HL2CapCommand* requestCommand = FindMatchingOutstandingRequest(EMatchAnyL2CAPRequest, aCommandReject->ID());
       
   404 			if(requestCommand)
       
   405 				{
       
   406 				// This is a work around to allow the new stack to interop with
       
   407 				// stacks that send Command Reject in response to Information Request.
       
   408 				if(requestCommand->Code() == EInformationRequest)
       
   409 					{
       
   410 					// Set the supported features to the default of not supported.
       
   411 					iPeerL2CapEntityConfig.UpdatePeerL2CapSupportedFeatures(TL2CapEntityInfo());
       
   412 					iMuxer->L2CapEntityConfigUpdated();
       
   413 					}
       
   414 				delete requestCommand;
       
   415 				}
       
   416 			}
       
   417 			break;
       
   418 			
       
   419 		case EMTUExceeded:
       
   420 			iSigMTU = Max(rejectData.iMTUExceeded, KL2MinMTU);
       
   421 			break;
       
   422 		
       
   423 		case EInvalidCID:
       
   424 			// This handles a corner case where a Disconnect Request command 
       
   425 			// retransmission crosses over with the Response for the initial
       
   426 			// Disconnect Request.  The peer will correctly send a Command Reject
       
   427 			// for the second Disconnect Request.  This should be ignored. 
       
   428 			break;
       
   429 			
       
   430 		default:
       
   431 			break;
       
   432 		};
       
   433 					
       
   434 	return ETrue;
       
   435 	}
       
   436 
       
   437 TBool CL2CapLinkSignalHandler::HandleInvalidCommand(HInvalidCommand* aInvalidCommand)
       
   438 	{
       
   439 	LOG_FUNC
       
   440 	TL2CAPCommandRejectData reason;
       
   441 	reason.iReason = ECommandNotUnderstood;
       
   442 	// Other reject data fields are not used for Command Not Understood
       
   443 	reason.iMTUExceeded = 0;
       
   444 	reason.iLocalEndpoint = 0;
       
   445 	reason.iRemoteEndpoint = 0;
       
   446 	
       
   447 	HL2CapCommand* command = HCommandReject::New(reason, aInvalidCommand->ID());
       
   448 	if(command)
       
   449 		{
       
   450 		AddToOutgoingQueue(command);
       
   451 		}
       
   452 	
       
   453 	// The link signal handler always services invalid commands.
       
   454 	return ETrue;
       
   455 	}
       
   456 
       
   457 
       
   458 TBool CL2CapLinkSignalHandler::HandleConnectionResponse(HConnectionResponse* /*aConnectionResponse*/)
       
   459 	{
       
   460 	LOG_FUNC
       
   461 	// This command has not been handled by any of the SAP 
       
   462 	// signal handlers. It's a response so just drop it.
       
   463 	return ETrue;
       
   464 	}
       
   465 
       
   466 TBool CL2CapLinkSignalHandler::HandleConfigureRequest(HConfigureRequest* aConfigRequest)
       
   467 	{
       
   468 	LOG_FUNC
       
   469 	// This command has not been handled by any of the SAP 
       
   470 	// signal handlers.  Send a Command Reject.
       
   471 	SendInvalidCIDCommandReject(aConfigRequest->ID(),
       
   472 	                            0,
       
   473                                 aConfigRequest->DestinationCID());
       
   474 
       
   475 	return ETrue;
       
   476 	}
       
   477 
       
   478 TBool CL2CapLinkSignalHandler::HandleConfigureResponse(HConfigureResponse* /*aConfigResponse*/)	
       
   479 	{
       
   480 	LOG_FUNC
       
   481 	// This command has not been handled by any of the SAP 
       
   482 	// signal handlers. It's a response so just drop it.
       
   483 	return ETrue;
       
   484 	}
       
   485 
       
   486 TBool CL2CapLinkSignalHandler::HandleDisconnectRequest(HDisconnectRequest* aDisconnectRequest)	
       
   487 	{
       
   488 	LOG_FUNC
       
   489 	// This command has not been handled by any of the SAP 
       
   490 	// signal handlers.  Send a Command Reject.
       
   491 	SendInvalidCIDCommandReject(aDisconnectRequest->ID(),
       
   492 	                            aDisconnectRequest->SourceCID(),
       
   493                                 aDisconnectRequest->DestinationCID());
       
   494 
       
   495 	return ETrue;
       
   496 	}
       
   497 
       
   498 TBool CL2CapLinkSignalHandler::HandleDisconnectResponse(HDisconnectResponse* /*aDisconnectResponse*/)	
       
   499 	{
       
   500 	LOG_FUNC
       
   501 	// This command has not been handled by any of the SAP 
       
   502 	// signal handlers. It's a response so just drop it.
       
   503 	return ETrue;
       
   504 	}
       
   505 
       
   506 void CL2CapLinkSignalHandler::PendingCommandsDrained()
       
   507 	{
       
   508 	LOG_FUNC
       
   509 	// No action is required here.
       
   510 	}
       
   511 	
       
   512 // HIncomingSAPSigPDUHandler Interface Definition.
       
   513 void CL2CapLinkSignalHandler::LinkUp()
       
   514 	{
       
   515 	LOG_FUNC
       
   516 	// No action required from the LinkSignalHandler when the link is established.
       
   517 	}
       
   518 
       
   519 void CL2CapLinkSignalHandler::Error(TInt /*aErrorCode*/, MSocketNotify::TOperationBitmasks /*aErrorAction*/)
       
   520 	{
       
   521 	LOG_FUNC
       
   522 	HandleLinkError();
       
   523 	}
       
   524 	
       
   525 void CL2CapLinkSignalHandler::CommandResponseFailure(HL2CapCommand* aCommand)
       
   526 	{
       
   527 	LOG_FUNC
       
   528 	switch(aCommand->Code())
       
   529 		{
       
   530 		case EInformationRequest:
       
   531 			//For IOP We set extended feature to basic if there is no reply for info request.
       
   532 			iPeerL2CapEntityConfig.UpdatePeerL2CapSupportedFeatures(TL2CapEntityInfo());
       
   533 			iMuxer->L2CapEntityConfigUpdated();
       
   534 			break;
       
   535 			
       
   536 		default:
       
   537 			iMuxer->ErrorAllSignalHandlers(KErrL2CAPRequestTimeout);
       
   538 			break;
       
   539 		}
       
   540 	
       
   541 	delete aCommand;
       
   542 	}
       
   543 	
       
   544 void CL2CapSignalHandler::PendingCommandsDrained()
       
   545 	{
       
   546 	LOG_FUNC
       
   547 	// Currently no action is required by the link signal handler.
       
   548 	}
       
   549 
       
   550 
       
   551 
       
   552