bluetooth/btstack/l2cap/l2capSignalHandler.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 // Base class for implementation of signalling handlers.  This class is able to sort incoming CFramePDUs and 
       
    15 // queue outgoing l2cap commands. This class can be derived by classes wanting to handle subsets of the 
       
    16 // signalling commands.
       
    17 // 
       
    18 //
       
    19 
       
    20 /**
       
    21  @file
       
    22  @internalComponent
       
    23 */
       
    24 
       
    25 #include <bluetooth/logger.h>
       
    26 
       
    27 #include "l2capSignalHandler.h"
       
    28 
       
    29 #include "l2capCommand.h"
       
    30 #include "l2signalmgr.h"
       
    31 
       
    32 #include "l2capSigPacketCommandReject.h"
       
    33 
       
    34 #include "l2util.h"
       
    35 #include "L2CapDebugControlInterface.h"
       
    36 
       
    37 #ifdef __FLOG_ACTIVE
       
    38 _LIT8(KLogComponent, LOG_COMPONENT_L2CAP);
       
    39 #endif
       
    40 
       
    41 //Constructor as used by the link signal handler
       
    42 CL2CapSignalHandler::CL2CapSignalHandler(CL2CAPMux* aMuxer)
       
    43  : iMuxer(aMuxer),
       
    44    iDrainPendingCommands(EFalse),
       
    45    iPendingCommands(_FOFF(HL2CapCommand, iLink)),
       
    46    iCommandsAwaitingResponse(_FOFF(HL2CapCommand, iLink)),
       
    47    iSentResponses(_FOFF(HL2CapCommand, iLink))
       
    48 	{
       
    49 	LOG_FUNC
       
    50 	L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::ESigHandlers,
       
    51 	                             L2capDebugInfo::EAllocated));	
       
    52 	}
       
    53 
       
    54 CL2CapSignalHandler::~CL2CapSignalHandler()
       
    55 /**
       
    56 	Destruct the signal handler.
       
    57 **/
       
    58 	{
       
    59 	LOG_FUNC
       
    60 	__ASSERT_DEBUG(iPendingCommands.IsEmpty(), Panic(EL2CAPSigHandlerDeletedWithResources));
       
    61 	__ASSERT_DEBUG(iCommandsAwaitingResponse.IsEmpty(), Panic(EL2CAPSigHandlerDeletedWithResources));
       
    62 
       
    63 	HL2CapCommand *cmd = NULL;
       
    64 	TDblQueIter<HL2CapCommand> responseIter(iSentResponses);
       
    65 	responseIter.SetToFirst();
       
    66 	while((cmd = responseIter++) != NULL)
       
    67 		{
       
    68 		delete cmd;
       
    69 		}
       
    70 
       
    71 	L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::ESigHandlers,
       
    72 	                             L2capDebugInfo::EDeleted));
       
    73 	}
       
    74 
       
    75 // Returns a signalling pdu awaiting transmission (might contain more than one L2CAP Command)
       
    76 HL2CapPDU* CL2CapSignalHandler::GetPDU()
       
    77 	{
       
    78 	LOG_FUNC
       
    79 	TBool pduComplete = EFalse;
       
    80 	TBool pduValid = EFalse;
       
    81 	TInt err = KErrNone;
       
    82 	
       
    83 	HCFramePDU* pdu = NULL;
       
    84 	
       
    85 	// 1. Check whether there are any commands to send
       
    86 	if(!iPendingCommands.IsEmpty())
       
    87 		{
       
    88 		// 2. Create a new PDU to put the commands into
       
    89 		pdu = HCFramePDU::New(iMuxer->GetACLMTU());
       
    90 		
       
    91 		if(pdu)
       
    92 			{
       
    93 			TDblQueIter<HL2CapCommand> iter(iPendingCommands);
       
    94 			HL2CapCommand* cmd;
       
    95 			while((cmd = iter++) != NULL && !pduComplete)
       
    96 				{
       
    97 				// 3. Attempts to add command onto end of pdu.
       
    98 				err = pdu->AddCommand(*cmd, *iMuxer);
       
    99 
       
   100 				if(err == KErrNone)
       
   101 			 		{
       
   102 			 		// The command has been added.  Remove it from the
       
   103 			 		// pending list.
       
   104 					pduValid = ETrue;
       
   105 			 		cmd->iLink.Deque();
       
   106 			 		
       
   107 					if(cmd->IsRequest())
       
   108 						{
       
   109 						// Add this to the awaiting response queue.
       
   110 						iCommandsAwaitingResponse.AddLast(*cmd);	
       
   111 
       
   112 						// Start response timer.
       
   113 						cmd->StartRTXTimer(HL2CapCommand::ERTXTimer, *this);
       
   114 						}
       
   115 					else 
       
   116 						{
       
   117 						if(cmd->StatefulResponse())
       
   118 							{
       
   119 							iSentResponses.AddLast(*cmd);
       
   120 							}
       
   121 						else
       
   122 							{
       
   123 							delete cmd;
       
   124 							}
       
   125 						}
       
   126 					}
       
   127 				else
       
   128 					{
       
   129 					if(err == KErrCompletion)
       
   130 						{
       
   131 						// The command could not be added.  This indicates that the
       
   132 						// CFrame is full.
       
   133 						pduComplete = ETrue;
       
   134 						}
       
   135 					else
       
   136 						{
       
   137 						// A different error has occurred.  Error the signal handler.
       
   138 						Error(err, MSocketNotify::EErrorAllOperations);
       
   139 						}
       
   140 					}
       
   141 			
       
   142 			 	}
       
   143 
       
   144 			// Check if the PDU is valid, i.e., contains at least one command.
       
   145 			if(!pduValid)
       
   146 				{
       
   147 				delete pdu;
       
   148 				pdu = NULL;
       
   149 				}
       
   150 				
       
   151 			// Check if any commands are outstanding.  If so request
       
   152 			// another callback.
       
   153 			if(!iPendingCommands.IsEmpty() || iDrainPendingCommands)
       
   154 				{
       
   155 				iMuxer->PDUAvailable();
       
   156 				}
       
   157 			}
       
   158 		else
       
   159 			{
       
   160 			// A C-Frame could not be created.
       
   161 			Error(KErrNoMemory, MSocketNotify::EErrorAllOperations);
       
   162 			}
       
   163 		}
       
   164 	else
       
   165 		{
       
   166 		if(iDrainPendingCommands && iCommandsAwaitingResponse.IsEmpty())
       
   167 			{
       
   168 			// Nothing more to send and nothing to wait for. 
       
   169 			// Signal disconnect to the state machine.
       
   170 			PendingCommandsDrained();
       
   171 			}
       
   172 		}
       
   173 	return pdu;
       
   174 	}
       
   175 
       
   176 
       
   177 HL2CapCommand* CL2CapSignalHandler::FindMatchingOutstandingRequest(TUint8 aExpectedCommandCode, TUint8 aId)
       
   178 	{
       
   179 	LOG_FUNC
       
   180 	HL2CapCommand* l2CapCommand = NULL;
       
   181 	HL2CapCommand* matchingCommand = NULL;
       
   182 	
       
   183 	TDblQueIter<HL2CapCommand> iter(iCommandsAwaitingResponse);
       
   184 	while((l2CapCommand = iter++) != NULL)
       
   185 		{
       
   186 		if(l2CapCommand->ID() == aId)
       
   187 			{
       
   188 			if(l2CapCommand->Code() == aExpectedCommandCode || 
       
   189 			   (aExpectedCommandCode == EMatchAnyL2CAPRequest && l2CapCommand->IsRequest()))
       
   190 				{
       
   191 				matchingCommand = l2CapCommand;
       
   192 				break;
       
   193 				}
       
   194 			}
       
   195 		}
       
   196 	return matchingCommand;
       
   197 	}
       
   198 	
       
   199 // Incoming PDU handler.
       
   200 TBool CL2CapSignalHandler::HandleIncomingCFrame(HCFramePDU* aCFrame)
       
   201 	{
       
   202 	LOG_FUNC
       
   203 	// The C-Frame can contain many L2CAP commands.  Not all of
       
   204 	// the commands will be for a SAP signal handler.  If a
       
   205 	// command can be processed it will be removed from the
       
   206 	// C-Frame.  Any remaining commands will be offered to the
       
   207 	// other SAP signal handlers, then the whole process of
       
   208 	// offering the commands to the SAP signal handlers is
       
   209 	// repeated until no more commands can be handled by them,
       
   210 	// after which the commands are offered to the link signal
       
   211 	// handler.  Only one command is handled at a time because a
       
   212 	// Command Reject may delete a SAP signal handler, thereby
       
   213 	// rendering it ineffective at processing further commands.
       
   214 
       
   215 	HL2CapCommand* cmd = aCFrame->FirstCommand();
       
   216 	while(cmd)
       
   217 		{
       
   218 		// This could be a duplicate sent from the peer due to an RTx timer.
       
   219 		// If the original was received and is being processed discard the
       
   220 		// command.
       
   221 		if(!IsDuplicateCommandRequest(cmd))
       
   222 			{
       
   223 			if (cmd->ProcessCommand(*this))
       
   224 				{
       
   225 				return ETrue;
       
   226 				}
       
   227 			}
       
   228 		cmd = aCFrame->NextCommand();
       
   229 		}
       
   230 	return EFalse;
       
   231 	}
       
   232 
       
   233 TBool CL2CapSignalHandler::IsDuplicateCommandRequest(HL2CapCommand* aCommand)
       
   234 	{
       
   235 	LOG_FUNC
       
   236 	TBool rcode = EFalse;
       
   237 	
       
   238 	// Check if this is a duplicate still kicking about waiting to be sent
       
   239 	if(aCommand->IsRequest())
       
   240 		{
       
   241 		HL2CapCommand *response = NULL;
       
   242 		
       
   243 		TDblQueIter<HL2CapCommand> pendIter(iPendingCommands);
       
   244 		while((response = pendIter++) != NULL)
       
   245 			{
       
   246 			// Check if this matches the last peer request.
       
   247 			if(aCommand->ID() == response->ID() &&
       
   248 			   (aCommand->Code() + 1) == response->Code())
       
   249 				{
       
   250 				delete aCommand;
       
   251 				rcode = ETrue;
       
   252 				
       
   253 				break;
       
   254 				}
       
   255 			}
       
   256 		}
       
   257 		
       
   258 	// Otherwise check if this is a response we've already sent
       
   259 	if(!rcode && aCommand->IsRequest())
       
   260 		{
       
   261 		HL2CapCommand *response = NULL;
       
   262 		
       
   263 		TDblQueIter<HL2CapCommand> respIter(iSentResponses);
       
   264 		while((response = respIter++) != NULL)
       
   265 			{
       
   266 			// Check if this matches the last peer request.
       
   267 			if(aCommand->ID() == response->ID() &&
       
   268 			   (aCommand->Code() + 1) == response->Code())
       
   269 				{			
       
   270 				// Re-send the stored response.
       
   271 				response->iLink.Deque();
       
   272 				AddToOutgoingQueue(response);
       
   273 
       
   274 				delete aCommand;
       
   275 				rcode = ETrue;
       
   276 				
       
   277 				break;
       
   278 				}
       
   279 			}
       
   280 		}
       
   281 
       
   282 	return rcode;
       
   283 	}
       
   284 
       
   285 /**
       
   286 Store this command on the outgoing queue.  
       
   287 
       
   288 @pre aCommand is not already on a queue.
       
   289 @param aCommand The command to add to the queue.
       
   290 */
       
   291 void CL2CapSignalHandler::AddToOutgoingQueue(HL2CapCommand* aCommand)
       
   292 	{
       
   293 	LOG_FUNC
       
   294 	if(aCommand->CommandLength() <= iMuxer->SigMTU())
       
   295 		{
       
   296 		// 1. Add to the list of outgoing commands.
       
   297 		iPendingCommands.AddLast(*aCommand);
       
   298 
       
   299 		// 2. Signal to the PDU that data is available in the queue.
       
   300 		iMuxer->PDUAvailable();
       
   301 		}
       
   302 	else
       
   303 		{
       
   304 		// At present the stack will not create a command greater in 
       
   305 		// length than the minimum SigMTU.
       
   306 		__ASSERT_DEBUG(EFalse, Panic(EL2CAPAttemptToCreateCommandLongerThanSigMTU));
       
   307 		}
       
   308 	}
       
   309 
       
   310 /**
       
   311 This is called when we know the remote has finished configuring this
       
   312 channel, ie when we've received data from it.  At this point we can
       
   313 flush the queued responses.
       
   314 */
       
   315 void CL2CapSignalHandler::ChannelConfigured()
       
   316 	{
       
   317 	LOG_FUNC
       
   318 	HL2CapCommand* cmd = NULL;
       
   319 	TDblQueIter<HL2CapCommand> responseIter(iSentResponses);
       
   320 	responseIter.SetToFirst();
       
   321 	while((cmd = responseIter++) != NULL)
       
   322 		{
       
   323 		cmd->iLink.Deque();
       
   324 		delete cmd;
       
   325 		}
       
   326 	}
       
   327 
       
   328 void CL2CapSignalHandler::DrainPendingCommands()
       
   329 	{
       
   330 	LOG_FUNC
       
   331 	iDrainPendingCommands = ETrue;
       
   332 	iMuxer->PDUAvailable();
       
   333 	}
       
   334 
       
   335 void CL2CapSignalHandler::FlushPendingCommands()
       
   336 	{
       
   337 	LOG_FUNC
       
   338 	// Remove all pending commands from the outgoing queue.
       
   339 	HL2CapCommand* cmd = NULL;
       
   340 	TDblQueIter<HL2CapCommand> pendIter(iPendingCommands);
       
   341 	while((cmd = pendIter++) != NULL)
       
   342 		{
       
   343 		LOG1(_L(" -- Removing 0x%02x command"), cmd->Code());
       
   344 		delete cmd;
       
   345 		}
       
   346 	LOG(_L(" - queue flushed"));
       
   347 	}
       
   348 
       
   349 void CL2CapSignalHandler::FlushAwaitingResponseCommands()
       
   350 	{
       
   351 	LOG_FUNC
       
   352 	DeleteCommands(iCommandsAwaitingResponse);
       
   353 	}
       
   354 
       
   355 void CL2CapSignalHandler::FlushAllQueues()
       
   356 	{
       
   357 	LOG_FUNC
       
   358 	DeleteCommands(iPendingCommands);
       
   359 	DeleteCommands(iCommandsAwaitingResponse);
       
   360 	DeleteCommands(iSentResponses);
       
   361 	}
       
   362 
       
   363 void CL2CapSignalHandler::HandleLinkError()
       
   364 	{
       
   365 	LOG_FUNC
       
   366 	// An error condition has occurred on the link.  
       
   367 	// Any commands awaiting transmission,
       
   368 	// or awaiting responses can be deleted as no more PDU can
       
   369 	// be sent or received on this link.
       
   370 	HL2CapCommand* cmd = NULL;
       
   371 	FlushPendingCommands();
       
   372 	
       
   373 	TDblQueIter<HL2CapCommand> waitIter(iCommandsAwaitingResponse);
       
   374 	waitIter.SetToFirst();
       
   375 	while((cmd = waitIter++) != NULL)
       
   376 		{
       
   377 		delete cmd;
       
   378 		}
       
   379 		
       
   380 	TDblQueIter<HL2CapCommand> responseIter(iSentResponses);
       
   381 	responseIter.SetToFirst();
       
   382 	while((cmd = responseIter++) != NULL)
       
   383 		{
       
   384 		cmd->iLink.Deque();
       
   385 		delete cmd;
       
   386 		}
       
   387 	}
       
   388 	
       
   389 	
       
   390 TUint8 CL2CapSignalHandler::CurrentRTXTimerDuration(TUint8 aBaseRTXTimerDuration) const
       
   391 	{
       
   392 	LOG_FUNC
       
   393 	__ASSERT_ALWAYS(iMuxer,Panic(EL2CAPMuxerDeletedUnexpectedly));
       
   394 	
       
   395 	return iMuxer->AdjustRTXTimerForSniffMode(aBaseRTXTimerDuration);
       
   396 	}
       
   397 	
       
   398 
       
   399 // This base class does not handle any Frame types or commands.  These
       
   400 // default implementations are here to allow derived class to only specify
       
   401 // commands and frames that are handled.
       
   402 TBool CL2CapSignalHandler::HandleConnectionResponse(HConnectionResponse* /*aConnectionResponse*/)
       
   403 	{
       
   404 	LOG_FUNC
       
   405 	return EFalse;
       
   406 	}
       
   407 
       
   408 TBool CL2CapSignalHandler::HandleConnectionRequest(HConnectionRequest* /*aConnectionRequest*/)
       
   409 	{
       
   410 	LOG_FUNC
       
   411 	return EFalse;
       
   412 	}
       
   413 TBool CL2CapSignalHandler::HandleConfigureRequest(HConfigureRequest* /*aConfigRequest*/)
       
   414 	{
       
   415 	LOG_FUNC
       
   416 	return EFalse;
       
   417 	}
       
   418 
       
   419 TBool CL2CapSignalHandler::HandleConfigureResponse(HConfigureResponse* /*aConfigResponse*/)
       
   420 	{
       
   421 	LOG_FUNC
       
   422 	return EFalse;
       
   423 	}
       
   424 
       
   425 TBool CL2CapSignalHandler::HandleEchoResponse(HEchoResponse* /*aEchoResponse*/)
       
   426 	{
       
   427 	LOG_FUNC
       
   428 	return EFalse;
       
   429 	}
       
   430 
       
   431 TBool CL2CapSignalHandler::HandleEchoRequest(HEchoRequest* /*aEchoRequest*/) // Take incoming EchoRequest extract any data to form a valid Echo Response from CEchoResponse	
       
   432 	{
       
   433 	LOG_FUNC
       
   434 	return EFalse;	
       
   435 	}
       
   436 TBool CL2CapSignalHandler::HandleInformationRequest(HInformationRequest* /*aInformationRequest*/)
       
   437 	{
       
   438 	LOG_FUNC
       
   439 	return EFalse;	
       
   440 	}
       
   441 	
       
   442 TBool CL2CapSignalHandler::HandleDisconnectRequest(HDisconnectRequest* /*aDisconnectRequest*/)
       
   443 	{
       
   444 	LOG_FUNC
       
   445 	return EFalse;	
       
   446 	}
       
   447 	
       
   448 TBool CL2CapSignalHandler::HandleDisconnectResponse(HDisconnectResponse* /*aDisconnectResponse*/)
       
   449 	{
       
   450 	LOG_FUNC
       
   451 	return EFalse;	
       
   452 	}
       
   453 
       
   454 TBool CL2CapSignalHandler::HandleInformationResponse(HInformationResponse* /*aInformationResponse*/)
       
   455 	{
       
   456 	LOG_FUNC
       
   457 	return EFalse;
       
   458 	}
       
   459 	
       
   460 TBool CL2CapSignalHandler::HandleCommandReject(HCommandReject* /*aCommandReject*/)
       
   461 	{
       
   462 	LOG_FUNC
       
   463 	return EFalse;
       
   464 	}
       
   465 
       
   466 TBool CL2CapSignalHandler::HandleInvalidCommand(HInvalidCommand* /*aInvalidCommand*/)
       
   467 	{
       
   468 	LOG_FUNC
       
   469 	return EFalse;
       
   470 	}
       
   471 
       
   472 
       
   473 void CL2CapSignalHandler::SendInvalidCIDCommandReject(TUint8 aId, TL2CAPPort aSourceCID, TL2CAPPort aDestinationCID)
       
   474 	{
       
   475 	LOG_FUNC
       
   476 	TL2CAPCommandRejectData reason;
       
   477 	reason.iReason = EInvalidCID;
       
   478 	reason.iMTUExceeded = 0;
       
   479 	reason.iLocalEndpoint = aDestinationCID;
       
   480 	reason.iRemoteEndpoint = aSourceCID;
       
   481 	
       
   482 	HL2CapCommand* command = HCommandReject::New(reason, aId);
       
   483 	if(command)
       
   484 		{
       
   485 		AddToOutgoingQueue(command);
       
   486 		}
       
   487 	}
       
   488 
       
   489 void CL2CapSignalHandler::DeleteCommands(TDblQue<HL2CapCommand>& aCommandsToDelete)
       
   490 	{
       
   491 	LOG_FUNC
       
   492 	HL2CapCommand* cmd = NULL;
       
   493 	TDblQueIter<HL2CapCommand> aDelCmdIter(aCommandsToDelete);
       
   494 	while((cmd = aDelCmdIter++) != NULL)
       
   495 		{
       
   496 		delete cmd;
       
   497 		}
       
   498 	}